Сайт визитка на Angular. Настройка локализации.

Aleksandr Serenko
F.A.F.N.U.R
Published in
5 min readMar 27, 2022

В данной статье рассмотрим интеграцию локализации в приложении.

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

Для установки локализации достаточно установить пакет
nx add @angular/localize

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

Сначала сконфигурируем локализацию в настройках сборки, где в файл проекта добавим локализацию apps/store/project.json:

{
"projectType": "application",
"root": "apps/store",
"sourceRoot": "apps/store/src",
"prefix": "banshop",
...
"i18n": {
"sourceLocale": "en-US",
"locales": {
"ru-RU": {
"translation": "libs/russian/localization/src/lib/messages.xlf",
"baseHref": ""
}
}
},
...
}

Как видно из настроек, файл локализации размещается в libs/russian/localization/src/lib/messages.xlf.

Для браузерной сборки укажем локализацию:

"build": {
...
"options": {
...
"localize": ["ru-RU"],
},
...
}

Для серверной версии все не так однозначно.

Из-за того, что dev-server не может корректно подключить локаль, то для сервреной сборки указывается localize: false, а для production уже ставится верная локаль:

"server": {
"executor": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/store/server",
"main": "apps/store/server.ts",
"tsConfig": "apps/store/tsconfig.server.json",
"inlineStyleLanguage": "scss",
"localize": false
},
"configurations": {
"production": {
"localize": ["ru-RU"],
"outputHashing": "media",
"fileReplacements": [
{
"replace": "apps/store/src/environments/environment.ts",
"with": "apps/store/src/environments/environment.prod.ts"
}
],
"bundleDependencies": true
},
"development": {
"localize": ["ru-RU"],
"optimization": false,
"sourceMap": true,
"extractLicenses": false
},
"ru": {
"optimization": false,
"sourceMap": true,
"extractLicenses": false
}
},
"defaultConfiguration": "production"
},

И тогда для запуска serve-ssr меняем конфигурацию на ru:

"serve-ssr": {
"executor": "@nguniversal/builders:ssr-dev-server",
"configurations": {
"development": {
"browserTarget": "store:build:development",
"serverTarget": "store:server:ru"
},
"production": {
"browserTarget": "store:build:production",
"serverTarget": "store:server:production"
}
},
"defaultConfiguration": "development"
},

Localication Module

Для это создадим отельный модуль, который будет подключаться в AppCoreModule.

Добавим новую библиотеку:

nx g lib russian/localization

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

Формат даты также отличается от страны к стране.

Создадим адаптер дат, для корректной работы с Angular Material:

Определим локаль в модуле и подключим выше созданные сервисы:

  • LOCALE_ID — токен текущей локализации в приложении. Его используют все пайпы, которые зависят от локали;
  • DEFAULT_CURRENCY_CODE — токен, который содержит в себе тип валюты;
  • MAT_DATE_LOCALE — токен с текущей локализации в Angular Material
  • DateAdapter — адаптер даты;
  • FormMaskService — сервис для работы с масками;
  • MAT_RADIO_DEFAULT_OPTIONS — токен, который устанавливает цвет по умолчанию для радио кнопок в приложении;
  • MAT_CHECKBOX_DEFAULT_OPTIONS — токен, который устанавливает цвет по умолчанию для чекбоксов в приложении.

Для того, чтобы Angular загрузил локализированные данные, в приложение импортируется и регистрируется русская дата:

import { registerLocaleData } from '@angular/common';
import localeRu from '@angular/common/locales/ru';
registerLocaleData(localeRu);

Локализация компонентов

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

Пример ее использования на странице ошибок:

<banshop-error-title i18n="Error not found|Title">
Page not found
</banshop-error-title>

Формат задания следующий: сначала идет тип перевода, потом описание, которое должно помочь переводчику.

Если запустить команду локазации, то Angular сгенерирует новый файл локализкации:

nx extract-i18n store --out-file=libs/russian/localization/src/lib/source.xlf

Из команды видно, что файл локализации сохраниться в libs/russian/localization/src/lib/source.xlf.

Для примера выше будет создан файл source.xlf :

  • trans-unit — объект перевода, где id уникальный идентификатор для строки перевода;
  • source — исходный перевод;
  • context-group — содержит информацию о размещении перевода
  • note — замечания к переводу.

Для того чтобы добавить перевод, необходимо после source создать новый тег:

<target state="translated">Страница не найдена</target>

Если добавить данный тег, то тогда строка в приложении «Page not found» перейдет в «Страница не найдена».

Итоговый файл:

<trans-unit id="c9be140e4b3e7fe071d29de65b243fb4e2a6bbba" datatype="html">
<source>Page not found</source>
<target state="translated">Страница не найдена</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/errors/not-found/page/src/lib/not-found-page.component.html</context>
<context context-type="linenumber">3</context>
</context-group>
<note priority="1" from="description">Title</note>
<note priority="1" from="meaning">Error not found</note>
</trans-unit>

Для локализации внутри компонентов, используется глобальная переменная $localize.

Пример использования:

{
title: $localize`:Errors server|:Internal server error | Banshop`,
}

В данном случае, если в шаблонах локализации является вертикальная черта “|”, то внутри компонентов это “:”.

Для того, что linter не ругался, необходимо в файл библиотеки или приложения, в файл tsconfig.lib.json добавлять тип глобальной переменной:

Множественное число с локализацией является простой задачей.

Разберем компонент, в котором выводится количество товаров в корзине.

Шаблон, отвечающий за вывод количества товаров будет следующим:

<div i18n="Cart info|Cart count">
{cartProducts | cartTotalCount, plural, =0 {no products} =1 {1 product} other { {{ cartProducts | cartTotalCount }} products} } in the cart.
</div>

Как видно из примера, для английского мы имеем пример, где корректными формами будут 1 product и 2 products (3 products, 4 products, …).

В русском же мы имеем 3 варианта: 1 товар, 2 товара, 3 товара, 4 товара и 5 товаров, и т.д.

Правила для русского будут определяться именно в файле локализации, а не в шаблоне.

Исходная фраза:

<source> <x id="ICU" equiv-text="{cartProducts | cartTotalCount, plural, =0 {no products} =1 {1 product} other {
{{ cartProducts | cartTotalCount }} products} }"/> in the cart. </source>

Будет заменена:

<target state="translated">
В корзине
<x id="ICU" equiv-text="{cartProducts | cartTotalCount, plural, =0 {no products} =1 {1 product} other { {{ cartProducts | cartTotalCount }} products} }"
/></target>

Сначала переводится все то, что не отвечает за количество, в частности фраза “В корзине”.

Затем отдельно переводится случай с множественными числами:

<source>{VAR_PLURAL, plural, =0 {no products} =1 {1 product} other {<x id="INTERPOLATION"/> products}}</source>

Трансформируется в:

<target state="translated">{VAR_PLURAL, plural, =0 {пусто} =1 {1 товар} =2 {2 товара} =3 {3 товара} =4 {4 товара} other {<x id="INTERPOLATION"/> товаров}}</target>

Локализация страниц

Иногда есть потребность в переводе больших частей текста, например, договоров, оферты, индивидуальных условий и других документов. Что делать в этом случае?

Самым худшим решением будет создать на каждый абзац i18n, и перевести с помощью пакета локализации.

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

Разберем страницу условий продажи в приложении.

Создадим новую библиотеку для условий продажи:

nx g lib russian/terms/page

Как видно из команды, страница с условиями располагается в папке russian, что говорит о том, что данная страница должна использоваться только в России и нигде более.

Добавим компонент и соответствующий текст:

nx g с terms-page --project=russian-terms-page

Как видно из примера, компонент не использует инструменты локализации, а просто выводит статичный текст.

Ссылки

Оглавление

Предыдущая статья — Страницы ошибок.

Следующая статья — Настройка SEO.

Все исходники находятся на github, в репозитории:

Для того, чтобы посмотреть состояние проекта на момент написания статьи, нужно выбрать соответствующий тег — article.

Подписывайтесь на блог, чтобы не пропустить новые статьи про Angular, и веб-разработку. Medium | Telegram| VK |Tw| Ln

--

--

Aleksandr Serenko
F.A.F.N.U.R

Senior Front-end Developer, Angular evangelist, Nx apologist, NodeJS warlock