Como usar a localização em c #

268

Eu simplesmente não consigo fazer a localização funcionar.

Eu tenho uma biblioteca de classes. Agora eu quero criar arquivos resx lá e retornar alguns valores com base na cultura do thread.

Como eu posso fazer isso?

JL.
fonte
PS: certifique-se de ter instalado a extensão livre Microsoft MAT (Multilingual App Toolkit) para visual studio ;-)
jufo

Respostas:

571
  • Adicione um arquivo de recursos ao seu projeto (você pode chamá-lo de "strings.resx") fazendo o seguinte:
    Clique com o botão direito do mouse em Propriedades no projeto, selecione Adicionar -> Novo item ... no menu de contexto e, em seguida, na lista de Os itens do Visual C # escolhem "Arquivo de recursos" e nomeie-o strings.resx.
  • Adicione um recurso de sequência de caracteres no arquivo resx e dê um bom nome (exemplo: nomeie "Hello" com e dê o valor "Hello")
  • Salve o arquivo de recurso ( nota: este será o arquivo de recurso padrão , pois não possui um código de idioma de duas letras)
  • Adicione referências ao seu programa: System.ThreadingeSystem.Globalization

Execute este código:

Console.WriteLine(Properties.strings.Hello);

Ele deve imprimir "Olá".

Agora, adicione um novo arquivo de recurso chamado "strings.fr.resx" (observe a parte "fr"; esta conterá recursos em francês). Adicione um recurso de sequência com o mesmo nome que em strings.resx, mas com o valor em francês (Name = "Hello", Value = "Salut"). Agora, se você executar o seguinte código, ele deverá imprimir Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(Properties.strings.Hello);

O que acontece é que o sistema procurará um recurso para "fr-FR". Ele não encontrará um (já que especificamos "fr" em seu arquivo "). Em seguida, retornará à verificação de" fr ", que encontra (e usa).

O código a seguir imprimirá "Hello":

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine(Properties.strings.Hello);

Isso ocorre porque ele não encontra nenhum recurso "en-US" e também nenhum recurso "en"; portanto, ele volta ao padrão, que foi o que adicionamos desde o início.

Você pode criar arquivos com recursos mais específicos, se necessário (por exemplo, strings.fr-FR.resx e strings.fr-CA.resx para francês na França e no Canadá, respectivamente). Em cada um desses arquivos, você precisará adicionar os recursos para as cadeias que diferem do recurso para o qual ele retornaria. Portanto, se um texto é o mesmo na França e no Canadá, você pode colocá-lo em strings.fr.resx, enquanto as strings diferentes no francês canadense podem ir para strings.fr-CA.resx.

Fredrik Mörk
fonte
24
A resposta pode fazer referência ao encanamento "nos bastidores" que está sendo executado pelo Visual Studio aqui: arquivo resx.designer.cs, fazendo o intellisense funcionar; assemblies de satélite compilados com a biblioteca de classes, que precisam ser implantados com o assembly compilado e quaisquer projetos posteriores que o usem, etc ... A resposta é agradável e simples, mas não ajuda a explicar onde as coisas podem dar errado, por exemplo, se você não usa o Visual Studio.
Tao
13
+1 postagem! Em vez de criar arquivos manualmente, tente o Zeta Resource Editor ( zeta-resource-editor.com/index.html ). É gratuito e ajuda a fazer esse tipo de tradução MUITO mais rápido do que apenas no VS.
Killnine
4
Access Modifierdeve ser definido Publicpara que a classe de recurso seja gerada. A classe não é necessária no espaço de nomes Propriedades, é onde você coloca o arquivo .resx.
Andrey Moiseev
3
Esteja ciente de que no VS 2017 o resx com localização no winform não está funcionando devido a um erro (pelo menos até a versão 15.4). Um ticket está disponível: developercommunity.visualstudio.com/content/problem/63772/…
muccix
4
No .NET 4.5, também é possível usar System.Globalization.CultureInfo.DefaultThreadCurrentCulture em vez de Thread.CurrentThread.CurrentUICulture para que você altere o
código
41

É bem simples, na verdade. Crie um novo arquivo de recurso, por exemplo Strings.resx. Defina Access Modifiercomo Public. Use o modelo de arquivo apropriado, para que o Visual Studio gere automaticamente uma classe de acessador (o nome será Strings, nesse caso). Este é o seu idioma padrão.

Agora, quando você quiser adicionar, por exemplo, localização alemã, adicione um arquivo resx localizado. Isso será tipicamente Strings.de.resxneste caso. Se você deseja adicionar localização adicional para, digamos, na Áustria, criará adicionalmente um Strings.de-AT.resx.

Agora vá criar uma string - digamos uma string com o nome HelloWorld. No seu Strings.resx, adicione essa sequência com o valor "Olá, mundo!". Em Strings.de.resx, adicione "Olá, Welt!". E em Strings.de-AT.resx, adicione "Servus, Welt!". Até agora.

Agora você tem essa Stringsclasse gerada e ela possui uma propriedade com um getter HelloWorld. Obter esta propriedade carregará "Servus, Welt!" quando seu código de idioma estiver desativado, "Olá, Welt! quando seu código de idioma for qualquer outro código de idioma (incluindo de-DE e de-CH) e" Olá, Mundo! "quando seu código de idioma for qualquer outra coisa. Se uma string for ausente na versão localizada, o gerenciador de recursos passará automaticamente pela cadeia, do recurso mais especializado ao invariante.

Você pode usar a ResourceManagerclasse para ter mais controle sobre como exatamente está carregando as coisas. A Stringsclasse gerada também a usa.

OregonGhost
fonte
como definir a localidade?
Matheus Simon
1
@MatheusSimon: Você não precisa. Por padrão, a localidade atual do usuário é usada. Se você deseja forçar um determinado código de idioma (por exemplo, para permitir que os usuários alterem o idioma manualmente), é necessário definir System.Threading.Thread.CurrentCulture e CurrentUICulture em cada thread , provavelmente antes de qualquer recurso ser carregado pela primeira vez. É mais fácil reiniciar um aplicativo para isso do que atualizar em tempo de execução.
OregonGhost 10/09
15

Além disso, a ótima resposta de @Fredrik Mörk sobre cadeias de caracteres, para adicionar localização a um formulário, faça o seguinte:

  • Defina a propriedade do formulário"Localizable" comotrue
  • Altere a Languagepropriedade do formulário para o idioma desejado (em um bom menu suspenso com todos eles dentro)
  • Traduza os controles dessa forma e mova-os se necessário (esmague as frases francesas completas muito longas em!)

Edit: Este artigo do MSDN sobre Localização de formulários do Windows não é o original que vinculei ... mas pode lançar mais luz se necessário. (o antigo foi levado embora)

noelicus
fonte
O artigo msdn não está mais disponível, qualquer substituição?
precisa saber é o seguinte
Não tenho certeza - Tenho ligado o melhor que eu podia ver, mas eu não consigo lembrar o que o artigo era como há 7 anos;)
noelicus
14

Ótima resposta de F.Mörk. Mas se você deseja atualizar a tradução ou adicionar novos idiomas assim que o aplicativo é lançado, você fica paralisado, porque sempre é necessário recompilá-lo para gerar os recursos.dll.

Aqui está uma solução para compilar manualmente uma dll de recurso. Ele usa as ferramentas resgen.exe e al.exe (instaladas com o sdk).

Digamos que você tenha um arquivo de recurso Strings.fr.resx, você pode compilar uma DLL de recursos com o seguinte lote:

resgen.exe /compile Strings.fr.resx,WpfRibbonApplication1.Strings.fr.resources 
Al.exe /t:lib /embed:WpfRibbonApplication1.Strings.fr.resources /culture:"fr" /out:"WpfRibbonApplication1.resources.dll"
del WpfRibbonApplication1.Strings.fr.resources
pause

Certifique-se de manter o espaço para nome original nos nomes dos arquivos (aqui "WpfRibbonApplication1")

Eric Bole-Feysot
fonte
2
Obrigado pelo comentário sobre a preservação do espaço para nome (y), que - se esquecido - não gera erros, mas simplesmente reverte para o recurso de fallback.
Mosca Pt
11

Uma correção e elaboração da resposta do @Fredrik Mörk .

  • Adicione um strings.resxarquivo de recursos ao seu projeto (ou um nome de arquivo diferente)
  • Defina Access Modifiercomo Public(na strings.resxguia arquivo aberto )
  • Adicione um recurso de sequência de caracteres no arquivo resx: (exemplo: nome Hello, valor Hello)
  • Salve o arquivo de recurso

O Visual Studio gera automaticamente uma stringsclasse respectiva , que é realmente inserida strings.Designer.cs. A classe está no mesmo espaço para nome em que você esperaria que um .csarquivo recém-criado fosse colocado.

Esse código sempre é impresso Hello, porque este é o recurso padrão e nenhum recurso específico ao idioma está disponível:

Console.WriteLine(strings.Hello);

Agora adicione um novo recurso específico ao idioma:

  • Adicionar strings.fr.resx(para francês)
  • Adicione uma sequência com o mesmo nome que anteriormente, mas com um valor diferente: (nome Hello, valor Salut)

O código a seguir é impresso Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(strings.Hello);

Qual recurso é usado depende Thread.CurrentThread.CurrentUICulture. É definido dependendo da configuração do idioma da interface do usuário do Windows ou pode ser definido manualmente, como neste exemplo. Saiba mais sobre isso aqui .

Você pode adicionar recursos específicos de país como strings.fr-FR.resxou strings.fr-CA.resx.

A cadeia a ser usada é determinada nesta ordem de prioridade:

  • Do recurso específico do país, como strings.fr-CA.resx
  • Do recurso específico do idioma, como strings.fr.resx
  • Do padrão strings.resx

Observe que recursos específicos de idioma geram assemblies de satélite .

Aprenda também como CurrentCulture difere CurrentUICulture daqui .

Andrey Moiseev
fonte
1

No meu caso

[assembly: System.Resources.NeutralResourcesLanguage("ru-RU")]

no AssemblyInfo.cs impedia que as coisas funcionassem normalmente.

Aleksandr
fonte
0

Além de @Eric Bole-Feysot :

Graças aos assemblies de satélite, a localização pode ser criada com base nos arquivos .dll / .exe . Deste jeito:

  • o código-fonte (projeto VS) pode ser separado do projeto de idioma,
  • adicionar um novo idioma não exige a recompilação do projeto,
  • a tradução pode ser feita mesmo pelo usuário final.

Existe uma ferramenta pouco conhecida chamada LSACreator (gratuita para uso não comercial ou opção de compra) que permite criar a localização com base em arquivos .dll / .exe. De fato, internamente (no diretório do projeto de idioma) ele cria / gerencia versões localizadas de arquivos resx e compila um assembly de maneira semelhante à descrita por @Eric Bole-Feysot .

Tomasz Malik
fonte
0

ResourceManager e .resx são um pouco confusos.

Você pode usar o Lexical.Localization ¹, que permite incorporar o valor padrão e os valores específicos da cultura no código, e ser expandido em arquivos de localização externos para outras culturas (como .json ou .resx).

public class MyClass
{
    /// <summary>
    /// Localization root for this class.
    /// </summary>
    static ILine localization = LineRoot.Global.Type<MyClass>();

    /// <summary>
    /// Localization key "Ok" with a default string, and couple of inlined strings for two cultures.
    /// </summary>
    static ILine ok = localization.Key("Success")
            .Text("Success")
            .fi("Onnistui")
            .sv("Det funkar");

    /// <summary>
    /// Localization key "Error" with a default string, and couple of inlined ones for two cultures.
    /// </summary>
    static ILine error = localization.Key("Error")
            .Format("Error (Code=0x{0:X8})")
            .fi("Virhe (Koodi=0x{0:X8})")
            .sv("Sönder (Kod=0x{0:X8})");

    public void DoOk()
    {
        Console.WriteLine( ok );
    }

    public void DoError()
    {
        Console.WriteLine( error.Value(0x100) );
    }
}

I'm (eu sou mantenedor dessa biblioteca)

Tag
fonte
0

Em geral, você coloca suas traduções em arquivos de recursos, por exemplo, resources.resx.

Cada cultura específica tem um nome diferente, por exemplo, resources.nl.resx, resources.fr.resx, resources.de.resx,…

Agora, a parte mais importante de uma solução é manter suas traduções. No Visual Studio, instale a ferramenta Microsoft MAT: Multilingual App Toolkit (MAT). Funciona com winforms, wpf, asp.net (core), uwp,…

Em geral, por exemplo, para uma solução WPF, no projeto WPF

  • Instale a extensão Microsoft MAT para o Visual Studio.
  • No Gerenciador de Soluções, navegue até seu Projeto> Propriedades> AssemblyInfo.cs
  • Adicione no AssemblyInfo.cs seu idioma neutro padrão (no meu caso, inglês): [assembly: System.Resources.NeutralResourcesLanguage("en")]
  • Selecione seu projeto no Solution Explorer e no Visual Studio, no menu superior, clique em "Ferramentas"> "Multilingual App Toolkit"> "Ativar seleção", para ativar o MAT no projeto.
    • Agora clique com o botão direito do mouse no projeto no Solution Explorer, selecione "Multilingual App Toolkit"> "Adicionar idiomas de tradução ..." e selecione o idioma ao qual deseja adicionar traduções. por exemplo holandês.

O que você verá é que uma nova pasta será criada, chamada "MultilingualResources" contendo um ....nl.xlfarquivo.

A única coisa que você precisa fazer agora é:

  1. adicione sua tradução ao seu arquivo resources.resx padrão (no meu caso, inglês)
  2. Traduza clicando no arquivo .xlf (NÃO no arquivo .resx), pois os arquivos .xlf irão gerar / atualizar os arquivos .resx.

(os arquivos .xlf devem abrir com o "Editor multilíngue", se esse não for o caso, clique com o botão direito do mouse no arquivo .xlf, selecione "Abrir com ..." e selecione "Editor multilíngue".

Diverta-se! agora você também pode ver o que não foi traduzido, exportar traduções em xlf para empresas de tradução externas, importá-las novamente, reciclar traduções de outros projetos etc.

Mais informações:

juFo
fonte