MULTI-IDIOMA ESTA DANDO ERRO

LUIS.HERRERA 05/12/2012 09:44:54
#415466
bom dia.
Estou implementando o multiidioma no meu projeto C# 2008, mas está dando um erro abaixo:

Troubleshooting Exceptions: System.Resources.MissingManifestResourceException
[Ô]Nenhum recurso adequado para a cultura especificada (ou a cultura neutra) foi encontrado no assembly dado. Verifique se [Ô]meuProjeto.myRes.pt-BR.resources[Ô] foi incorporado ou vinculado ao assembly [Ô]meuProjeto[Ô] corretamente no tempo de compilação ou se todos os assemblies satélites necessários podem ser carregados e estão totalmente assinados.[Ô]

Eu criei 2 Resources (myRes.en.resx e myRes.pt-BR.resx) ambos com a propriedade Build Action = Enbedded Resource.
Em ambos criei apenas duas strings iniciais para um form e nele associei os dois itens para o teste. E gerou o erro.

Pensei então que seria preciso criar um outro arquivo [Ô]Padrão[Ô] myRes.resx e incluí nele o mesmo conteúdo do pt-BR por ser o idioma padrão, mas deu o mesmo erro. O que estou fazendo de errado?

Código que usei no formulário de teste:

//usar globalização de multi idiomas
using System.Globalization;
using System.Resources;

namespace meuProjeto
{
public partial class frmCadDepartamentos : Form, IIncluir, IICancelarInclusao
{
// declara a variável de cultura (idioma) usado no Windows
private CultureInfo cultura;

public frmCadDepartamentos()
{
InitializeComponent();
cultura = CultureInfo.CurrentCulture; //usa o idioma padrão do windows se tiver um resource correspondente ou o idioma BR
ajustaCultura();
}

private void ajustaCultura()
{
ResourceManager rm = new ResourceManager([Ô]meuProjeto.myRes.pt-BR[Ô], typeof(frmCadDepartamentos).Assembly);
this.Text = rm.GetString([Ô]frmTitCadDepto[Ô], cultura);
label1.Text = rm.GetString([Ô]frmLabel1[Ô], cultura);
}
}
}

Nota: Em um projeto de exemplo que peguei na Web funciona, mas ao implementar no meu não. O que pode ser?

Além do erro, suponhamos que o idioma do Windows seja num idioma que não há resource, como defino que use sempre o padrão ?

Nota: No arquivo AssemblyInfo.cs ví um item
[assembly: AssemblyCulture([Ô][Ô])]

Tentei colocar nele o [assembly: AssemblyCulture([Ô]pt-BR[Ô])] mas deu erro também, disse que este valor deve ser sempre vazio. Não entendi então para que ter essa opção.
LUIS.HERRERA 05/12/2012 13:29:51
#415480
Como ainda não encontrei solução para o problema acima, estou tentando outra alternativa que é usar o próprio recurso do VS (Forms) para montar as traduções direto nos forms, com as propriedades Localization e Linguage.

O problema agora é outro. A rotina que usei, só consegue trocar os dados dos controles da coleção do Form. Quando se inclui no form outros componentes que são contatiners, não funciona. Ex: TabControl, Grid, GroupBox, e todos os demais containers, incluive um dentro do outro aninhado.

Como eu faço para percorrer todos os container e sub container de um form, independente de qual seja, para acessar os controles neles contidos?

O código - Criei uma Nova Classe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms; //para usar Control

namespace meuProjeto
{
class Idioma
{
//Para realizar a troca do idioma, primeiro alterar a cultura da aplicação e depois varrer o form alterando as propriedades dos controles.

private static void AlteraThreadIdioma(string culture)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture, true);
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture, true);
}

//O método acima altera a cultura da aplicação enquanto o método abaixo varre os controles alterando suas propriedades.

private static void AlteraCultura(Form frm, System.ComponentModel.ComponentResourceManager resx)
{
//Altera o texto na barra de títulos do form
frm.Text = resx.GetObject([Ô]$this.Text[Ô], System.Threading.Thread.CurrentThread.CurrentCulture).ToString();

//Varre os controles do form aplicando a nova cultura
foreach (Control ctrl in frm.Controls)
{
// AQUI TENDO IDENTIFICAR O TABCONTROL e percorrer suas TABs (Nâo está dando certo e ainda teria de identificar os outros containers e subcontainer)
if (ctrl is TabControl)
{

foreach (TabPage pag in ctrl)
{
ctrl.Text = resx.GetObject([Ô]$this.Text[Ô], System.Threading.Thread.CurrentThread.CurrentCulture).ToString();
}
}
else
{
//Aqui faço com que o VS atualize o idioma no controle na coleção do form (OK Funciona)
resx.ApplyResources(ctrl, ctrl.Name, System.Threading.Thread.CurrentThread.CurrentCulture);
}
}
}

//O método público abaixo irá chamar esses dois métodos anteriores e especificar qual será o arquivo de resource utilizado para buscar as propriedades dos controles.

public static void AjustaCultura(Form frm, string culture)
{
AlteraThreadIdioma(culture);
System.ComponentModel.ComponentResourceManager resx = new System.ComponentModel.ComponentResourceManager(frm.GetType());
AlteraCultura(frm, resx);
}
}
}


Para Usar é só criar dois botões no form e assoicar o idioma desejado para troca em tempo real.

private void button1_Click(object sender, EventArgs e)
{
Idioma.AjustaCultura(this, [Ô]pt-BR[Ô]);
}

private void button2_Click(object sender, EventArgs e)
{
Idioma.AjustaCultura(this, [Ô]en-US[Ô]);
}[
OCELOT 05/12/2012 14:43:40
#415485
Resposta escolhida
Você precisa mesmo poder mudar o idioma durante a execução do programa? Geralmente é mais simples mudar o idioma na hora da inicialização do programa, dentro do main antes de chamar o seu form principal, desta forma ele automaticamente pega a linguagem correta que foi configurada usando o Localization e Language.

A linguagem Default vai ser a padrão quando não se tem a linguagem própria do Windows, se o Windows for em inglês dos estados unidos ele vai pegar o en-US, mas digamos que você queira forçar ele a carregar em en-US mesmo se o Windows for em português, então você pode colocar o seguinte no main antes de abrir o form

System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo([Ô]en-US[Ô]);

Quanto ao loop pelos controles você tem que entender que a coleção Controls retorna os controles que estão diretamente dentro deles, se o controle está dentro de um container ele não esta no form e por isso não é listado nessa coleção, a solução é bem simples, só precisa usar uma função recursiva pra isso, sua função ficaria mais ou menos assim:

 private static void AlteraCultura(Control parent, System.ComponentModel.ComponentResourceManager resx)
{
foreach (Control child in parent.Controls)
{
//Aqui faço com que o VS atualize o idioma no controle na coleção do form (OK Funciona)
resx.ApplyResources(child, child.Name, System.Threading.Thread.CurrentThread.CurrentCulture);
//Verifica se o controle tem outros controles dentro dele, se sim chama a função recursivamente
if (child.Controls.Count > 0)
AlteraCultura(child, resx);
}
}
LUIS.HERRERA 05/12/2012 15:07:53
#415488
OCELOT boa tarde.

Amigo funcionou perfeitamente. Obrigado.

A idéia que tenho é exatamente que o programa, ao ser aberto, uso o idioma do Windows, se não tiver então abre em português. O detalhe é imaginando que o windows esteja em Espanhol, mas quem vai usar quer o programa em inglês e não o português que é o padrão, então ele teria como entrar no menuStrip e selecionar o idioma desejado, no caso o inglês. Eu ainda não cheguei nessa fase, mas a idéia é gravar essa configuração no Windows, e ao abrir o programa ele procuraria a configuração para já abrir no idioma correto. Um passo de cada vez (rs).

Uma dúvida que surgiu, o comando que você passou:
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo([Ô]en-US[Ô]);

1) Poderia ser usado no Main() do programa, para carregar o idioma setado no registro do windows, e assim ser usado em uma variável pública que todos os formulários usariam para abrir corretamente?

2) Essa ajuste do código que passou, funciona também para um MDI Form e os controles: menuStrip, ToolTip, StatusStrip e notifyIcon ?
OCELOT 05/12/2012 15:52:06
#415497
1) Se usado no main antes de abrir o form você não precisa fazer nada para carregar a linguagem escolhida ali, e você pode por exemplo ler o registro do windows para pegar a linguagem escolhida ali antes de abrir o form.

Faça um teste, crie um projeto com um form e um label com um texto em português, mude o Localizable para true e o Language para [Ô]English (United States)[Ô], então mude o texto para inglês. Se simplesmente rodar o programa o texto em português vai aparecer (salvo o caso do seu windows ser em inglês), se você colocar aquela linha de código que passei no main vai ver que sem precisar fazer nada vai carregar o texto em inglês.

2) Deve funcionar para tudo que seja herdado de Control, não testei com os Strip mas como eles herdam do Control então deve funcionar sem problemas, já o NotifyIcon não herda de Control então ele não entra nessas collections, não sei bem como daria para pegar eles já que não existe realmente uma collection como a dos Controls, existe apenas um campo privado criado pelo designer chamado components, com um loop acho que seria bem difícil mesmo você fazer isso, principalmente se tiver outros componentes como por exemplo o ToolTip, por isso eu diria para você ir da outra forma que falei, usando o código no main para mudar o idioma, e caso o usuário queira mudar o idioma você mostra uma mensagem dizendo que tem que reiniciar o programa pra alteração ter efeito.
LUIS.HERRERA 05/12/2012 16:09:26
#415501
Legal OCELOT vou fazer assim então.
Muito obrigado por tudo.
Tópico encerrado , respostas não são mais permitidas