Интернационализация (i18n) в Angular 2
Hello baby!
Для маркера можно указывать дополнительные параметры которые отображаются в специализированных редакторах использующихся для перевода и дополняют переводимый текст служебной информацией призванной помочь переводчику. Это параметры передаются в формате «Значение|Описание» или только «Описание».
Hello baby!
Hello baby!
Возможно указать маркер и для текста который не окружен тегом. Для этого используется либо специальный пустой тег который не рендерится в финальный код.
I don't output any element
или специальный комментарий
I don't output any element either
Возможно так же делать перевод для аттрибутов тегов. Таких как alt, title, …
Plural
Окончание слов для множественного числа основано на правилах http://unisource.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules и http://cldr.unisource.org/index/cldr-spec/plural-rules в формате:
{wolves, plural, =0 {no wolves} =1 {one wolf} =2 {two wolves} other {a wolf pack}}
wolves — название переменной содержащей число
plural — название типа преобразования
=0 — возможное значение переменной, {no wolves} — отображаемый текст для значения данного значения
=1 — возможное значение переменной, {one wolf} — отображаемый текст для данного значения
=2 — возможное значение переменной, {two wolves} — отображаемый текст для данного значения
other — если значение переменной не задано, {a wolf pack} — отображаемый текст для данного значения
Возможные следующие варианты:
- =0
- =1
- =2
- few (…3–10 или 5–10, зависит от правил локалищации)
- other (дефолтное значение для всех неуказанных вариантов)
Select
Дает возможность выбирать значение на базе литеральной переменной:
The hero is {gender, select, m {male} f {female}}
gender — название переменной содержащей значение
select — название типа преобразования
m — возможное значение переменной, {male} — отображаемый текст для данного значения
f — возможное значение переменной, {female} — отображаемый текст для данного значения
ng-xi18n
Для извлечения строк из аппликации используется специальная утилита ng-xi18n входящая в состав angular-cli:
./node_modules/.bin/ng-xi18n -p src/tsconfig.json
Данная утилита ищет маркер i18n в шаблонах и копирует соответствующий текст формируя из него XML файл XLIFF формата (версии 1.2).
Так же поддерживается формат XML Message Bundle (XMB). Для этого нужно задать соответствующий ключ:
./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p src/tsconfig.json
Далее XML файл может быть отправлен переводчику который сможет редактировать его одним из специализированных редакторов. Полученный в итоге файл должен быть сохранен в папке i18n и содержать в своем названии язык локализации. Например в случае испанского языка, из исходного messages.xlf получится messages.es.xlf. Для каждого языка интерфейса должен быть создан отдельный файл.
Для того что бы файл с переводом мог быть использован Ангуларом необходимо добавить следующий код в main.ts:
// Указать нужные зависимости
import {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID} from '@angular/core';
// Задать ссылку на XML файл содержащий перевод
let current_language = 'ru';
import {RU_TRANS} from './i18n/messages.' + current_language;
Тут есть одно замечание. Если мы используем angular-cli, то в настоящее время мы не можем самостоятельно (официально) менять конфигурацию webpack и соответственно не можем добавить правило raw для файлов с расширением xlf позволяющее импортировать их напрямую. Поэтому пока приходится вставлять их в файл обертку (messages.ru.ts):
export const RU_TRANS = ` //Обратные кавычки в файле позволяют многострочный контент.
// сюда нужно скопировать содержимое XML файла messages.ru.xlf
`;
Конфигурируем в main.ts
platformBrowserDynamic().bootstrapModule(AppModule, {
providers: [
{provide: TRANSLATIONS, useValue: RU_TRANS},
{provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
{provide: LOCALE_ID, useValue: current_language}
]
});
К сожалению описанная выше интернализация имеет ряд подводных камней и ограничений из-за которых она может быть использована только в проектах с самым простым интерфейсом:
- при смене содержимого тега даже не относящегося к переводимому тексту при последующей экстракции может поменяться ID, что в свою очередь приводит к ошибкам компиляции приложения.
- экстракция происходит только из HTML файлов и невозможна для динамического контента (например каких либо списков или дропбоксов)
Это ставит крест на данном подходе для использования в большинстве проектов насыщенных динамическим контентом и использующие взаимосвязанные дропбоксы.
Работа по решению данных вопросов происходит и возможно в версиях Ангулар 4 или 5 интернационализация будет доведена до ума.
Поэтому пока единственным рабочим решением, по прежнему, остается ng2-translate.
ng2-translate
Является непрямым наследником хорошо известного модуля angular-translate.
Так же использует translate фильтр. Кроме того тексты с переводом хранятся в файлах JSON в том же формате как и в angular-translate.
Все это позволяет очень просто перенести шаблоны из ng1 в ng2. По сути все что требуется это сделать следующее:
Добавить зависимость в модуль аппликации в файл src/app/app.module.ts
import { HttpModule, Http } from '@angular/http';
import { TranslateModule, TranslateLoader, TranslateStaticLoader } from 'ng2-translate/ng2-translate';
@NgModule({
...
imports: [
...
HttpModule,
TranslateModule.forRoot({
provide: TranslateLoader,
// можно указать свой путь к папке i18n где находятся файлы с переводом
useFactory: (http: Http) => new TranslateStaticLoader(http, '/assets/i18n', '.json'),
deps: [Http]
})
],
providers: [],
bootstrap: [AppComponent]
})
Модуль сам подключает JSON файлы находящиеся в папке i18n. Поэтому импортировать вручную их не требуется.
Так же необходимо в корневом компоненте указать используемый язык
import {TranslateService} from 'ng2-translate';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
constructor(translate: TranslateService) {
// this language will be used as a fallback when a translation isn't found in the current language
translate.setDefaultLang('ru');
// the lang to use, if the lang isn't available, it will use the current loader to get them
translate.use('ru');
}
}
Собственно это все что необходимо. Модуль готов к работе.
Формат JSON файла очень простой (ключ: перевод):
{
"HELLO": "Привет"
}
далее в HTML можно соответственно использовать translate в следующих формах:
{{'HELLO' | translate}}
HELLO
Так же можно использовать TranslateService в компонентах. Полное API https://github.com/ngx-translate/core