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