Статьи

Углубленное обучение: настройте языковую культуру до отображения любого пользовательского интерфейса

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

Эта статья является частью моей серии «Learning NG» , в которой рассказывается о моих приключениях во время изучения Angular. Проверьте вступление серии и другие статьи . Обратите внимание, я новичок в Angular, поэтому я более чем рад любым отзывам и предложениям по улучшению от более опытных людей, чем я.

проблема

В своем приложении я устанавливаю язык пользователя на основе его личных предпочтений. Это означает, что у меня есть бэкэнд API, /api/v1/users/currentкоторый возвращает информацию о текущем пользователе:

{
  "username": "juristr",
  ...
  "language": "de"
}

Как большинство разработчиков, я использую angular-translate для i18n . Поэтому, помимо некоторых подробностей о том, как я использую возможности частичной загрузки angular-translate для получения всех различных файлов локализации, я использую $translate.use(..)для установки языка на основе предпочтений пользователя. Изменение языка автоматически обновит все переводы, связанные с пользовательским интерфейсом.

{{ "message" | translate }}

Все идет нормально. Но есть проблема: я должен убедиться, что язык установлен перед визуализацией интерфейса, чтобы убедиться, что данные отображаются в правильной локали. Но подождите, разве вы не сказали, что пользовательский интерфейс будет обновляться при смене языка? По крайней мере, вы видите мерцание ..

Ну, не совсем так. Моя структура данных выглядит так:

{
  name: {
    de: 'Deutscher',
    en: 'English value',
    it: 'valore in italiano'
  },
  ...
}

В коде HTML я связываю это как.

{{ vm.data.name[vm.currentLanguage] }}

… и контроллер, очевидно, привязывает vm.currentLanguageк $translate.use()и vm.dataк образцу структуры данных, показанной выше.

Теперь это больше не обновляет.

Решение

Прежде всего я должен был убедиться, что пользователь и язык заданы прежде всего. Поскольку пользователь может войти в приложение по какому-либо клиентскому маршруту /index.html#people/edit, функция разрешения маршрута предложила себя в качестве хорошего кандидата.

Кроме того, $translate.use()возвращает обещание! Результат:

$stateProvider
  .state('home', {
     url: '/',
     ...
     resolve: {
       ensureUserAndLanguage: function($log, $q, $translate, user){
         var deferred = $q.defer();
         user.getCurrent()
           .then(function(result){
             $log.debug('Route resolve. Setting lang to ' + result.language);

             // HERE'S THE IMPORTANT PART!!
             $translate.use(result.language)
               .then(function(){
                  $log.debug('$translate.use. Lang is: ' + $translate.use());

                  deferred.resolve();
               });

           });

         return deferred.promise;
       }
     }
  });

И это работает! Вот файл Plunker с кодом. Обратите внимание, что вы должны открыть окно редактирования, чтобы увидеть, как оно работает правильно.

Ссылка на сайт

Attention: In my real application, I dynamically attach the above shown resolve function to my routes. Obviously you need to cache calls like user.getCurrent() s.t. they don’t call the backend each time a client-side route changes. Furthermore while simply resolving with nothing, it would be more meaningful to resolve with an object that contains the user object and current language s.t. they are at disposal for an eventual controller, like:

resolve: {
    metaInfo: function(...) {
      var deferred = $q.defer();
      ...
      user.getCurrent()
        .then(function(result){
          ...
          $translate.use(result.language)
            .then(function(currentLanguage){
                deferred.resolve({
                  user: result,
                  language: currentLanguage
                });
            });
        });
      ...
    }
}

An eventual «route controller» can then take an object metaInfo containing the user and current language.