Когда мне прилетела задача реализовать перевод для уже немаленького проекта, честно, я немного потерялась. Есть несколько вариантов библиотек, помогающих с данной задачей, но остановилась я на i18n для Angular и вот почему. На мой субъективный взгляд библиотека замечательно справляется с локализацией уже готового проекта. Но даже так, придется немного повозиться, без этого никуда.

Уточню, что данная статья описывает процессы для Angular v.9 и выше. Надеюсь информация будет вам полезна.

Шаг 1. Установка

Для работы с i18n необходимо установить пакет @angular/localize. Можно использовать любой привычный для Вас менеджер пакетов или воспользоваться CLI от Angular.

ng add @angular/localize
npm install -D @angular/localiz
yarn add --dev @angular/localize

Далее сразу предлагаю дополнить настройки в конфиге angular.json. Пример ниже:

{
  "projects": {
    "my-project": {
      "i18n": { // Настройки для i18n. Обязательно нужно добавить.
        "sourceLocale": { // Настройка языка по умолчанию. 
          "code": "ru",
          "baseHref": "/ru/" // Путь до корневой папки при билде. Необязательный парамер, но мне пригодилось
        },
        "locales": { // Другие поддерживаемые языки
          "en": {
            "translation": "src/locale/messages.en.xlf", // Путь до файла с переводом
            "baseHref": "/en/"
          }
        }
      },
      "build": {
        "options": {
          "localize": true, // Флаг указывает на поддержку локализации
          "i18nMissingTranslation": "error", // Сообщает об отсутсвии перевода при билде проекта
          
          //...
        },
        "configurations": {
          "ru": {  // Конфигулации для конкретного языка, поможет при тестировании
            "localize": ["ru"]
          },
          "en" : {
            "localize": ["en"]
          }
          
          //...
        }
        
        //...
      },
      "serve": {
        "configurations": {
          "ru": {
            "browserTarget": "my-project:build:development,ru" // Конфигулации для при тестирования
          },
          "en": {
            "browserTarget": "my-project:build:development,en"
          }
          
          //...
        }
      }

      //...
    }
  }
}

Шаг 2. Подготовка к переводу

Перевод в html-шаблонах

Для html все достаточно просто. После установки и настройки нам становится доступен
i18n-атрибут. Просто отмечаем теги с текстом, который хотим перевести.

<h1 i18n>Переведи меня!!!</h1>

Атрибут выступает в роли маркера для локализации. При компиляции он будет удален, а текст заменен переводом на текущий язык.

В атрибут можно передать дополнительные данные, такие как значение, описание или id

<h1 i18n="Значение|описание@@id">Переведи меня!!!</h1>

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

Прелесть i18n в том, что его можно использовать не только в стандартных html-тегах, но и в ng-container

<ng-container *ngIf="flag" i18n>Текст по условию</ng-container>

Замечание: В Angular до v.9 можно было использовать конструкцию

<h1 i18n>{{flag ? "Текст по условию 1" : "Текст по условию 2"}}</h1>

После v.9 такая конструкция в файл с переводом не попадет.

Используйте ng-container

Также можно переводить не только текст в тегах, но и текст в атрибутах, используя
i18n-{attribute_name}

<inpul i18n-placeholder placeholder="Пароль"/>

Перевод в typescript файлах

В typescript файлах доступна функция $localize. Подробнее о ней можно почитать тут.

Работает она схожим образом.

$localize`:Значение|описание@@id:Переведи меня!!!`;

Замечание: Некоторые редакторы кода норовят добавить импорт функции $localize. Только вот импортировать ее не нужно. Функция удалится из кода при компиляции, а импорт останется. Не повторяйте моих ошибок))

Шаг 3. Генерация файла и перевод

После того как все, что хотелось перевести, отмечено, можно генерировать файл с текстовками. Для этого в Angular CLI есть отдельная команда extract-i18n. При желании ее можно настроить в конфиге Angular

{
  
  //...
  "projects": {
    "my-project": {
      
      //...
      "architect": {
        
        //...
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "my-project:build",
            "format": "xlf", // формат для файлов с переводом
            "outputPath": "src/locale" // Путь для файлов с переводом
          }
        }
      }
    }
  }

Подробнее тут.

Просто запускаем команду

ng extract-i18n

С настройками выше Вы получите файл messages.xlf с собранными текстовками по пути src/locale.

<?xml version="1.0" encoding="UTF-8" ?>

<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="ru" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="id" datatype="html">
        <source>Переведи меня</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">1</context>
        </context-group>
        <note priority="1" from="description">Значение</note>
        <note priority="1" from="meaning">описание</note>
      </trans-unit>
    </body>
  </file>
</xliff>

Теперь дублируем файл и изменяем его имя на messages.en.xlf, должно получиться 2 файла, один с языком по умолчанию, второй с переводом. Осталось только перевести текстовки, заменив текст в поле source на перевод. Не забудьте изменить атрибут source-language в теге file на "en"

Проверить все ли переведено правильно можно с помощью команды

ng serve --configuration=en --open

Запустится проект с переведенными текстовками. Таким образом можно проверить перевод и не поехала ли верстка при переводе.

Остается только сбилдить проект, а для этого у нас уже все готово. запускаем команду 
ng build.

В результате получим структуру файлов

dist
  ru
    /// файлы на русском
  en
    /// файлы на английском

Шаг 4. Изменения в проекте

При разработке проекта без изменений никуда. Что-то нужно добавить, удалить или изменить. И текстовки не исключение.

Изменим наш старый вариант

<h1 i18n="Значение|описание@@id">Переведи меня!!!</h1>

<p i18n="Значение2|описание2@@id-2">Новый текст...</p>

Снова запустим уже известную нам команду

ng extract-i18n

Она автоматически заменит содержимое файла messages.xlf на новое.

<?xml version="1.0" encoding="UTF-8" ?>

<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="ru" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="id" datatype="html">
        <source>Переведи меня</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">1</context>
        </context-group>
        <note priority="1" from="description">Значение</note>
        <note priority="1" from="meaning">описание</note>
      </trans-unit>
      <trans-unit id="id2" datatype="html">
        <source>Новый текст...</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">3</context>
        </context-group>
        <note priority="1" from="description">Значение2</note>
        <note priority="1" from="meaning">описание2</note>
      </trans-unit>
    </body>
  </file>
</xliff>

Но файл messages.en.xlf останется без изменений. А при попытке сбилдить проект с настройками в шаге 1 вылетит ошибка. Чтобы ее избежать необходимо вручную добавить новый перевод в файл messages.en.xlf.

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
      <trans-unit id="id" datatype="html">
        <source> Transfer me</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">1</context>
        </context-group>
        <note priority="1" from="description">Значение</note>
        <note priority="1" from="meaning">описание</note>
      </trans-unit>
      <trans-unit id="id2" datatype="html">
        <source> New text...</source>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">3</context>
        </context-group>
        <note priority="1" from="description">Значение2</note>
        <note priority="1" from="meaning">описание2</note>
      </trans-unit>
    </body>
  </file>
</xliff>

Итог

I18n достаточно прост и удобен в использовании, а для работы с форматом xliff есть удобные программы. В этой статье я описала путь от установки и настройки до компиляции. Надеюсь она будет полезна.

Напоследок поделюсь ссылками на возможности i18n не описанные в этой статье.

Склонение по числам(plural) – позволяет указать разные склонения для слова (день, дня, дней).

Выбор альтернативного варианта (select) – позволяет указать на альтернативные варианты текстовок по текстовому ключу (мужская одежда, женская одежда).

 

Комментарии (5)


  1. tertiumnon
    10.09.2023 20:25

    Внедрить xml в 21 веке мог только старпёр. Некрасивое решение.


  1. domix32
    10.09.2023 20:25

    i18n

    локализация

    Это какой-то мем?


  1. berestov1
    10.09.2023 20:25

    Мы на своём проекте используем Transloco. Переводы хранятся в .json файлах.


    1. litvi74 Автор
      10.09.2023 20:25

      Смотрела на нее) наверное даже выбрала бы, если бы проект не большой был или с 0 писать надо было.


  1. litvi74 Автор
    10.09.2023 20:25

    Смотрела на нее) наверное даже выбрала бы, если бы проект не большой был или с 0 писать надо было.