Правильное использование для angular-translate in controllers

Я использую угловой-перевести для i18n в приложении AngularJS.

для каждого представления приложения есть специальный контроллер. В контроллерах ниже я устанавливаю значение, которое будет отображаться как заголовок страницы.

код

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';
    }])

я загружаю файлы перевода с помощью угловой-перевести-загрузчик-url расширение.

5 ответов


редактировать: пожалуйста, см. ответ от PascalPrecht (автор angular-translate) для лучшего решения.


асинхронный характер загрузки вызывает проблему. Видите ли, с {{ pageTitle | translate }}, Angular будет следить за выражением; при загрузке данных локализации значение выражения изменяется, и экран обновляется.

Итак, вы можете сделать это сами:

.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
    $scope.$watch(
        function() { return $filter('translate')('HELLO_WORLD'); },
        function(newval) { $scope.pageTitle = newval; }
    );
});

однако, это будет работать наблюдал за выражением каждый цикл переваривания. Это неоптимально и может или не может вызвать заметное снижение производительности. Во всяком случае, это то, что делает Angular, поэтому это не может быть так плохо...


рекомендуется: не переводите в контроллере, переводите на свой взгляд

Я бы рекомендовал сохранить ваш контроллер свободным от логики перевода и перевести строки непосредственно в вашем представлении следующим образом:

<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>

используя предоставленную услугу

угловой перевод обеспечивает $translate сервис, который вы можете использовать в своих контроллерах.

пример использования $translate сервис могут быть:

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {
    $translate('PAGE.TITLE')
        .then(function (translatedValue) {
            $scope.pageTitle = translatedValue;
        });
});

в translate service также имеет метод прямого перевода строк без необходимости обрабатывать обещание, используя $translate.instant():

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {
    $scope.pageTitle = $translate.instant('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});

недостаток с помощью $translate.instant() может быть, что языковой файл еще не загружен, если вы загружаете его асинхронно.

используя предоставленный фильтр

это мой предпочтительный способ, так как мне не нужно обрабатывать обещания таким образом. Выходе фильтра может быть непосредственно установлен в переменной области.

.controller('TranslateMe', ['$scope', '$filter', function ($scope, $filter) {
    var $translate = $filter('translate');

    $scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});

используя предоставленная директива

так как @PascalPrecht является создателем этой удивительной библиотеки, я бы рекомендовал пойти с его совет (см. Его ответ ниже) и используйте предоставленную директиву, которая, похоже, обрабатывает переводы очень умно.

директива заботится об асинхронном выполнении и также достаточно умна, чтобы отменить сопоставление идентификаторов перевода в области, если перевод не имеет динамических значений.


на самом деле, вы должны использовать директиву translate для таких вещей.

<h1 translate="{{pageTitle}}"></h1>

директива заботится об асинхронном выполнении и также достаточно умна, чтобы отменить сопоставление идентификаторов перевода в области, если перевод не имеет динамических значений.

однако, если нет никакого способа обойти, и вы действительно обязательно использовать $translate сервис в контроллере, вы должны обернуть вызов в $translateChangeSuccess событие с помощью $rootScope в сочетании с $translate.instant() вот так:

.controller('foo', function ($rootScope, $scope, $translate) {
  $rootScope.$on('$translateChangeSuccess', function () {
    $scope.pageTitle = $translate.instant('PAGE.TITLE');
  });
})

почему $rootScope, а не $scope? Причина этого в том, что в angular-translate события $emited on $rootScope, а не $broadcasted on $scope потому что нам не нужно транслировать по всей иерархии масштабов.

почему $translate.instant() и не только асинхронных $translate()? Когда $translateChangeSuccess событие запускается, он уверен, что необходимые данные перевода есть и не происходит асинхронного выполнения (например, асинхронный загрузчик исполнения), поэтому мы можем просто использовать $translate.instant(), который является синхронным и просто предполагает, что переводы доступны.

начиная с версии 2.8.0 там тоже $translate.onReady(), который возвращает обещание, которое разрешается, как только переводы будут готовы. посмотреть историю изменений.


чтобы сделать перевод в контроллере, вы можете использовать $translate сервис:

$translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
    vm.si = translations['COMMON.SI'];
    vm.no = translations['COMMON.NO'];
});

этот оператор выполняет только перевод при активации контроллера, но не обнаруживает изменения времени выполнения на языке. Чтобы достичь такого поведения, вы можете слушать $rootScope событие: $translateChangeSuccess и сделайте там тот же перевод:

    $rootScope.$on('$translateChangeSuccess', function () {
        $translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
            vm.si = translations['COMMON.SI'];
            vm.no = translations['COMMON.NO'];
        });
    });

конечно, вы можете инкапсулировать $translateсервис в методе и вызовите его в контроллере и в $translateChangeSucessслушатель.


происходит то, что Angular-translate наблюдает за выражением с системой на основе событий, и, как и в любом другом случае привязки или двухсторонней привязки, событие запускается при извлечении данных и изменении значения, что, очевидно, не работает для перевода. Данные перевода, в отличие от других динамических данных на странице, должны, конечно, немедленно отображаться пользователю. Он не может появиться после загрузки страницы.

даже если вы можете успешно отладить этот вопрос, большая проблема заключается в том, что связанная с разработкой работа огромна. Разработчик должен вручную извлечь каждую строку на сайте, поместить ее в a .файл json, вручную ссылаться на него строковым кодом (т. е. 'pageTitle' в этом случае). Большинство коммерческих сайтов имеют тысячи строк, для которых это должно произойти. И это только начало. Теперь вам нужна система синхронизации переводов при изменении базового текста в некоторых из них, система отправки файлов переводов в различные переводчики, реинтеграции их в сборку, перераспределения сайта, чтобы переводчики могли видеть их изменения в контексте, и так далее.

кроме того, поскольку это "привязка", основанная на событиях система, событие запускается для каждой строки на странице, что не только является более медленным способом преобразования страницы, но и может замедлить все действия на странице, если вы начнете добавлять к ней большое количество событий.

в любом случае, используя постобработку перевода платформа имеет больше смысла для меня. Используя например GlobalizeIt, переводчик может просто зайти на страницу на сайте и начать редактирование текста непосредственно на страницу для их языка, и вот это: https://www.globalizeit.com/HowItWorks. Никакого программирования не требуется (хотя это может быть программно расширяемая), он легко интегрируется с углового: https://www.globalizeit.com/Translate/Angular трансформация страниц происходит на одном дыхании, и он всегда отображается переведенный текст с начальной отрисовки страницы.

полное раскрытие: я соучредитель:)