Estou usando angular-translate para i18n em um aplicativo AngularJS.
Para todas as visualizações de aplicativos, há um controlador dedicado. Nos controladores abaixo, defino o valor a ser mostrado como o título da página.
Código
HTML
<h1>{{ pageTitle }}</h1>
Javascript
.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
$scope.pageTitle = $filter('translate')('HELLO_WORLD');
}])
.controller('SecondPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
$scope.pageTitle = 'Second page title';
}])
Estou carregando os arquivos de tradução usando a extensão angular-translate-loader-url .
Problema
No carregamento inicial da página, a chave de conversão é mostrada em vez da tradução dessa chave. A tradução é Hello, World!
, mas estou vendo HELLO_WORLD
.
Na segunda vez que vou à página, tudo está bem e a versão traduzida é mostrada.
Suponho que o problema esteja relacionado ao fato de que talvez o arquivo de tradução ainda não esteja carregado quando o controlador estiver atribuindo o valor $scope.pageTitle
.
Observação
Ao usar <h1>{{ pageTitle | translate }}</h1>
e$scope.pageTitle = 'HELLO_WORLD';
, a tradução funciona perfeitamente desde a primeira vez. O problema disso é que nem sempre quero usar traduções (por exemplo, para o segundo controlador, só quero passar uma string bruta).
Questão
Esse é um problema / limitação conhecido? como isso pode ser resolvido?
fonte
$scope.$watch
é um exagero, já que o Angular Translate está oferecendo um serviço para ser usado nos controladores. Veja minha resposta abaixo.$translate.instant()
oferece o mesmo que um serviço. Além disso, preste atenção à resposta de Pascal.Recomendado: não traduza no controlador, traduza na sua opinião
Eu recomendo manter seu controlador livre da lógica de tradução e traduzir suas strings diretamente dentro da sua visualização da seguinte maneira:
Usando o serviço fornecido
O Angular Translate fornece o
$translate
serviço que você pode usar em seus Controladores.Um exemplo de uso do
$translate
serviço pode ser:O serviço de conversão também possui um método para traduzir diretamente as strings sem a necessidade de lidar com uma promessa, usando
$translate.instant()
:A desvantagem de usar
$translate.instant()
pode ser que o arquivo de idioma ainda não esteja carregado se você estiver carregando de forma assíncrona.Usando o filtro fornecido
Esta é a minha maneira preferida, pois não preciso lidar com promessas dessa maneira. A saída do filtro pode ser definida diretamente para uma variável de escopo.
Usando a diretiva fornecida
Como o @PascalPrecht é o criador desta incrível biblioteca, recomendo que siga o conselho dele (veja a resposta abaixo) e use a diretiva fornecida, que parece lidar com traduções de maneira muito inteligente.
fonte
Na verdade, você deve usar a diretiva translate para essas coisas.
A diretiva cuida da execução assíncrona e também é inteligente o suficiente para desbloquear os IDs de tradução no escopo se a tradução não tiver valores dinâmicos.
No entanto, se não houver maneira de contornar e você realmente precisar usar o
$translate
serviço no controlador, encerre a chamada em um$translateChangeSuccess
evento usando$rootScope
em combinação com o$translate.instant()
seguinte:Então, por que
$rootScope
não$scope
? A razão disso é que, nos eventos do angular-translate, são$emit
editados$rootScope
e não$broadcast
editados$scope
porque não precisamos transmitir por toda a hierarquia do escopo.Por que
$translate.instant()
e não apenas assíncrono$translate()
? Quando o$translateChangeSuccess
evento é disparado, é certo que os dados de conversão necessários estão lá e nenhuma execução assíncrona está acontecendo (por exemplo, execução assíncrona do carregador); portanto, podemos apenas usar o$translate.instant()
que é síncrono e apenas assume que as traduções estão disponíveis.Desde a versão 2.8.0, também há
$translate.onReady()
, o que retorna uma promessa que é resolvida assim que as traduções estiverem prontas. Veja o changelog .fonte
{{::'HELLO_WORLD | translate}}'
.Para fazer uma tradução no controlador, você pode usar o
$translate
serviço:Essa declaração faz apenas a tradução na ativação do controlador, mas não detecta a alteração no tempo de execução no idioma. Para atingir esse comportamento, você pode ouvir o
$rootScope
evento:$translateChangeSuccess
e fazer a mesma tradução lá:Obviamente, você pode encapsular o
$translate
serviço em um método e chamá-lo no controlador e no$translateChangeSucess
ouvinte.fonte
O que está acontecendo é que o Angular-translate está assistindo a expressão com um sistema baseado em eventos e, como em qualquer outro caso de ligação ou de mão dupla, um evento é disparado quando os dados são recuperados e o valor alterado, o que é alterado. obviamente não funciona para tradução. Os dados de tradução, diferentemente de outros dados dinâmicos da página, devem, é claro, aparecer imediatamente para o usuário. Não pode aparecer após o carregamento da página.
Mesmo que você possa depurar com êxito esse problema, o maior problema é que o trabalho de desenvolvimento envolvido é enorme. Um desenvolvedor precisa extrair manualmente todas as strings do site, colocá-las em um arquivo .json, referenciá-las manualmente pelo código da string (por exemplo, 'pageTitle' neste caso). A maioria dos sites comerciais possui milhares de strings para as quais isso precisa acontecer. E isso é apenas o começo. Agora você precisa de um sistema para manter as traduções sincronizadas quando o texto subjacente for alterado em algumas delas, um sistema para enviar os arquivos de tradução para os vários tradutores, reintegrá-los na compilação, reimplementar o site para que os tradutores possam ver suas mudanças de contexto, e assim por diante.
Além disso, como este é um sistema baseado em eventos "vinculativo", um evento está sendo acionado para cada sequência de caracteres na página, o que não só é uma maneira mais lenta de transformar a página, mas também pode retardar todas as ações da página, se você começar a adicionar um grande número de eventos a ele.
De qualquer forma, usar uma plataforma de tradução pós-processamento faz mais sentido para mim. Usando o GlobalizeIt, por exemplo, um tradutor pode simplesmente ir para uma página no site e começar a editar o texto diretamente na página para o idioma deles, e é isso: https://www.globalizeit.com/HowItWorks . Sem necessidade de programação (embora possa ser programaticamente extensível), ele se integra facilmente ao Angular: https://www.globalizeit.com/Translate/Angular , a transformação da página ocorre de uma só vez e sempre exibe o texto traduzido com a renderização inicial da página.
Divulgação completa: Sou co-fundador :)
fonte