Estoy usando angular-translate para i18n en una aplicación AngularJS.
Para cada vista de la aplicación, hay un controlador dedicado. En los controladores siguientes, configuro el valor que se mostrará como título de la 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';
}])
Estoy cargando los archivos de traducción usando la extensión angular-translate-loader-url .
Problema
En la carga de la página inicial, se muestra la clave de traducción en lugar de la traducción de esa clave. La traducción es Hello, World!
, pero estoy viendo HELLO_WORLD
.
La segunda vez que voy a la página, todo está bien y se muestra la versión traducida.
Supongo que el problema tiene que ver con el hecho de que tal vez el archivo de traducción aún no esté cargado cuando el controlador asigna el valor a $scope.pageTitle
.
Observación
Al usar <h1>{{ pageTitle | translate }}</h1>
y $scope.pageTitle = 'HELLO_WORLD';
, la traducción funciona perfectamente desde la primera vez. El problema con esto es que no siempre quiero usar traducciones (por ejemplo, para el segundo controlador solo quiero pasar una cadena sin procesar).
Pregunta
¿Es este un problema / limitación conocido? ¿Cómo se puede solucionar esto?
fuente
$scope.$watch
es bastante exagerado ya que Angular Translate ofrece un servicio para usar en los controladores. Vea mi respuesta a continuación.$translate.instant()
ofrece lo mismo que un servicio. Además de esto, preste atención a la respuesta de Pascal.Recomendado: no traduzca en el controlador, traduzca en su vista
Recomendaría mantener su controlador libre de lógica de traducción y traducir sus cadenas directamente dentro de su vista de esta manera:
Usando el servicio provisto
Angular Translate proporciona el
$translate
servicio que puede utilizar en sus controladores.Un ejemplo de uso del
$translate
servicio puede ser:El servicio de traducción también tiene un método para traducir cadenas directamente sin necesidad de manejar una promesa, usando
$translate.instant()
:La desventaja de usar
$translate.instant()
podría ser que el archivo de idioma aún no está cargado si lo está cargando de forma asincrónica.Usando el filtro provisto
Esta es mi forma preferida ya que no tengo que manejar las promesas de esta forma. La salida del filtro se puede establecer directamente en una variable de alcance.
Usando la directiva proporcionada
Dado que @PascalPrecht es el creador de esta increíble biblioteca, recomendaría seguir su consejo (ver su respuesta a continuación) y usar la directiva provista que parece manejar las traducciones de manera muy inteligente.
fuente
En realidad, debería usar la directiva translate para tales cosas.
La directiva se encarga de la ejecución asincrónica y también es lo suficientemente inteligente como para dejar de ver los identificadores de traducción en el alcance si la traducción no tiene valores dinámicos.
Sin embargo, si no hay forma de evitarlo y realmente tiene que usar el
$translate
servicio en el controlador, debe envolver la llamada en un$translateChangeSuccess
evento usando$rootScope
en combinación con$translate.instant()
esto:Entonces, ¿por qué
$rootScope
y no$scope
? La razón de ello es que, en angular traducen de eventos se$emit
ed en$rootScope
lugar de$broadcast
Ed en$scope
porque no necesito para transmitir a través de toda la jerarquía alcance.¿Por qué
$translate.instant()
y no solo asincrónico$translate()
? Cuando$translateChangeSuccess
se dispara el evento, es seguro que los datos de traducción necesarios están allí y no se está produciendo una ejecución asíncrona (por ejemplo, ejecución de cargador asíncrono), por lo tanto, podemos usar el$translate.instant()
que es síncrono y simplemente asume que las traducciones están disponibles.Desde la versión 2.8.0 también existe
$translate.onReady()
, que devuelve una promesa que se resuelve tan pronto como las traducciones están listas. Ver el registro de cambios .fuente
{{::'HELLO_WORLD | translate}}'
.Para hacer una traducción en el controlador, puede usar el
$translate
servicio:Esa declaración solo hace la traducción en la activación del controlador, pero no detecta el cambio de tiempo de ejecución en el idioma. Para lograr ese comportamiento, puede escuchar el
$rootScope
evento:$translateChangeSuccess
y hacer la misma traducción allí:Por supuesto, puede encapsular el
$translate
servicio en un método y llamarlo en el controlador y en el$translateChangeSucess
oyente.fuente
Lo que está sucediendo es que Angular-translate está observando la expresión con un sistema basado en eventos, y al igual que en cualquier otro caso de enlace o enlace bidireccional, se dispara un evento cuando se recuperan los datos y se cambia el valor, lo que obviamente no funciona para la traducción. Los datos de traducción, a diferencia de otros datos dinámicos de la página, deben, por supuesto, mostrarse inmediatamente al usuario. No puede aparecer después de que se cargue la página.
Incluso si puede depurar con éxito este problema, el mayor problema es que el trabajo de desarrollo involucrado es enorme. Un desarrollador tiene que extraer manualmente todas las cadenas del sitio, ponerlas en un archivo .json y hacer referencia a ellas manualmente mediante un código de cadena (es decir, 'pageTitle' en este caso). La mayoría de los sitios comerciales tienen miles de cadenas para las que esto debe suceder. Y eso es sólo el comienzo. Ahora necesita un sistema para mantener las traducciones sincronizadas cuando el texto subyacente cambia en algunas de ellas, un sistema para enviar los archivos de traducción a los distintos traductores, para reintegrarlos en la compilación, para volver a implementar el sitio para que los traductores puedan ver sus cambios de contexto, y así sucesivamente.
Además, como se trata de un sistema 'vinculante' basado en eventos, se activa un evento para cada cadena de la página, que no solo es una forma más lenta de transformar la página, sino que también puede ralentizar todas las acciones de la página. si comienza a agregarle una gran cantidad de eventos.
De todos modos, usar una plataforma de traducción de posprocesamiento tiene más sentido para mí. Usando GlobalizeIt, por ejemplo, un traductor puede simplemente ir a una página del sitio y comenzar a editar el texto directamente en la página para su idioma, y eso es todo: https://www.globalizeit.com/HowItWorks . No se necesita programación (aunque puede ser extensible mediante programación), se integra fácilmente con Angular: https://www.globalizeit.com/Translate/Angular , la transformación de la página ocurre de una vez y siempre muestra el texto traducido con el render inicial de la página.
Divulgación completa: soy cofundador :)
fuente