Лучший способ реализовать многоязычность / глобализацию в большом .NET-проекте

86

Вскоре я буду работать над большим проектом C # и с самого начала хотел бы встроить многоязычную поддержку. У меня была игра, и я могу заставить ее работать, используя отдельный файл ресурсов для каждого языка, а затем использовать диспетчер ресурсов для загрузки строк.

Есть ли другие хорошие подходы, которые я мог бы изучить?

Tjjjohnson
источник

Ответы:

88

Используйте отдельный проект с ресурсами

Я могу сказать это по нашему опыту, имея текущее решение с 12 24 проектами, которые включают API, MVC, библиотеки проектов (основные функции), WPF, UWP и Xamarin. Стоит прочитать этот длинный пост, так как я думаю, что это лучший способ сделать это. С помощью инструментов VS легко экспортируется и импортируется для отправки в бюро переводов или проверки другими людьми.

РЕДАКТИРОВАТЬ 02/2018: По-прежнему сильна, преобразование ее в библиотеку .NET Standard позволяет даже использовать ее в .NET Framework и NET Core. Я добавил дополнительный раздел для преобразования его в JSON, чтобы, например, angular мог его использовать.

РЕДАКТИРОВАТЬ 2019: продвигаясь вперед с Xamarin, это по-прежнему работает на всех платформах. Например, Xamarin.Forms также советует использовать файлы resx. (Я еще не разрабатывал приложение на Xamarin.Forms, но документация, подробно описанная для начала, охватывает это: Документация Xamarin.Forms ). Так же, как преобразование в JSON, мы также можем преобразовать его в файл .xml для Xamarin.Android.

РЕДАКТИРОВАТЬ 2019 (2): при обновлении до UWP из WPF я обнаружил, что в UWP они предпочитают использовать другой тип файла .resw, который идентичен с точки зрения содержимого, но использование отличается. Я нашел другой способ сделать это, который, на мой взгляд, работает лучше, чем решение по умолчанию .

РЕДАКТИРОВАТЬ 2020: обновлены некоторые предложения для более крупных (модульных) проектов, для которых может потребоваться несколько языковых проектов.

Итак, приступим к делу.

Профи

  • Сильно набирается почти везде.
  • В WPF вам не придется иметь дело с ResourceDirectories.
  • Насколько я тестировал, поддерживается для ASP.NET, библиотек классов, WPF, Xamarin, .NET Core, .NET Standard.
  • Никаких дополнительных сторонних библиотек не требуется.
  • Поддерживает альтернативный язык и региональные параметры: en-US -> en.
  • Не только серверная часть, но также работает в XAML для WPF и Xamarin.Forms, в .cshtml для MVC.
  • Легко манипулируйте языком, изменяя Thread.CurrentThread.CurrentCulture
  • Поисковые системы могут сканировать на разных языках, и пользователь может отправлять или сохранять URL-адреса для конкретных языков.

Против

  • WPF XAML иногда содержит ошибки, недавно добавленные строки не отображаются напрямую. Восстановление - это временное исправление (vs2015).
  • UWP XAML не отображает предложения intellisense и не отображает текст во время проектирования.
  • Скажи мне.

Настроить

Создайте языковой проект в своем решении, дайте ему имя, например MyProject.Language . Добавьте в него папку с именем Resources и в этой папке создайте два файла ресурсов (.resx). Один называется Resources.resx, а другой - Resources.en.resx (или, в частности, .en-GB.resx). В моей реализации в качестве языка по умолчанию используется NL (голландский), так что он идет в моем первом файле, а английский - во втором.

Настройка должна выглядеть так:

проект настройки языка

Свойства для Resources.resx должны быть: свойства

Убедитесь, что пространство имен настраиваемого инструмента соответствует пространству имен вашего проекта. Причина этого в том, что в WPF нельзя ссылаться на Resourcesвнутренний XAML.

И внутри файла ресурсов установите модификатор доступа на Public:

модификатор доступа

Если у вас такое большое приложение (скажем, разные модули), вы можете рассмотреть возможность создания нескольких проектов, как указано выше. В этом случае вы можете префикс своих ключей и классов ресурсов с конкретным модулем. Используйте лучший языковой редактор для Visual Studio, чтобы объединить все файлы в единый обзор.

Использование в другом проекте

Ссылка на ваш проект: щелкните правой кнопкой мыши Ссылки -> Добавить ссылку -> Prjects \ Solutions.

Использовать пространство имен в файле: using MyProject.Language;

Используйте это так же в серверной части: string someText = Resources.orderGeneralError; если есть что-то еще, называемое ресурсами, просто вставьте все пространство имен.

Использование в MVC

В MVC вы можете установить язык, но я использовал параметризованные URL-адреса, которые можно настроить следующим образом:

RouteConfig.cs Ниже других сопоставлений

routes.MapRoute(
    name: "Locolized",
    url: "{lang}/{controller}/{action}/{id}",
    constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },   // en or en-US
    defaults: new { controller = "shop", action = "index", id = UrlParameter.Optional }
);

FilterConfig.cs (может потребоваться добавить, если да, добавьте FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);к Application_start()методу вGlobal.asax

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ErrorHandler.AiHandleErrorAttribute());
        //filters.Add(new HandleErrorAttribute());
        filters.Add(new LocalizationAttribute("nl-NL"), 0);
    }
}

LocalizationAttribute

public class LocalizationAttribute : ActionFilterAttribute
{
    private string _DefaultLanguage = "nl-NL";
    private string[] allowedLanguages = { "nl", "en" };

    public LocalizationAttribute(string defaultLanguage)
    {
        _DefaultLanguage = defaultLanguage;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string lang = (string) filterContext.RouteData.Values["lang"] ?? _DefaultLanguage;
        LanguageHelper.SetLanguage(lang);
    }
}

LanguageHelper просто устанавливает информацию о культуре.

//fixed number and date format for now, this can be improved.
public static void SetLanguage(LanguageEnum language)
{
    string lang = "";
    switch (language)
    {
        case LanguageEnum.NL:
            lang = "nl-NL";
            break;
        case LanguageEnum.EN:
            lang = "en-GB";
            break;
        case LanguageEnum.DE:
            lang = "de-DE";
            break;
    }
    try
    {
        NumberFormatInfo numberInfo = CultureInfo.CreateSpecificCulture("nl-NL").NumberFormat;
        CultureInfo info = new CultureInfo(lang);
        info.NumberFormat = numberInfo;
        //later, we will if-else the language here
        info.DateTimeFormat.DateSeparator = "/";
        info.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
        Thread.CurrentThread.CurrentUICulture = info;
        Thread.CurrentThread.CurrentCulture = info;
    }
    catch (Exception)
    {

    }
}

Использование в .cshtml

@using MyProject.Language;
<h3>@Resources.w_home_header</h3>

или, если вы не хотите определять использование, просто заполните все пространство имен ИЛИ вы можете определить пространство имен в /Views/web.config:

<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
  <namespaces>
    ...
    <add namespace="MyProject.Language" />
  </namespaces>
</pages>
</system.web.webPages.razor>

Это руководство по исходной реализации mvc: отличный учебный блог

Использование в библиотеках классов для моделей

Внутреннее использование такое же, но только пример использования в атрибутах

using MyProject.Language;
namespace MyProject.Core.Models
{
    public class RegisterViewModel
    {
        [Required(ErrorMessageResourceName = "accountEmailRequired", ErrorMessageResourceType = typeof(Resources))]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }
}

Если у вас есть преобразователь, он автоматически проверит, существует ли данное имя ресурса. Если вы предпочитаете безопасность типов, вы можете использовать шаблоны T4 для создания перечисления

Использование в WPF.

Конечно, добавьте ссылку на ваше пространство имен MyProject.Language , мы знаем, как использовать его в серверной части.

В XAML внутри заголовка Window или UserControl добавьте ссылку на пространство имен, которая называется langтак:

<UserControl x:Class="Babywatcher.App.Windows.Views.LoginView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyProject.App.Windows.Views"
              xmlns:lang="clr-namespace:MyProject.Language;assembly=MyProject.Language" <!--this one-->
             mc:Ignorable="d" 
            d:DesignHeight="210" d:DesignWidth="300">

Затем внутри метки:

    <Label x:Name="lblHeader" Content="{x:Static lang:Resources.w_home_header}" TextBlock.FontSize="20" HorizontalAlignment="Center"/>

Поскольку он строго типизирован, вы уверены, что строка ресурса существует. Иногда вам может потребоваться перекомпилировать проект во время установки, WPF иногда содержит ошибки с новыми пространствами имен.

Еще одна вещь для WPF: установите язык внутри App.xaml.cs. Вы можете реализовать свою собственную реализацию (выбрать во время установки) или позволить системе решать.

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        SetLanguageDictionary();
    }

    private void SetLanguageDictionary()
    {
        switch (Thread.CurrentThread.CurrentCulture.ToString())
        {
            case "nl-NL":
                MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("nl-NL");
                break;
            case "en-GB":
                MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
                break;
            default://default english because there can be so many different system language, we rather fallback on english in this case.
                MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
                break;
        }
       
    }
}

Использование в UWP

В UWP Microsoft использует это решение , что означает, что вам нужно будет создать новые файлы ресурсов. Кроме того, вы не можете повторно использовать текст, потому что они хотят, чтобы вы установили x:Uidсвой элемент управления в XAML на ключ в своих ресурсах. И в ваших ресурсах вы должны сами Example.Textзаполнить TextBlockтекст. Мне совсем не понравилось это решение, потому что я хочу повторно использовать свои файлы ресурсов. В конце концов я пришел к следующему решению. Я только что узнал об этом сегодня (2019-09-26), поэтому я могу вернуться с чем-нибудь еще, если окажется, что это не работает так, как хотелось бы.

Добавьте это в свой проект:

using Windows.UI.Xaml.Resources;

public class MyXamlResourceLoader : CustomXamlResourceLoader
{
    protected override object GetResource(string resourceId, string objectType, string propertyName, string propertyType)
    {
        return MyProject.Language.Resources.ResourceManager.GetString(resourceId);
    }
}

Добавьте это App.xaml.csв конструктор:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

Где бы вы ни захотели в своем приложении, используйте это, чтобы изменить язык:

ApplicationLanguages.PrimaryLanguageOverride = "nl";
Frame.Navigate(this.GetType());

Последняя строка нужна для обновления пользовательского интерфейса. Пока я работал над этим проектом, я заметил, что мне нужно сделать это 2 раза. Я могу закончить выбор языка при первом запуске пользователя. Но поскольку это будет распространяться через Магазин Windows, язык обычно совпадает с языком системы.

Затем используйте в XAML:

<TextBlock Text="{CustomResource ExampleResourceKey}"></TextBlock>

Используя его в Angular (конвертировать в JSON)

Сейчас более распространено использование фреймворка, такого как Angular, в сочетании с компонентами, то есть без cshtml. Переводы хранятся в файлах json, я не собираюсь рассказывать, как это работает, я просто настоятельно рекомендую ngx-translate вместо углового мультиперевода . Поэтому, если вы хотите преобразовать переводы в файл JSON, это довольно просто, я использую сценарий шаблона T4, который преобразует файл ресурсов в файл json. Я рекомендую установить редактор T4, чтобы прочитать синтаксис и правильно его использовать, потому что вам нужно внести некоторые изменения.

Только одно замечание: невозможно сгенерировать данные, скопировать их, очистить данные и сгенерировать их для другого языка. Таким образом, вы должны скопировать приведенный ниже код столько раз, сколько языков у вас есть, и изменить запись перед «// выбрать язык здесь». В настоящее время нет времени исправлять это, но, вероятно, обновлюсь позже (если интересно).

Путь: MyProject.Language / T4 / CreateLocalizationEN.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".json" #>
<#


var fileNameNl = "../Resources/Resources.resx";
var fileNameEn = "../Resources/Resources.en.resx";
var fileNameDe = "../Resources/Resources.de.resx";
var fileNameTr = "../Resources/Resources.tr.resx";

var fileResultName = "../T4/CreateLocalizationEN.json";//choose language here
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);
//var fileDestinationPath = "../../MyProject.Web/ClientApp/app/i18n/";

var fileNameDestNl = "nl.json";
var fileNameDestEn = "en.json";
var fileNameDestDe = "de.json";
var fileNameDestTr = "tr.json";

var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

string[] fileNamesResx = new string[] {fileNameEn }; //choose language here
string[] fileNamesDest = new string[] {fileNameDestEn }; //choose language here

for(int x = 0; x < fileNamesResx.Length; x++)
{
    var currentFileNameResx = fileNamesResx[x];
    var currentFileNameDest = fileNamesDest[x];
    var currentPathResx = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", currentFileNameResx);
    var currentPathDest =pathBaseDestination + "/MyProject.Web/ClientApp/app/i18n/" + currentFileNameDest;
    using(var reader = new ResXResourceReader(currentPathResx))
    {
        reader.UseResXDataNodes = true;
#>
        {
<#
            foreach(DictionaryEntry entry in reader)
            {
                var name = entry.Key;
                var node = (ResXDataNode)entry.Value;
                var value = node.GetValue((ITypeResolutionService) null); 
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
#>
            "<#=name#>": "<#=value#>",
<#

    
            }
#>
        "WEBSHOP_LASTELEMENT": "just ignore this, for testing purpose"
        }
<#
    }
    File.Copy(fileResultPath, currentPathDest, true);
}


#>

Если у вас есть приложение modulair, и вы последовали моему предложению создать несколько языковых проектов, вам нужно будет создать файл T4 для каждого из них. Убедитесь, что файлы json определены логически, это не обязательно en.json, но также может быть example-en.json. Чтобы объединить несколько файлов json для использования с ngx-translate , следуйте инструкциям здесь

Использование в Xamarin.Android

Как объяснялось выше в обновлениях, я использую тот же метод, что и с Angular / JSON. Но Android использует файлы XML, поэтому я написал файл T4, который генерирует эти файлы XML.

Путь: MyProject.Language / T4 / CreateAppLocalizationEN.tt

#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".xml" #>
<#
var fileName = "../Resources/Resources.en.resx";
var fileResultName = "../T4/CreateAppLocalizationEN.xml";
var fileResultRexPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileName);
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);

    var fileNameDest = "strings.xml";

    var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

    var currentPathDest =pathBaseDestination + "/MyProject.App.AndroidApp/Resources/values-en/" + fileNameDest;

    using(var reader = new ResXResourceReader(fileResultRexPath))
    {
        reader.UseResXDataNodes = true;
        #>
        <resources>
        <#

                foreach(DictionaryEntry entry in reader)
                {
                    var name = entry.Key;
                    //if(!name.ToString().Contains("WEBSHOP_") && !name.ToString().Contains("DASHBOARD_"))//only include keys with these prefixes, or the country ones.
                    //{
                    //  if(name.ToString().Length != 2)
                    //  {
                    //      continue;
                    //  }
                    //}
                    var node = (ResXDataNode)entry.Value;
                    var value = node.GetValue((ITypeResolutionService) null); 
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("&", "&amp;");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("<<", "");
                     //if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("'", "\'");
#>
              <string name="<#=name#>">"<#=value#>"</string>
<#      
                }
#>
            <string name="WEBSHOP_LASTELEMENT">just ignore this</string>
<#
        #>
        </resources>
        <#
        File.Copy(fileResultPath, currentPathDest, true);
    }

#>

Android работает с values-xxпапками, поэтому выше для английского языка в values-enпапке. Но вам также необходимо создать значение по умолчанию, которое будет помещено в valuesпапку. Просто скопируйте вышеуказанный шаблон T4 и измените папку в вышеуказанном коде.

Итак, теперь вы можете использовать один файл ресурсов для всех своих проектов. Это позволяет очень легко экспортировать все в документ excl и позволить кому-нибудь перевести его и снова импортировать.

Особая благодарность за это замечательное расширение VS, которое отлично работает с resxфайлами. Подумайте о том, чтобы пожертвовать ему за его потрясающую работу (я не имею к этому никакого отношения, мне просто нравится расширение).

CularBytes
источник
1. как добавить больше языков после развертывания? Путем добавления дополнительных ресурсов в Mylanguage и повторной компиляции, а затем повторного развертывания? (2) Есть ли какая-нибудь среда разработки или инструмент, который вы использовали для перевода (у меня более 40 форм в winform), вы можете поделиться? (3) Я попробовал, и он не получил перевода, когда я изменил культуру на арабский, я создам вопрос и дам вам знать
Смит
5
1: Просто дублируйте Resources.xx.resx и измените xx, и везде, где у меня есть операторы switch, добавьте язык. 2 Я использую расширение ResxManager (от TomEnglert), его можно установить через Инструменты -> Расширения, хороший способ разместить языки рядом друг с другом, но фактический перевод выполняется кем-то другим (простой экспорт и импорт в / из Excel с помощью ResxManager). 3. Обнаружено это в последний раз, также добавив один, проверьте все файлы, перечисленные выше, но некоторые точки останова. Однако я не использовал это в WinForms.
CularBytes 01
13
Могу ли я проголосовать за свой ответ? Мне просто пришлось тупо проверить свой ответ, чтобы исправить ошибку переключения между языками в WPF -.-
CularBytes
1
@TiagoBrenck Привет, только в этой конкретной ситуации, если английский является вашим языком по умолчанию, вы можете создать файл resources.en-gb.resx и добавить туда 1% изменений. По умолчанию, если выбран язык en-gb и слова не переведены, используется язык по умолчанию (resources.resx).
CularBytes
1
Как вы структурировали ключи файла ресурсов? Поскольку я вижу, что вы используете только один файл ресурсов и, по вашему мнению, у вас огромное приложение, как вы разделили ключи? Что-то вроде "Feature.MyMessage" или "Area.Feature.MyMessage"
Франческо Вентурини
21

Я видел проекты, реализованные с использованием различных подходов, каждый из которых имеет свои достоинства и недостатки.

  • Один сделал это в файле конфигурации (не мой любимый)
  • Один сделал это с использованием базы данных - это работало довольно хорошо, но было проблемой, когда вы знали, что поддерживать.
  • Один использовал файлы ресурсов так, как вы предлагаете, и я должен сказать, что это был мой любимый подход.
  • Самый простой - с использованием включаемого файла, полного строк - уродливо.

Я бы сказал, что выбранный вами ресурсный метод имеет большой смысл. Было бы интересно увидеть ответы других людей, так как я часто задаюсь вопросом, есть ли лучший способ делать такие вещи. Я видел множество ресурсов, которые все указывают на метод использования ресурсов, в том числе один прямо здесь, на SO .

БенАлабастер
источник
5

Я не думаю, что есть «лучший способ». Это действительно будет зависеть от технологий и типа создаваемого вами приложения.

Веб-приложения могут хранить информацию в базе данных, как предлагали другие плакаты, но я рекомендую использовать отдельные файлы ресурсов. Это файлы ресурсов, отделенные от вашего источника . Отдельные файлы ресурсов уменьшают конкуренцию за одни и те же файлы, и по мере роста вашего проекта вы можете обнаружить, что локализация будет выполняться отдельно от бизнес-логики. (Программисты и переводчики).

Гуру Microsoft WinForm и WPF рекомендуют использовать отдельные сборки ресурсов, настроенные для каждой локали.

Возможность WPF изменять размер элементов пользовательского интерфейса в соответствии с содержимым снижает объем требуемой работы с макетом, например: (японские слова намного короче английских).

Если вы рассматриваете WPF: я предлагаю прочитать эту статью msdn. Честно говоря, я нашел инструменты локализации WPF: msbuild, locbaml (и, возможно, электронную таблицу Excel) утомительными в использовании, но они действительно работают.

Что-то немного связанное: распространенная проблема, с которой я сталкиваюсь, - это интеграция устаревших систем, которые отправляют сообщения об ошибках (обычно на английском языке), а не коды ошибок. Это заставляет либо вносить изменения в унаследованные системы, либо отображать внутренние строки на мои собственные коды ошибок, а затем на локализованные строки ... да. Коды ошибок - друг локализаций

MW_dev
источник
4

+1 База данных

Формы в вашем приложении могут даже повторно переводиться на лету, если в базу данных вносятся исправления.

Мы использовали систему, в которой все элементы управления были сопоставлены в XML-файле (по одному на форму) с идентификаторами языковых ресурсов, но все идентификаторы были в базе данных.

По сути, вместо того, чтобы каждый элемент управления содержал идентификатор (реализация интерфейса или использование свойства tag в VB6), мы использовали тот факт, что в .NET дерево элементов управления было легко обнаружено с помощью отражения. Процесс при загрузке формы построит XML-файл, если он отсутствует. XML-файл будет сопоставлять элементы управления с их идентификаторами ресурсов, поэтому его просто нужно было заполнить и сопоставить с базой данных. Это означало, что не было необходимости изменять скомпилированный двоичный файл, если что-то не было помечено или если его нужно было разделить на другой идентификатор (некоторые слова на английском языке, которые могут использоваться как существительные и глаголы, возможно, потребуется перевести в два разных слова в словаре и не могут быть использованы повторно, но вы можете не обнаружить этого во время первоначального присвоения идентификаторов).

Единственное, где приложение принимает более активное участие, - это когда используется фаза с точками вставки.

Программное обеспечение для перевода базы данных было вашим основным экраном обслуживания CRUD с различными вариантами рабочего процесса, чтобы облегчить просмотр недостающих переводов и т. Д.

Кейд Ру
источник
Мне нравится ваш метод, можете ли вы сказать мне, как создается XML-файл, а затем сопоставляется с базой данных?
Smith
В Form_Load или чем-то еще функция перевода была вызвана в экземпляре формы. Файл XML для этой формы был загружен. Если его не было, он был создан. У меня нет схемы, но в основном она сопоставляет имя элемента управления в форме с идентификатором перевода. Таким образом, любой элемент управления в форме, которого нет в XML-файле, получит запись без идентификатора перевода. Поскольку они будут создаваться по запросу, вы можете просто создать свою форму, запустить приложение, которое будет создавать или обновлять XML-файл для любых отсутствующих элементов управления. Затем введите идентификаторы перевода для элементов.
Cade Roux
4

Я искал и нашел это:

Если вы используете WPF или Silverlight, ваш подход может заключаться в использовании WPF LocalizationExtension по многим причинам.

Открытый исходный код IT БЕСПЛАТНО (и останется бесплатным) находится в очень стабильном состоянии

В приложении для Windows вы можете сделать что-то вроде этого:

public partial class App : Application  
{  
     public App()  
     {             
     }  
 
     protected override void OnStartup(StartupEventArgs e)  
     {  
         Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); ;  
         Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE"); ;  
 
          FrameworkElement.LanguageProperty.OverrideMetadata(  
              typeof(FrameworkElement),  
              new FrameworkPropertyMetadata(  
                  XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));  
          base.OnStartup(e);  
    }  
} 

И я думаю, что на Wep Page подход может быть таким же.

Удачи!

JxXx
источник
2

Я бы пошел с несколькими файлами ресурсов. Это не должно быть так сложно настроить. Фактически, я недавно ответил на аналогичный вопрос о настройке файлов ресурсов на основе глобального языка в сочетании с файлами ресурсов языка форм.

Локализация в Visual Studio 2008

Я считаю, что это лучший подход, по крайней мере, для разработки WinForm.

KMessenger
источник
Недостатком ресурсов является то, что для переключения языков необходимо перезапускать. Это, наверное, приемлемо для большинства, но это моя любимая мозоль ...
Роман Старков
2

Вы можете использовать коммерческие инструменты, такие как Sisulizer . Он создаст вспомогательную сборку для каждого языка. Единственное, на что следует обратить внимание, это не запутывать имена классов формы (если вы используете обфускатор).

Даворин
источник
0

Большинство проектов с открытым исходным кодом используют для этой цели GetText . Я не знаю, как и использовался ли он раньше в проекте .Net.

Василь
источник
0

Мы используем настраиваемый поставщик для многоязыковой поддержки и помещаем все тексты в таблицу базы данных. Он работает хорошо, за исключением того, что мы иногда сталкиваемся с проблемами кеширования при обновлении текстов в базе данных без обновления веб-приложения.

Коссинтан
источник
0

Стандартные файлы ресурсов проще. Однако, если у вас есть какие-либо данные, зависящие от языка, такие как таблицы поиска, вам придется управлять двумя наборами ресурсов.

Я этого не делал, но в своем следующем проекте я бы реализовал поставщика ресурсов базы данных. Я нашел, как это сделать в MSDN:

http://msdn.microsoft.com/en-us/library/aa905797.aspx

Я также нашел эту реализацию:

Поставщик DBResource

Бен Демпси
источник