Melhor maneira de implementar multi-idioma / globalização em um grande projeto .NET


86

Em breve estarei trabalhando em um grande projeto c # e gostaria de criar suporte para vários idiomas desde o início. Fiz uma experiência e posso fazê-lo funcionar usando um arquivo de recursos separado para cada idioma e, em seguida, usar um gerenciador de recursos para carregar as strings.

Existem outras boas abordagens que eu poderia examinar?

Respostas:


88

Use um projeto separado com recursos

Posso dizer isso por experiência própria, tendo uma solução atual com 12 24 projetos que inclui API, MVC, Bibliotecas de Projetos (funcionalidades do Core), WPF, UWP e Xamarin. Vale a pena ler este longo post, pois acho que é a melhor maneira de fazer isso. Com a ajuda de ferramentas VS facilmente exportáveis ​​e importáveis ​​para enviar para agências de tradução ou revisão por outras pessoas.

EDITAR 02/2018: Ainda forte, convertê-lo em uma biblioteca .NET Standard torna possível até mesmo usá-lo em .NET Framework e NET Core. Eu adicionei uma seção extra para convertê-lo em JSON para que, por exemplo, o angular possa usá-lo.

EDITAR 2019: Avançando com o Xamarin, ainda funciona em todas as plataformas. Por exemplo, conselhos do Xamarin.Forms para usar arquivos resx também. (Eu não desenvolvi um aplicativo em Xamarin.Forms ainda, mas a documentação, que é detalhada para começar, cobre: Documentação do Xamarin.Forms ). Assim como convertê-lo para JSON, também podemos convertê-lo em um arquivo .xml para Xamarin.Android.

EDIT 2019 (2): Ao atualizar para UWP a partir do WPF, descobri que na UWP eles preferem usar outro tipo de arquivo .resw, que é idêntico em termos de conteúdo, mas o uso é diferente. Eu encontrei uma maneira diferente de fazer isso que, na minha opinião, funciona melhor do que a solução padrão .

EDIT 2020: Atualizado algumas sugestões para projetos maiores (modulair) que podem exigir vários projetos de idioma.

Então vamos fazer isso.

Pro's

  • Fortemente digitado em quase todos os lugares.
  • No WPF você não tem que lidar ResourceDirectories.
  • Compatível com ASP.NET, Bibliotecas de classes, WPF, Xamarin, .NET Core, .NET Standard até onde testei.
  • Nenhuma biblioteca extra de terceiros necessária.
  • Suporta fallback de cultura: en-US -> en.
  • Não apenas back-end, funciona também em XAML para WPF e Xamarin.Forms, em .cshtml para MVC.
  • Manipule facilmente o idioma alterando o Thread.CurrentThread.CurrentCulture
  • Os mecanismos de pesquisa podem rastrear em diferentes idiomas e o usuário pode enviar ou salvar urls específicas de um idioma.

Con's

  • Às vezes, o WPF XAML apresenta erros, as cadeias de caracteres recém-adicionadas não aparecem diretamente. Reconstruir é a correção temporária (vs2015).
  • O UWP XAML não mostra sugestões de intellisense e não mostra o texto durante o projeto.
  • Conte-me.

Configuração

Crie um projeto de linguagem em sua solução, dê a ele um nome como MyProject.Language . Adicione uma pasta chamada Recursos e, nessa pasta, crie dois arquivos de Recursos (.resx). Um denominado Resources.resx e outro denominado Resources.en.resx (ou .en-GB.resx para específico). Na minha implementação, tenho o idioma NL (holandês) como o idioma padrão, então isso vai no meu primeiro arquivo e o inglês vai no meu segundo arquivo.

A configuração deve ser semelhante a esta:

projeto de configuração de linguagem

As propriedades de Resources.resx devem ser: propriedades

Certifique-se de que o namespace da ferramenta personalizada esteja definido como o namespace do seu projeto. A razão para isso é que no WPF, você não pode fazer referência a Resourcesdentro do XAML.

E dentro do arquivo de recurso, defina o modificador de acesso como Público:

modificador de acesso

Se você tiver um aplicativo tão grande (digamos, módulos diferentes), você pode considerar a criação de vários projetos como acima. Nesse caso, você pode prefixar suas Chaves e classes de recursos com o Módulo específico. Use o melhor editor de linguagem existente para o Visual Studio para combinar todos os arquivos em uma única visão geral.

Usando em outro projeto

Referência ao seu projeto: Clique com o botão direito em References -> Add Reference -> Prjects \ Solutions.

Use namespace em um arquivo: using MyProject.Language;

Use-o assim no back-end: string someText = Resources.orderGeneralError; se houver outra coisa chamada Recursos, basta inserir o namespace inteiro.

Usando em MVC

Em MVC você pode fazer o que quiser para definir o idioma, mas eu usei urls parametrizadas, que podem ser configuradas da seguinte forma:

RouteConfig.cs Abaixo dos outros mapeamentos

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 (pode precisar ser adicionado, se assim for, adicione FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);ao Application_start()método emGlobal.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 apenas define as informações de cultura.

//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)
    {

    }
}

Uso em .cshtml

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

ou se você não quiser definir usings, basta preencher todo o namespace OU você pode definir o namespace em /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>

Este tutorial da fonte de implementação do mvc: Blog de tutorial incrível

Usando bibliotecas de classe para modelos

O uso de back-end é o mesmo, mas apenas um exemplo de uso em atributos

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; }
    }
}

Se você tiver remodelado, ele verificará automaticamente se o nome do recurso fornecido existe. Se você preferir segurança de tipo, você pode usar modelos T4 para gerar um enum

Usando em WPF.

Claro, adicione uma referência ao seu namespace MyProject.Language , sabemos como usá-lo no back-end.

Em XAML, dentro do cabeçalho de uma janela ou UserControl, adicione uma referência de namespace chamada langassim:

<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">

Então, dentro de um rótulo:

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

Uma vez que é fortemente tipado, você tem certeza de que a string de recurso existe. Pode ser necessário recompilar o projeto às vezes durante a configuração, às vezes o WPF apresenta erros com novos namespaces.

Mais uma coisa para o WPF, defina o idioma dentro do App.xaml.cs. Você pode fazer sua própria implementação (escolha durante a instalação) ou deixar o sistema decidir.

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;
        }
       
    }
}

Usando em UWP

Na UWP, a Microsoft usa essa solução , o que significa que você precisará criar novos arquivos de recursos. Além disso, você não pode reutilizar o texto porque eles querem que você defina o x:Uidde seu controle em XAML como uma chave em seus recursos. E em seus recursos você tem que fazer Example.Textpara preencher um TextBlocktexto de. Eu não gostei dessa solução porque quero reutilizar meus arquivos de recursos. Eventualmente, encontrei a seguinte solução. Acabei de descobrir isso hoje (26/09/2019), então posso voltar com outra coisa, se isso não funcionar como desejado.

Adicione isto ao seu projeto:

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);
    }
}

Adicione isto a App.xaml.csno construtor:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

Sempre que você quiser em seu aplicativo, use isto para alterar o idioma:

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

A última linha é necessária para atualizar a IU. Enquanto ainda estou trabalhando neste projeto, percebi que precisava fazer isso 2 vezes. Posso acabar com uma seleção de idioma na primeira vez que o usuário iniciar. Mas, como será distribuído por meio da Windows Store, o idioma geralmente é igual ao idioma do sistema.

Em seguida, use em XAML:

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

Usando no Angular (converter para JSON)

Hoje em dia é mais comum ter um framework como o Angular em combinação com componentes, portanto, sem cshtml. As traduções são armazenadas em arquivos json, não vou cobrir como isso funciona, eu recomendo fortemente o ngx-translate em vez da multi-tradução angular. Portanto, se você deseja converter traduções em um arquivo JSON, é muito fácil, eu uso um script de modelo T4 que converte o arquivo de Recursos em um arquivo json. Eu recomendo instalar o editor T4 para ler a sintaxe e usá-lo corretamente porque você precisa fazer algumas modificações.

Apenas uma coisa a se notar: não é possível gerar os dados, copiá-los, limpar os dados e gerá-los para outro idioma. Portanto, você deve copiar o código abaixo tantas vezes quanto os idiomas que possui e alterar a entrada antes de '// escolher o idioma aqui'. Atualmente não há tempo para consertar isso, mas provavelmente atualizarei mais tarde (se estiver interessado).

Caminho: 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);
}


#>

Se você tem um aplicativo modulair e seguiu minha sugestão de criar projetos em vários idiomas, terá que criar um arquivo T4 para cada um deles. Certifique-se de que os arquivos json estão definidos logicamente, não precisa ser en.json, também pode ser example-en.json. Para combinar vários arquivos json para usar com ngx-translate , siga as instruções aqui

Use no Xamarin.Android

Conforme explicado acima nas atualizações, eu uso o mesmo método que usei com Angular / JSON. Mas o Android usa arquivos XML, então escrevi um arquivo T4 que gera esses arquivos XML.

Caminho: 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);
    }

#>

O Android funciona com values-xxpastas, portanto, acima é para Inglês para na values-enpasta. Mas você também deve gerar um padrão que vai para a valuespasta. Basta copiar o modelo T4 acima e alterar a pasta no código acima.

Pronto, agora você pode usar um único arquivo de recurso para todos os seus projetos. Isso torna muito fácil exportar tudo para um documento excl e permitir que alguém o traduza e importe novamente.

Agradecimentos especiais a esta extensão VS incrível que funciona muito bem com resxarquivos. Considere fazer uma doação a ele por seu trabalho incrível (não tenho nada a ver com isso, simplesmente amo a extensão).


1. como você adiciona mais idiomas após a implantação ?, adicionando mais recursos ao Mylanguage e recompilar e reimplantar? (2) Existe algum IDE ou ferramenta que você usou para tradução (eu tenho mais de 40 formulários em winform), você pode compartilhar? (3) Tentei e não obtive a tradução quando mudei a cultura para o árabe, vou criar uma pergunta e informá-lo
Smith

5
1: Basta publicar Resources.xx.resx e alterar xx e em todos os lugares onde tenho as instruções switch adicione o idioma. 2 Eu uso a extensão ResxManager (por TomEnglert), pode ser instalado através de Ferramentas -> Extensões, ótima maneira de ter os idiomas próximos uns dos outros, mas a tradução real é feita por outra pessoa (exportação e importação fáceis de / para o Excel com ResxManager). 3. Também encontrei isso da última vez adicionando um também, verifique todos os arquivos listados acima, mas alguns pontos de interrupção. Eu não usei isso no WinForms.
CularBytes

13
Posso votar positivamente na minha própria resposta? Eu apenas tive que verificar estupidamente minha própria resposta para corrigir um bug para alternar entre idiomas no WPF -.-
CularBytes

1
@TiagoBrenck Olá, somente nesta situação específica, se o inglês for seu idioma padrão, você pode criar um arquivo resources.en-gb.resx e adicionar as alterações de 1% nele. Por padrão, se o idioma en-gb for selecionado e as palavras não forem traduzidas, ele usa o idioma padrão (resources.resx).
CularBytes

1
Como você estruturou as chaves do arquivo de recursos? Como vejo que você usa apenas um arquivo de recurso e, segundo você, tem um aplicativo enorme, como você dividiu as chaves? Algo como "Feature.MyMessage" ou "Area.Feature.MyMessage"
Francesco Venturini

21

Já vi projetos implementados usando uma série de abordagens diferentes, cada uma com seus méritos e desvantagens.

  • Um fez isso no arquivo de configuração (não é meu favorito)
  • Fazia-se isso usando um banco de dados - funcionava muito bem, mas era difícil saber o que manter.
  • Um usou arquivos de recursos da maneira que você está sugerindo e devo dizer que foi minha abordagem favorita.
  • O mais básico fez isso usando um arquivo de inclusão cheio de strings - feio.

Eu diria que o método de recurso que você escolheu faz muito sentido. Seria interessante ver as respostas de outras pessoas também, pois muitas vezes me pergunto se há uma maneira melhor de fazer coisas assim. Eu vi vários recursos que apontam para o método de recursos de uso, incluindo um aqui no SO .


5

Não acho que haja uma "melhor maneira". Realmente dependerá das tecnologias e do tipo de aplicativo que você está construindo.

Os aplicativos da Web podem armazenar as informações no banco de dados como sugeriram outros pôsteres, mas eu recomendo o uso de arquivos de recursos separados. Ou seja , os arquivos de recursos são separados da sua fonte . Arquivos de recursos separados reduzem a contenção pelos mesmos arquivos e, à medida que seu projeto cresce, você pode descobrir que a localização será feita separadamente da lógica de negócios. (Programadores e Tradutores).

Os gurus do Microsoft WinForm e do WPF recomendam o uso de assemblies de recursos separados, personalizados para cada local.

A capacidade do WPF de dimensionar elementos da IU para o conteúdo diminui o trabalho de layout necessário, por exemplo: (palavras em japonês são muito mais curtas do que em inglês).

Se você está considerando o WPF: Eu sugiro a leitura deste artigo do msdn. Para ser sincero, achei as ferramentas de localização do WPF: msbuild, locbaml (e talvez uma planilha do Excel) tediosas de usar, mas funcionam.

Algo apenas ligeiramente relacionado: um problema comum que enfrento é a integração de sistemas legados que enviam mensagens de erro (geralmente em inglês), não códigos de erro. Isso força a mudança para sistemas legados ou mapeamento de strings de back-end para meus próprios códigos de erro e, em seguida, para strings localizadas ... yech. Códigos de erro são amigos de localizações


4

+1 Banco de dados

Os formulários em seu aplicativo podem até se traduzir novamente em tempo real se as correções forem feitas no banco de dados.

Usamos um sistema em que todos os controles foram mapeados em um arquivo XML (um por formulário) para IDs de recursos de linguagem, mas todos os IDs estavam no banco de dados.

Basicamente, em vez de fazer com que cada controle contenha o ID (implementando uma interface ou usando a propriedade tag no VB6), usamos o fato de que no .NET a árvore de controle era facilmente descoberta por meio de reflexão. Um processo quando o formulário carregado iria construir o arquivo XML se estivesse faltando. O arquivo XML mapearia os controles para seus IDs de recursos, portanto, isso simplesmente precisava ser preenchido e mapeado para o banco de dados. Isso significa que não há necessidade de alterar o binário compilado se algo não estiver marcado ou se precisar ser dividido em outro ID (algumas palavras em inglês que podem ser usadas como substantivos e verbos podem precisar ser traduzidas para duas palavras diferentes no dicionário e não ser reutilizado, mas você pode não descobrir isso durante a atribuição inicial de IDs).

Os únicos em que o aplicativo fica mais envolvido é quando uma fase com pontos de inserção é usada.

O software de tradução de banco de dados era sua tela de manutenção CRUD básica com várias opções de fluxo de trabalho para facilitar a passagem pelas traduções que faltavam, etc.


Eu gosto do seu método, você pode me dizer como o arquivo xml é gerado e depois mapeado para o banco de dados?
Smith

Em Form_Load ou em qualquer outro lugar, a função de tradução foi chamada na instância do formulário. O arquivo XML desse formulário foi carregado. Se não existisse, foi criado. Não tenho o esquema disponível, mas basicamente ele mapeou o nome do controle em um formulário para um ID de tradução. Portanto, qualquer controle no formulário que não estivesse no arquivo XML obteria uma entrada sem ID de tradução. Como eles seriam criados sob demanda, você poderia simplesmente criar seu formulário, executar o aplicativo que criaria ou atualizaria o arquivo XML para quaisquer controles ausentes. Em seguida, preencha os IDs de tradução dos itens.
Cade Roux

4

Estive pesquisando e encontrei o seguinte:

Se você está usando WPF ou Silverlight, sua abordagem pode usar WPF LocalizationExtension por muitos motivos.

Código aberto de TI É GRATUITO (e permanecerá gratuito) está em um estado real de estabilidade

Em um aplicativo do Windows, você pode fazer algo assim:

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);  
    }  
} 

E eu acho que em uma página Wep a abordagem poderia ser a mesma.

Boa sorte!


2

Eu iria com os vários arquivos de recursos. Não deve ser tão difícil de configurar. Na verdade, recentemente respondi a uma pergunta semelhante sobre a configuração de arquivos de recursos baseados em linguagem global em conjunto com arquivos de recursos de linguagem de formulário.

Localização no Visual Studio 2008

Eu consideraria essa a melhor abordagem pelo menos para o desenvolvimento do WinForm.


Uma desvantagem dos recursos é que você precisa reiniciar para alternar os idiomas. Provavelmente é aceitável para a maioria, mas é minha implicância ...
Roman Starkov

2

Você pode usar ferramentas comerciais como Sisulizer . Ele criará um assembly satélite para cada idioma. A única coisa que você deve prestar atenção é não ofuscar os nomes das classes de formulário (se você usar o ofuscador).


0

A maioria dos projetos de código aberto usa GetText para essa finalidade. Não sei como e se já foi usado em um projeto .Net antes.


0

Usamos um provedor personalizado para suporte a vários idiomas e colocamos todos os textos em uma tabela de banco de dados. Ele funciona bem, exceto que às vezes enfrentamos problemas de cache ao atualizar textos no banco de dados sem atualizar o aplicativo da web.


0

Arquivos de recursos padrão são mais fáceis. No entanto, se você tiver dados dependentes de idioma, como tabelas de pesquisa, terá que gerenciar dois conjuntos de recursos.

Não fiz isso, mas em meu próximo projeto implementaria um provedor de recursos de banco de dados. Descobri como fazer isso no MSDN:

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

Também encontrei esta implementação:

Provedor DBResource

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.