はじめに
タイトルのユースケース例としては、複数のAngularアプリが存在しそれらには固有のアプリIDが振られておりそれぞれのアプリで文言のカスタマイズができるというケース。そこで、
- どのアプリにも共通して利用される文言
- アプリごとに設定された文言
この2種類の多言語化を必要としたとき「ngx-translate」を使っている場合は複数の多言語ファイルで管理したくなる。そのときどうしたら実現できるかを共有していく。
まずはインストール
$ npm install --save @ngx-translate/core @ngx-translate/http-loader
app.module.tsに設定を追加
※useFactory
の部分が無いが、ここはのちに追加する。
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
+ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
CoreModule,
CoreModule,
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useFactory: ,
+ deps: [HttpClient],
+ },
+ isolate: false,
+ }),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
複数の多言語ファイルをロードするため、独自のLoaderを実装
multi-translate-http-loader.ts
import { TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
/**
* 複数の多言語ファイルを読み込むためのカスタムTranslateHttpLoader
*/
class MultiTranslateHttpLoader implements TranslateLoader {
constructor(
private http: HttpClient,
public resources: { prefix: string; suffix: string }[] = [
{
prefix: '/assets/language/',
suffix: '.json',
},
]
) {}
public getTranslation(lang: string): Observable<object> {
return forkJoin(
this.resources.map(({ prefix, suffix }) => {
return this.http.get(`${prefix}${lang}${suffix}`);
})
).pipe(
map(response => {
return response.reduce((a, b) => {
return Object.assign(a, b);
});
})
);
}
}
export function createTranslateLoader(http: HttpClient) {
// TODO: ここでアプリIDをSessionStorageから取得する想定
const appId = 'app-01';
console.log('Translateのインスタンス生成');
return new MultiTranslateHttpLoader(http, [
// 複数アプリで共通の多言語ファイル
{ prefix: '/assets/language/common/', suffix: '.json' },
// アプリごとの多言語ファイル
{ prefix: `/assets/language/${appId}/`, suffix: '.json' },
]);
}
実装したLoaderをuseFactory
に追加
app.component.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
+ import { createTranslateLoader } from './core/translate/multi-translate-http-loader';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
CoreModule,
CoreModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
+ useFactory: createTranslateLoader,
deps: [HttpClient],
},
isolate: false,
}),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
app.component.ts
で言語の設定を書く
app.component.ts
import { Component } from '@angular/core';
+ import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
constructor(private translate: TranslateService) {
+ this.translate.setDefaultLang('en');
+ this.translate.use('en');
}
}
多言語ファイルを用意する
ディレクトリの構成はこんな感じ。
src
└ assets
└ language
├ app-01
│ └ en.json
├ app-02
│ └ en.json
└ common
└ en.json
app-01/en.json
{
"おはよう これはapp01だよ": "Good morning this is app01"
}
app-02/en.json
{
"こんにちは これはapp02だよ": "Hello It's app02"
}
common/en.json
{
"これは共通だお": "This is common"
}
ちなみに表示する画面はこうだ。
「これは共通だお」はどちらのアプリIDでも翻訳される、残りはアプリIDによって翻訳されるされないが切り替わることが期待される動作。
translate-example.component.html
<p translate>これは共通だお</p>
<p translate>おはよう これはapp01だよ</p>
<p translate>こんにちは これはapp02だよ</p>
確認してみる
アプリIDによって参照される翻訳ファイルが切り替わることが確認できる。