【Angular】ngx-translate で多言語対応

アプリ開発

メモです。

スポンサーリンク

環境

  • Windows 11 Home 21H2 22000.556
  • Angular CLI: 13.2.6
  • Node: 16.13.1
  • Package Manager: npm 8.3.0
  • @ngx-translate/core 14.0.0
  • @ngx-translate/http-loader 7.0.0

準備

お試しということで、サンプルアプリ に ローカライゼーション を実装していきます。

toh-pt6

まず ZIP をダウンロードして、展開して、デバッグ実行ができる状態まで進めておきます。

Tour of Heroes

手順

インストール

次のコマンドで npmモジュール をインストールします。

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save

実装

「src\app\app.module.ts」を次のように修正します。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroSearchComponent } from './hero-search/hero-search.component';
import { MessagesComponent } from './messages/messages.component';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';

export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: createTranslateLoader,
        deps: [HttpClient]
      },
      defaultLanguage: 'en'
    }),

    // HttpClientInMemoryWebApiModule.forRoot(
    //   InMemoryDataService, { dataEncapsulation: false }
    // )
  ],
  declarations: [
    AppComponent,
    DashboardComponent,
    HeroesComponent,
    HeroDetailComponent,
    MessagesComponent,
    HeroSearchComponent
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule {
  constructor(translate: TranslateService) {
    translate.use('ja');
  }
}
app.module.ts

翻訳の設定

後は翻訳の設定を書いていくだけです。

「src\assets\i18n\」に、読み込む翻訳JSONを作成します。

今回は「ja.json」と「en.json」をそれぞれ作りました。

{
    "Dashboard": "ダッシュボード",
    "Heroes": "ヒーローズ",
    "Tour of Heroes": "ツアー・オブ・ヒーローズ",
    "Top Heroes": "上位ヒーローズ",
    "Hero Search": "ヒーロー検索"
}
ja.json

HTML内に翻訳を埋め込む場合は、次ように修正します。

<h1>{{title}}</h1>
<nav>
  <a routerLink="/dashboard" translate>{{'Dashboard'}}</a>
  <a routerLink="/heroes" translate>{{'Heroes'}}</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages>
app.component.html

TSから翻訳する場合は、次のように修正します。

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title: string = '';

  constructor(private translate: TranslateService) {
    this.translate.get('Tour of Heroes').subscribe((res: string) => {
      this.title = res;
    });
  }
}
app.component.ts

確認

上記修正をすると、次のように表示されます。

ツアー・オブ・ヒーローズ

キャッシュバスティング

翻訳JSONをキャッシュバスティングに対応させます。

「src\app\app.module.ts」を次のように修正することで、ページを開くと新たな翻訳JSONを取得するようになります。

export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
↓↓↓
export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json?cb=' + new Date().getTime());
}
'./assets/i18n/', '.json?cb=' + new Date().getTime()

実行してみるとこんな感じに、毎回取得しているのが分かると思います。

キャッシュバスティング

理想を言えばビルドやデプロイ毎で、キャッシュバスティングされればいいのですが、Angular にはその機能がないようです。

今後のアップデートに期待します。

躓いた点

./assets/i18n/en.json 404 Not Found

次のエラーが出て、翻訳JSONが取得できなかった。

ERROR {body: {…}, url: './assets/i18n/en.json', headers: HttpHeaders, status: 404, statusText: 'Not Found'}
ERROR {body: {…}, url: './assets/i18n/en.json', headers: HttpHeaders, status: 404, statusText: 'Not Found'}

解決

「src\app\app.module.ts」内で HttpClientInMemoryWebApiModule が読み込まれているとエラーになるみたいなので、コメントアウトしました。

HttpClientInMemoryWebApiModule をコメントアウト

Invalid version: “15.2-15.3”

次のエラーが出て、build ができなかった。

PS D:\Angular\toh-pt6> npm run build

> [email protected] build
> ng build

⠙ Generating browser application bundles (phase: setup)...Processing legacy "View Engine" libraries:
- angular-in-memory-web-api [module/esm5] (git+https://github.com/angular/in-memory-web-api.git)
Encourage the library authors to publish an Ivy distribution.
✔ Browser application bundle generation complete.
An unhandled exception occurred: Transform failed with 1 error:
error: Invalid version: "15.2-15.3"
See "C:\Users\*****\AppData\Local\Temp\ng-jJmYje\angular-errors.log" for further details.
error: Invalid version: "15.2-15.3"
[error] HookWebpackError: Transform failed with 1 error:
error: Invalid version: "15.2-15.3"
    at makeWebpackError (D:\Angular\toh-pt6\node_modules\webpack\lib\HookWebpackError.js:48:9)
    at D:\Angular\toh-pt6\node_modules\webpack\lib\Compilation.js:3055:12
    at eval (eval at create (D:\Angular\toh-pt6\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:98:1)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
-- inner error --
Error: Transform failed with 1 error:
error: Invalid version: "15.2-15.3"
    at failureErrorWithLog (D:\Angular\toh-pt6\node_modules\esbuild\lib\main.js:1557:15)
    at D:\Angular\toh-pt6\node_modules\esbuild\lib\main.js:1346:29
    at D:\Angular\toh-pt6\node_modules\esbuild\lib\main.js:637:9
    at handleIncomingPacket (D:\Angular\toh-pt6\node_modules\esbuild\lib\main.js:734:9)
    at Socket.readFromStdout (D:\Angular\toh-pt6\node_modules\esbuild\lib\main.js:604:7)
    at Socket.emit (node:events:390:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at Pipe.onStreamRead (node:internal/stream_base_commons:199:23)

解決

「@angular-devkit/build-angular」を 13.2.6 にアップデートしたらビルドできた。

npm update @angular-devkit/[email protected]
npm run build

参考

GitHub - ngx-translate/core: The internationalization (i18n) library for Angular
The internationalization (i18n) library for Angular - GitHub - ngx-translate/core: The internationalization (i18n) library for Angular
タイトルとURLをコピーしました