Когда мне прилетела задача реализовать перевод для уже немаленького проекта, честно, я немного потерялась. Есть несколько вариантов библиотек, помогающих с данной задачей, но остановилась я на 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) – позволяет указать на альтернативные варианты текстовок по текстовому ключу (мужская одежда, женская одежда).
