ホームページ > 記事 > ウェブフロントエンド > Angular を使用して国際化を実装する方法 (詳細なチュートリアル)
この記事では主に Angular プロジェクトの国際化を実現する方法を紹介しますので、参考にしてください。
angular 公式 Web サイトに記載されているように、プロジェクトの国際化は、多面的な取り組み、継続的な献身と決意を必要とする困難な作業です。
この記事では、静的ファイル (html) の国際化と ts ファイルのコピーライティングを含む、Angular プロジェクトの国際化計画を紹介します。
Angular: 5.0
Angular Cl: 1.6.1 (1.5.x も利用可能)
NG-ZORRO: 0.6.8
i18n テンプレートの翻訳プロセスには 4 つの段階があります:
コンポーネント テンプレート内で翻訳する必要がある静的テキスト情報をマークします (つまり、i18n タグを追加します)。
Angular の i18n ツールは、タグ付けされた情報を業界標準の翻訳ソース ファイル (ng xi18n を使用した .xlf ファイルなど) に抽出します。
翻訳者はファイルを編集し、抽出されたテキスト情報をターゲット言語に翻訳して、ファイルを返します (翻訳者のアクセスが必要です。この記事では、xlf ファイルを使用して json 形式のファイル出力に変換し、最後にjson ファイルを xlf 形式ファイルに変換し直します)。
Angular コンパイラーは、翻訳されたファイルをインポートし、元の情報を翻訳されたテキストに置き換えて、アプリケーションの新しいターゲット言語バージョンを生成します。
翻訳された xlf ファイルを置き換えるだけで、サポートされている言語ごとに個別のプロジェクト バージョンを構築してデプロイできます。
テンプレートファイルで使用するにはどうすればよいですか?
i18n はいくつかの使い方を提供しており、単数と複数の変換方法も提供しています (私は個人的に使ったことがないので不便に感じます)。次に、別の html ファイルを使用して、いくつかの使用方法を紹介します。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Angular i18n</title> </head> <body> <h1 i18n="Site Header|An introduction header for i18n Project@@stTitle">Angular 国际化项目</h1> <p> <span i18n="@@agDescription">国际化是一项很具有挑战性,需要多方面的努力、持久的奉献和决心的任务。</span> <span class="delete" i18n-title="@@agDelete" title="删除"></span> </p> <p><ng-container i18n=@@agLetGo>让我们现在开始吧!</ng-container>朋友!</p> </body> </html>
上記のコードは、i18n を使用するいくつかの方法を示しています:
1. i18n 属性タグを使用します (説明的なコピーを追加できます。形式は次のようになります: title|description@@id、タイトルと説明は翻訳者が意味をよりよく理解するのに役立ちます)
静的タグに i18n タグを直接タグ付けすることもできます。例えば、
<span i18n="@@agDescription"></span>
によって生成される xlf (xml) フィールドの形式は
<trans-unit id="agDescription" datatype="html"> <source>国际化是一项很具有挑战性,需要多方面的努力、持久的奉献和决心的任务。</source> <context-group purpose="location"> <context context-type="sourcefile">xxx.ts</context> <context context-type="linenumber">linenum</context> </context-group> </trans-unit>
2 です。タイトルに i18n 属性を追加します
HTML タグの属性については、
<span class="delete" i18n-title="@@agDelete" title="删除"></span>などの i18n を追加することもできます
生成される xlf (xml) 形式は上記と同じです
3. 要素を作成せずにテキストを翻訳します
場合によっては、1 つの文の中に複数の文の区切りがある場合があります。span や label などの要素を追加すると、ページのレイアウトに重大な影響を与える可能性があります。このとき、ng-container を使用して、必要なコピーをラップすることができます。翻訳しました。
<p> <ng-container i18n=@@agLetGo>让我们现在开始吧!</ng-container>朋友! </p>
はページ上で
<p> <!----> LET'S GO朋友! </p>
* として表示されます。これはページのレイアウトには影響しません (特にスタイルが適用されている場合)。
ラベルを付けた後は、ng xi18n を実行するだけです。 xlf ファイル (通常は message.xlf) を自動的に作成します。カスタマイズする必要がある場合は、Angular CLI 公式 Web サイトにアクセスして表示できます。
XLFとJSON変換
xlf to jsonメソッド
私は個人的にxml2jsライブラリを使用して操作します。簡単なコードは次のとおりです:
const fs = require('fs'); xml2js = require('xml2js'); var parser = new xml2js.Parser(); fs.readFile(fileName, 'utf8', (err, data) => { parser.parseString(data, function (err, result) { // 读取新文件全部需要翻译的数据,并对比已翻译的进行取舍,具体转换成的格式结构可自行查看 result['xliff']['file'][0]['body'][0]['trans-unit'].forEach((item) => { var itemFormat = { "key" : item['$']['id'], "value": item['source'][0] }; // 执行相关操作,key-value形式是为了统一翻译文件结构,可按需定义 }) }); });
json to xlfメソッド
function backToXLF(translatedParams) { // 文件格式可自行参考angular.cn官网的例子 var xlfFormat = { "xliff": { "$" : { "version": "1.2", "xmlns" : "urn:oasis:names:tc:xliff:document:1.2" }, "file": [ { "$" : { "source-language": "en", "datatype" : "plaintext", "original" : "ng2.template" }, "body": [ { "trans-unit": [] } ] } ] } }; if (translatedParams instanceof Array) { // 获取原始名称 translatedParams.forEach((data) => { var tmp = { "$" : { "id" : data.key, "datatype": "html" }, "source": [i18nItemsOrigin[data.key]], // 这里的i18nItemsOrigin是json格式,属性名为key值,表示原始文案 "target": [data.value] }; // 数组,json项 xlfFormat['xliff']['file'][0]['body'][0]['trans-unit'].push(tmp); }); } var builder = new xml2js.Builder(); var xml = builder.buildObject(xlfFormat); return xml; }
このようにして、コピー情報は抽出され、翻訳されたファイルが変換されました。完了しました。次に、翻訳されたコピーをプロジェクトに適用する必要があります。
src ディレクトリに新しいロケール フォルダを作成し、変更されたディレクトリに翻訳されたdemo.en-US.xlf ファイルを保存します
app フォルダに新しい i18n-providers.ts を作成します
import { LOCALE_ID, MissingTranslationStrategy, StaticProvider, TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core'; import { CompilerConfig } from '@angular/compiler'; import { Observable } from 'rxjs/Observable'; import { LOCALE_LANGUAGE } from './app.config'; // 自行定义配置位置 export function getTranslationProviders(): Promise<StaticProvider[]> { // get the locale string from the document const locale = LOCALE_LANGUAGE.toString(); // return no providers const noProviders: StaticProvider[] = []; // no locale or zh-CN: no translation providers if (!locale || locale === 'zh-CN') { return Promise.resolve(noProviders); } // Ex: 'locale/demo.zh-MO.xlf` const translationFile = `./locale/demo.${locale}.xlf`; return getTranslationsWithSystemJs(translationFile) .then((translations: string) => [ { provide: TRANSLATIONS, useValue: translations }, { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, { provide: LOCALE_ID, useValue: locale }, { provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) } ]).catch(() => noProviders); // ignore if file not found } declare var System: any; // 获取locale文件 function getTranslationsWithSystemJs(file: string) { let text = ''; const fileRequest = new XMLHttpRequest(); fileRequest.open('GET', file, false); fileRequest.onerror = function (err) { console.log(err); }; fileRequest.onreadystatechange = function () { if (fileRequest.readyState === 4) { if (fileRequest.status === 200 || fileRequest.status === 0) { text = fileRequest.responseText; } } }; fileRequest.send(); const observable = Observable.of(text); const prom = observable.toPromise(); return prom; }
main .ts ファイルを
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { getTranslationProviders } from './app/i18n-providers'; if (environment.production) { enableProdMode(); } getTranslationProviders().then(providers => { const options = { providers }; platformBrowserDynamic().bootstrapModule(AppModule, options) .catch(err => console.log(err)); });
に変更します。ロケール ディレクトリを .angular-cli.json に追加して個別にパッケージ化することを忘れないでください。
このようにして、静的コピーの翻訳は基本的に完了しましたが、ts ファイル内のコピーやサードパーティのフレーム属性など、一部の動的コピーをどのように翻訳すればよいでしょうか?以下に、ts ファイルの動的コピー翻訳のソリューションと NG-ZORRO フレームワークを紹介します。
具体的なアイデア
Pipe経由でServiceメソッドを呼び出し、対応する一意のID値に従ってjsonオブジェクト内の翻訳結果を照合し、それを先頭に返しますレンダリングについては、NG-ZORRO フレームワークの国際実施計画を参照してください。
まず、3 層構造である json 翻訳オブジェクトの形式を定義します。これは、プロジェクトの構造に関連しており、統合を容易にするためです。後で i18n でフォーマットします。
{ "app": { "base": { "hello": "文件文案", "userCount": "一共%num%人" } } }
フォーマットが決定されましたので、サービス処理メソッドの定義を続けます
ここでは NG-ZORRO の国際化ソリューションが再利用されており、開発を簡素化できます。興味がある場合は、そのソース コードを参照してください。
*** TranslateService *** import { Injectable } from '@angular/core'; // 引入语言配置和国际化文件文案对象 import { LOCALE_LANGUAGE } from '../app.config'; import { enUS } from '../locales/demo.en-US'; import { zhCN } from '../locales/stream.zh-CN'; @Injectable() export class TranslateService { private _locale = LOCALE_LANGUAGE.toString() === 'zh-CN' ? zhCN : enUS; constructor() { } // path为app.base.hello格式的字符串,这里按json层级取匹配改变量 translate(path: string, data?: any): string { let content = this._getObjectPath(this._locale, path) as string; if (typeof content === 'string') { if (data) { Object.keys(data).forEach((key) => content = content.replace(new RegExp(`%${key}%`, 'g'), data[key])); } return content; } return path; } private _getObjectPath(obj: object, path: string): string | object { let res = obj; const paths = path.split('.'); const depth = paths.length; let index = 0; while (res && index < depth) { res = res[paths[index++]]; } return index === depth ? res : null; } }
このように、Pipe の Service の translation メソッドを呼び出すだけで済みます
*** NzTranslateLocalePipe *** import { Pipe, PipeTransform } from '@angular/core'; import { TranslateService } from '../services/translate.service'; @Pipe({ name: 'nzTranslateLocale' }) export class NzTranslateLocalePipe implements PipeTransform { constructor(private _locale: TranslateService) { } transform(path: string, keyValue?: object): string { return this._locale.translate(path, keyValue); } }
さて、処理ロジックは完全に終わりました。使い方を紹介しましょう
*** NG-ZORRO 控件 *** <nz-input [nzPlaceHolder]="'app.base.hello'|nzTranslateLocale"></nz-input> // 无动态参数 <nz-popconfirm [nzTitle]="'app.base.userCount'|nzTranslateLocale: {num:users.length}" ...> ... // 有动态参数 </nz-popconfirm> *** ts文件 *** export class AppComponent implements OnInit { demoTitle=''; users = ['Jack', 'Johnson', 'Lucy']; constructor(privete translateService: TranslateService) { } ngOnInit() { this.demoTitle = this.translateService.translate('app.base.hello'); } }
上記のプロセスは、基本的にほとんどの Angular プロジェクトを満たすことができます国際化の必要性。より複雑な国際化が必要な場合は、議論を歓迎します。
Angular の 5.0 への国際化は比較的簡単で、適切な場所に i18n をタグ付けするだけで、翻訳されたファイルの処理方法は人によって異なります。変換にはさまざまな方法が役立ちます (nodejs を使用したこの記事など)。
さらに複雑なのは、i18n タグを入力しても翻訳できないテキストです。NG-ZORRO の国際化ソリューションはこの欠点を補っており、組み合わせることでプロジェクトの国際化を簡単に完了できます。 国際化のための専任チームのサポートがないと翻訳は非常に難しく、繁体字中国語、マカオ繁体字中国語、台湾繁体字中国語など考慮すべき点が多く、文法も異なります。
リファレンスディレクトリ
Angularの国際化(i18n)オンラインサンプル
NG-ZORROロケール国際化
上記は、将来皆さんのお役に立てれば幸いです。
関連記事:
JQueryを使ったフォームバリデーションの実装方法、具体的に何をすればいいのか?
SpringMVCで投稿内の複数選択ボックスの値を取得する方法(コード例)
SpringMVC_jqueryでのjQuery+Checkboxの選択と値の受け渡しの例
以上がAngular を使用して国際化を実装する方法 (詳細なチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。