Инициализируйте и реализуйте приложение Angular i18n. Руководство по реализации многоязычных приложений на Angular с помощью Transloco! Включая ленивую загрузку перевода.

Таблица содержания

  • Обзор интернационализации (i18n) и локализации
  • Инициализация приложения Angular и установка пакетов
  • Конфигурации проекта
  • Перевод внутри шаблона
  • Перевод внутри TypeScript
  • Изменить активный язык
  • Ленивая загрузка файлов перевода

TL;DR

Вы можете перейти к реализованному примеру кода в этом репозитории GitHub и ознакомиться с рабочей демонстрацией здесь.

Интернационализация (i18n) и локализация

За последние десятилетия было создано множество приложений для пользователей по всему миру. Следовательно, ощущается необходимость реализации продуктов и услуг для пользователей на основе их языка и культуры. Мы называем этот процесс интернационализацией (i18n«И» — восемнадцать букв -«Н»). С другой стороны, локализация — это адаптация конкретного продукта к уникальному местному рынку. Angular локализация предоставляет нам несколько функций:

  • Извлечение текста для перевода на разные языки
  • Форматирование данных для определенной локали

Мы можем использовать интернационализацию Angular для:

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

Инициализация приложения Angular и установка пакетов

Во-первых, нам нужно приложение Angular! Я предполагаю, что вы установили Angular CLI на свой компьютер. Для инициализации приложения Angular с использованием Angular CLI мы могли бы ввести:

ng new <PROJECT_NAME>

В этой статье на Medium мы не будем вдаваться в подробности реализации приложения Angular. Вы можете найти этот репозиторий GitHub, чтобы увидеть полную реализацию проекта. Запустите приложение Angular с помощью команды ng serve. Теперь, когда у нас запущен проект Angular, давайте перейдем к деталям реализации i18n.

Для простоты мы будем использовать Transloco. Во-первых, нам нужно установить необходимые пакеты.

ng add @ngneat/transloco

После выполнения следующей команды вам нужно ответить на пару вопросов, например, используете ли вы Angular Universal в своем проекте и какие языки вы будете поддерживать. Ответив на них, вы можете найти новые файлы в своем проекте.

Вам необходимо ввести код ISO 639–1 вашего языка. Например, если вы хотите, чтобы ваше приложение включало английский, немецкий, испанский и персидский языки, вам нужно ввести: en, de, es, fa.

Вы можете найти файл конфигурации для transloco в файле transloco-root.module.ts. Вы можете изменить языки, которые вы поддерживаете, язык вашего приложения по умолчанию, а также хотите ли вы изменить свой язык во время выполнения. Список всех опций вы можете найти здесь.

import { HttpClient } from '@angular/common/http';
import {
  TRANSLOCO_LOADER,
  Translation,
  TranslocoLoader,
  TRANSLOCO_CONFIG,
  translocoConfig,
  TranslocoModule,
} from '@ngneat/transloco';
import { Injectable, isDevMode, NgModule } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class TranslocoHttpLoader implements TranslocoLoader {
  constructor(private http: HttpClient) {}

  getTranslation(lang: string) {
    return this.http.get<Translation>(`/assets/i18n/${lang}.json`);
  }
}

@NgModule({
  exports: [TranslocoModule],
  providers: [
    {
      provide: TRANSLOCO_CONFIG,
      useValue: translocoConfig({
        availableLangs: ['en', 'de', 'fa'],
        defaultLang: 'en',
        reRenderOnLangChange: true,
        prodMode: !isDevMode(),
      }),
    },
    { provide: TRANSLOCO_LOADER, useClass: TranslocoHttpLoader },
  ],
})
export class TranslocoRootModule {}

Теперь вам нужно импортировать TranslocoRootModule в корневой модуль, который, скорее всего, называется app.module.ts .

Ключевой вывод: чтобы работать с модулями и сервисами Angular, нам нужно импортировать в наш модуль модуль, спонсируемый ядром, для этого нам нужно импортироватьTranslocoRootModule один раз в наш app.module.ts и для все нашифункциональные модули, нам нужно импортировать TranslocoModule .

Перевод внутри шаблона

После выполнения команды ng add @ngneat/transloco вы найдете каталог с именем i18n в каталоге ресурсов со всеми указанными вами языками. Это основные языковые файлы. Вы можете использовать его на своей домашней странице или в шапке. Но вы также можете создать уникальный каталог для каждого модуля, а затем лениво загрузить их в свой модуль. Мы рассмотрим ленивую загрузку через секунду. Во-первых, давайте начнем работать с Transloco.

Использование структурной директивы

Вы можете использовать директивы *transloco в своем шаблоне. Но вам нужно либо импортировать translocoModule для функциональных модулей, либо для главной страницы translocoRootModule. Представьте, что мы хотим перевести наш заголовок. Нам нужно включить переведенный текст в файлы JSON в каталоге i18n.

en.json должен выглядеть следующим образом:

{
  "title": "Hello World!"
}

А для перевода на другой язык (скажем, немецкий) de.json должен быть примерно таким:

{
  "title": "Hallo Welt!"
}

Теперь в нашем шаблоне с помощью директивы мы можем продемонстрировать значение выбранного языка, как показано ниже:

<h1 *transloco="let t"> {{ t("title") }} </h1>

Но допустим, у нас может быть сложная структура JSON с вложенными ключевыми свойствами, как показано ниже:

// JSON does not support comments like this. 
// These comments are only for demonstrating.

// en.json
{
  "title": "Hello World!",
  "form": {
     "firstName": "First Name",
     "lastName": "Last Name"
    }
}

// de.json
{
  "title": "Hallo Welt!",
  "form": {
     "firstName": "Vorname",
     "lastName": "Nachname"
    }
}

Теперь у нас есть два варианта. Либо используйте вложенные элементы в функции t, либо пусть директива where ищет значение:

<!-- option 1 -->
<h1 *transloco="let t"> {{ t("form.firstName") }} </h1>

<!-- option 2-->
<h1 *transloco="let t; read:'form'"> {{ t("firstName") }} </h1>

Второй вариант более читаем.

Использование трубы

Другой подход заключается в использовании каналов, как показано ниже:

<h1>{{ 'title' | transloco }}</h1>

Перевод внутри TypeScript

После внедрения TranslocoService в наш компонент мы можем безопасно использовать его, как показано ниже:

export class AppComponent {
  constructor(private readonly translocoService: TranslocoService) {}

  ngOnInit() {
    this.translocoService.translate('title');
    this.translocoService.translate('form.firstName')
  }
}

Существуют и другие API-интерфейсы перевода, которые вы можете найти здесь. Но помните, что для правильной работы этих API необходимо убедиться, что файлы перевода загружены во время выполнения.

Изменить активный язык

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

import { Component } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';

@Component({
  selector: 'app-language-selector',
  template: `
    <div>
      <button
        *ngFor="let language of languagesList; index as i"
        (click)="changeLanguage(language.code)"
      >
        <img [src]="language.imgUrl" [alt]="language.name" />
        <span> {{ language.shorthand }} </span>
      </button>
    </div>
  `,
})
export class LanguageSelectorComponent {
  constructor(private translocoService: TranslocoService) {}
  public languagesList: 
    Array<Record<'imgUrl' | 'code' | 'name' | 'shorthand', string>> = [
    {
      imgUrl: '/assets/images/English.png',
      code: 'en',
      name: 'English',
      shorthand: 'ENG',
    },
    {
      imgUrl: '/assets/images/Deutsch.png',
      code: 'de',
      name: 'German',
      shorthand: 'GER',
    },
    {
      imgUrl: '/assets/images/Persian.png',
      code: 'fa',
      name: 'Persian',
      shorthand: 'PER',
    },
  ];
  public changeLanguage(languageCode: string): void {
    this.translocoService.setActiveLang(languageCode);
    languageCode === 'fa'
      ? (document.body.style.direction = 'rtl')
      : (document.body.style.direction = 'ltr');
  }
}

Как видите, мы реализовали три кнопки для смены языка приложения на английский, немецкий и персидский. Как только пользователь нажмет кнопку, мы вызовем метод setActiveLang для translocoService с кодом выбранного языка.
Обратите внимание, что такие языки, как персидский и арабский, пишутся справа налево. Поэтому не забудьте изменить направление вашего приложения с rtl на ltr, чтобы изменить направление тела.

Отложенная загрузка перевода

Загружать сразу все файлы перевода при инициализации вашего приложения — плохая идея, особенно если у вас тонны модулей. Помимо увеличения времени загрузки вашего приложения, работа над одним файлом перевода для всего приложения является сложной задачей. К счастью, мы можем лениво загружать файлы перевода в наши модули.
Допустим, у нас есть два модуля с именами pageOne и pageTwo. Для каждого модуля мы создадим каталог внутри нашего каталога i18n. Не забудьте заполнить каталоги одинаковым количеством файлов JSON для каждого языка. Теперь нам нужно только указать область действия для каждого модуля. Есть несколько способов сделать это.

<!-- pageOne module -->
<h1 *transloco="let t; scope:'pageOne'"> {{ t('title') }} </h1>
<!-- Pay attention to the scope above -->

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

Во-первых, в вашем модуле, куда вы импортировали translocoModule, вам нужно указать желаемую область видимости.

const routes: Routes = [
  {
    path: '',
    component: PageOneComponent
  }
];

@NgModule({
  declarations: [PageOneComponent],
  providers: [{ provide: TRANSLOCO_SCOPE, useValue: 'pageOne' }],
  imports: [RouterModule.forChild(routes), TranslocoModule]
})
export class PageOneModule {}

Теперь вы можете получить доступ к текущей области в вашем файле TypeScript, как показано ниже:

export class AppComponent {
  constructor(
    private translocoService: TranslocoService, 
    @Inject(TRANSLOCO_SCOPE) private scope
  ) {}

  ngOnInit() {
    this.translocoService.selectTranslate('title', params, this.scope)
      .subscribe(console.log);
  }
}

Внедрив TRANSLOCO_SCOPEв свой компонент, вы можете использовать текущую область действия модуля.

Окончательный результат

Полностью реализованную демонстрацию можно посмотреть здесь:

https://angular-multi-lingual.hmousavi.dev

Вы также можете проверить его репозиторий GitHub:

https://github.com/hossein13m/angular-multi-lingual

Поделись с друзьями! Хлопните 👏 максимум 50 раз.

Пожалуйста, не стесняйтесь делиться со мной своими мыслями и идеями. Вы можете связаться со мной в Твиттере или найти другой способ, посетив мое портфолио.



Узнайте больше от меня: