J'utilise angular-translate pour i18n dans une application AngularJS.
Pour chaque vue d'application, il existe un contrôleur dédié. Dans les contrôleurs ci-dessous, j'ai défini la valeur à afficher comme titre de page.
Code
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';
}])
Je charge les fichiers de traduction à l'aide de l' extension angular-translate-loader-url .
Problème
Lors du chargement initial de la page, la clé de traduction est affichée à la place de la traduction de cette clé. La traduction est Hello, World!
, mais je vois HELLO_WORLD
.
La deuxième fois que je vais sur la page, tout va bien et la version traduite est affichée.
Je suppose que le problème est lié au fait que le fichier de traduction n'est peut-être pas encore chargé lorsque le contrôleur attribue la valeur à $scope.pageTitle
.
Remarque
Lors de l'utilisation <h1>{{ pageTitle | translate }}</h1>
et$scope.pageTitle = 'HELLO_WORLD';
, la traduction fonctionne parfaitement dès la première fois. Le problème avec ceci est que je ne veux pas toujours utiliser des traductions (par exemple, pour le deuxième contrôleur, je veux juste passer une chaîne brute).
Question
S'agit-il d'un problème / limitation connu? Comment cela peut-il être résolu?
la source
$scope.$watch
est plutôt exagéré car Angular Translate propose un service à utiliser dans les contrôleurs. Voir ma réponse ci-dessous.$translate.instant()
offre la même chose qu'un service. A côté de cela, faites attention à la réponse de Pascal.Recommandé: ne traduisez pas dans le contrôleur, traduisez dans votre vue
Je vous recommande de garder votre contrôleur exempt de logique de traduction et de traduire vos chaînes directement dans votre vue comme ceci:
Utilisation du service fourni
Angular Translate fournit le
$translate
service que vous pouvez utiliser dans vos contrôleurs.Un exemple d'utilisation du
$translate
service peut être:Le service de traduction a également une méthode pour traduire directement des chaînes sans avoir besoin de gérer une promesse, en utilisant
$translate.instant()
:L'inconvénient de l'utilisation
$translate.instant()
pourrait être que le fichier de langue n'est pas encore chargé si vous le chargez de manière asynchrone.Utilisation du filtre fourni
C'est ma méthode préférée car je n'ai pas à gérer les promesses de cette façon. La sortie du filtre peut être directement définie sur une variable de portée.
Utilisation de la directive fournie
Puisque @PascalPrecht est le créateur de cette bibliothèque géniale, je recommanderais de suivre son conseil (voir sa réponse ci-dessous) et d'utiliser la directive fournie qui semble gérer les traductions très intelligemment.
la source
En fait, vous devriez plutôt utiliser la directive translate pour ce genre de choses.
La directive prend en charge l'exécution asynchrone et est également suffisamment intelligente pour déverrouiller les identifiants de traduction sur la portée si la traduction n'a pas de valeurs dynamiques.
Cependant, s'il n'y a pas moyen de contourner et vous vraiment avoir à utiliser le
$translate
service dans le contrôleur, vous devez envelopper l'appel dans un$translateChangeSuccess
événement à l' aide$rootScope
en combinaison avec$translate.instant()
comme ceci:Alors pourquoi
$rootScope
et pas$scope
? La raison en est que, dans angular-translate, les événements sont$emit
édités$rootScope
plutôt que$broadcast
modifiés$scope
parce que nous n'avons pas besoin de diffuser à travers toute la hiérarchie de portée.Pourquoi
$translate.instant()
et pas seulement asynchrone$translate()
? Lorsque l'$translateChangeSuccess
événement est déclenché, il est certain que les données de traduction nécessaires sont présentes et qu'aucune exécution asynchrone ne se produit (par exemple, l'exécution du chargeur asynchrone), nous pouvons donc simplement utiliser$translate.instant()
ce qui est synchrone et suppose simplement que les traductions sont disponibles.Depuis la version 2.8.0, il y a aussi
$translate.onReady()
, qui renvoie une promesse qui est résolue dès que les traductions sont prêtes. Voir le changelog .la source
{{::'HELLO_WORLD | translate}}'
.Pour faire une traduction dans le contrôleur, vous pouvez utiliser le
$translate
service:Cette instruction ne fait que la traduction lors de l'activation du contrôleur, mais elle ne détecte pas le changement de langue à l'exécution. Afin d'obtenir ce comportement, vous pouvez écouter l'
$rootScope
événement:$translateChangeSuccess
et y faire la même traduction:Bien sûr, vous pouvez encapsuler le
$translate
service dans une méthode et l'appeler dans le contrôleur et dans l'$translateChangeSucess
écouteur.la source
Ce qui se passe, c'est que Angular-translate surveille l'expression avec un système basé sur des événements, et comme dans tout autre cas de liaison ou de liaison bidirectionnelle, un événement est déclenché lorsque les données sont récupérées et la valeur modifiée, ce qui ne fonctionne évidemment pas pour la traduction. Les données de traduction, contrairement aux autres données dynamiques de la page, doivent bien sûr apparaître immédiatement à l'utilisateur. Il ne peut pas apparaître après le chargement de la page.
Même si vous parvenez à déboguer ce problème avec succès, le plus gros problème est que le travail de développement impliqué est énorme. Un développeur doit extraire manuellement chaque chaîne du site, la mettre dans un fichier .json, la référencer manuellement par code de chaîne (c'est-à-dire «pageTitle» dans ce cas). La plupart des sites commerciaux ont des milliers de chaînes pour lesquelles cela doit se produire. Et ce n'est que le début. Vous avez maintenant besoin d'un système permettant de synchroniser les traductions lorsque le texte sous-jacent change dans certains d'entre eux, d'un système d'envoi des fichiers de traduction aux différents traducteurs, de les réintégrer dans la construction, de redéployer le site pour que les traducteurs puissent voir leurs changements de contexte, et ainsi de suite.
De plus, comme il s'agit d'un système basé sur des événements, un événement est déclenché pour chaque chaîne de la page, ce qui non seulement est un moyen plus lent de transformer la page, mais peut ralentir toutes les actions sur la page, si vous commencez à y ajouter un grand nombre d'événements.
Quoi qu'il en soit, utiliser une plate-forme de traduction post-traitement a plus de sens pour moi. En utilisant GlobalizeIt par exemple, un traducteur peut simplement accéder à une page du site et commencer à éditer le texte directement sur la page pour sa langue, et c'est tout: https://www.globalizeit.com/HowItWorks . Aucune programmation nécessaire (bien qu'il puisse être extensible par programme), il s'intègre facilement à Angular: https://www.globalizeit.com/Translate/Angular , la transformation de la page se produit en une seule fois, et il affiche toujours le texte traduit avec le rendu initial de la page.
Divulgation complète: je suis co-fondateur :)
la source