web-dev-qa-db-ja.com

コードでの翻訳のangular-i18n回避策?

エラーメッセージなどのコードでの変換をサポートするには、angular-i18nのAngular 6まで待つ必要があります。

(たとえばngx-translateの代わりに)angular-i18nを使用している場合、その間にコードで翻訳を処理するために何をしていますか?文字列が少ない場合は、言語コードとIDで翻訳を取得するメソッドを備えた単純な言語サービスが機能することに気付きますが、よりエレガントで「角度のある」ものに興味があります。

約束されたコード変換サポートがどのようになるかはわかりませんが、一時的な解決策は、稼働時にangular-i18n方式に簡単に変換できるのが理想的です。

この問題を処理するためにそこにいる人々は何をしていますか?何か案は?

7
Carbo

このポリフィルは、今のところ最善の方法のようです。

https://github.com/ngx-translate/i18n-polyfill

翻訳したいものはすべてi18n()関数でラップできます(このAPIはAngularの将来のリリースで保持される可能性があります-この回答の下部にある私のメモを参照してください)。

ポリフィルは主に、i18nを担当するAngularチームのメンバーであるOlivierCombeによって作成されています。


Angular 5の場合、インストール時にバージョン0.2.0が必要です。

npm install @ngx-translate/[email protected] --save

Angular 6の場合、最新バージョンを取得します-現在1.0.0:

npm install @ngx-translate/[email protected] --save

ポリフィルが機能するようになりましたJITとAOTの両方のコンパイル、Angular 5(Angular 6でも機能します)。単一の言語に翻訳するために必要なことは次のとおりです(これは、これを機能させるための良い方法です。後で複数の言語を機能させることができます。これについては後で説明します)。


app.module.ts

次のインポートをルートAngularモジュールに追加します。

import { TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core';
import { I18n } from '@ngx-translate/i18n-polyfill';

次の定数を追加し、ルートモジュールでプロバイダーを指定します。

// add this after import + export statements
// you need to specify the location for your translations file
// this is the translations file that will be used for translations in .ts files

const translations = require(`raw-loader!../locale/messages.fr.xlf`);

@NgModule({ ....

  providers:
  [
    I18n,
    {provide: TRANSLATIONS, useValue: translations},
    {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
    ...

AOTコンパイルの使用に関する注意:AOTコンパイルを使用してテンプレートを翻訳している場合、。tsファイル内のメッセージの翻訳は引き続き行われます実行時にJITコンパイルを使用して実行する(そのため、ビルドスクリプトでこれらを指定するのではなく、TRANSLATIONSTRANSLATIONS_FORMATを参照する必要があります)。


* .ts

翻訳を提供する.tsファイルに、次を追加します。

import { I18n } from '@ngx-translate/i18n-polyfill';

constructor(private i18n: I18n) {
    console.log(i18n("This is a test {{myVar}} !", {myVar: "^_^"}));
}

これは、翻訳したいメッセージに補間を含めることさえできることを示しています。

次のようにi18n定義を使用できます(つまり、翻訳の「ソース」ID、意味、説明を指定することを使用します)。

this.i18n({value: 'Some message', id: 'Some message id', meaning: 'Meaning of some message', description: 'Description of some message'})

それでもメッセージを抽出する必要があり、ngx-extractorツールを使用してこれを行うことができます。これはポリフィルをインストールするときに含まれ、npmスクリプト内での使用法の例を以下に追加しました。 ポリフィルページ のreadmeも参照してください。


多言語

複数の言語間の切り替えをサポートするには、翻訳用のファクトリプロバイダーが必要です。 ポリフィルページ のreadmeに詳細があります。ルートモジュールには次のようなものが必要です(またはAOTコンパイルの場合、localeFactoryの戻り値を、アプリのどのAOTコンパイル言語バリアントが現在実行されているかを検出する関数に置き換えます)。

  export function localeFactory(): string {
    return (window.clientInformation && window.clientInformation.language) || window.navigator.language;
  }

  providers:
  [
    {
      provide: TRANSLATIONS,
      useFactory: (locale) => {
        locale = locale || 'en'; // default to english if no locale provided
        return require(`raw-loader!../locale/messages.${locale}.xlf`);
      },
      deps: [LOCALE_ID]
    },
    {
      provide: LOCALE_ID,
      useFactory: localeFactory
    },

メッセージ抽出とxliffmerge

これらはすべて xliffmerge と互換性があります。これは、既存の翻訳を上書きせずに、追加したnew翻訳を自動的にマージするための優れたツールです。 Xliffmergeは、Google翻訳を使用して自動的に翻訳を実行することもできます(Google翻訳APIキーが必要です)。これを機能させるには、抽出とマージ/変換を次の順序で実行します。before実際のAOTビルドを実行します。

"extract-i18n-template-messages": "ng xi18n --outputPath=src/locale --i18n-format=xlf",
"extract-i18n-ts-messages": "ngx-extractor --input=\"src/**/*.ts\" --format=xlf --out-file=src/locale/messages.xlf",
"generate-new-translations": "xliffmerge --profile xliffmerge.json en fr es de zh"

サイトの特定の言語バージョンのAOTビルドは次のようになります。

"build:fr": "ng build --aot --output-path=dist/fr --base-href /fr/ --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr",

このポリフィルの現在のステータス:

これは主に、i18nを担当するAngularチームのメンバーであるOlivierCombeによって書かれています。この段階では、これは.tsファイル内の変数または文字列を変換するための「投機的」ポリフィルです。 Angularに組み込まれているAPIに置き換えられる可能性が高いため、後でアップグレードすることは合理的に管理できるはずです。 Githubページの免責事項は次のとおりです。

このライブラリは投機的なポリフィルであり、将来登場するAPIを置き換えることになっていることを意味します。 APIが異なる場合、可能かつ必要に応じて移行ツールが提供されます。

コード内の変数/文字列の翻訳のためのAngular6の今後のマイナーバージョンでのサポートについていくつかの議論がありました。

これは、Githubでの次のディスカッションからの、Olivier Combe(今年の3月から)からの引用です。

https://github.com/angular/angular/issues/11405

ランタイムi18nの最初のPRは、機能のテストに使用するhello worldデモアプリとともに、masterにマージされました。実行時に機能し、サービスがまだない場合でも、理論的にはコード変換をサポートします。今のところ、サポートはごくわずかです(静的文字列)。新しい機能の追加に取り組んでいます(来週抽出を機能させてから、プレースホルダーと変数を使用した動的文字列を作成します)。その後、コード翻訳のサービスを行います。新しい機能が終了するとすぐにマスターにマージされるので、新しいメジャーを待つ必要はありません。

11
Chris Halcrow

前回の回答から久しぶりで、簡単にできます。

.htmlが次のような場合

<!--at first we put all the translation in a hidden div-->
<div *ngIf="!yet" style="display: none">
    <span #t id="message1">Translation app</span>
    <span #t id="message2">Hola Mundo</span>
</div>

.tsには、単純なViewChildren、変数「yet」および変数「translation」があります。

  yet: boolean = false;
  translation:any={}
  @ViewChildren("t")
  set translations(values: QueryList<any>) {
    //when yet becomes true, values.length=0
    if (values.length) {
      values.forEach(c => {
        this.translation[c.nativeElement.id]=c.nativeElement.innerHTML
      })
      //it's necesary enclosed this.yet=true in a setTime to avoid 
      //the error expresion changes After Exec
      setTimeout(()=>{
        this.yet=true;
      })

    }
  }

その後、私たちはいくつかのように書くことができます

alert(this.translation['message1']);

更新同じ考え:コンポーネントの実装にはコンポーネントがあります

import { Component, QueryList, AfterViewInit, ContentChildren } from '@angular/core';
@Component({
    selector: 'ng-translation',
    template: `
    <div *ngIf="!yet" [style.display]="'none'">
    <ng-content></ng-content>
    </div>
    `
})
export class TranslationComponent implements AfterViewInit {
    @ContentChildren("t") translations: QueryList<any>
    data: any = {}
    yet: boolean = false;

    get(text: string) {
        return this.data[text];
    }
    ngAfterViewInit(): void {
        if (this.translations.length) {
            this.translations.forEach(c => {
                this.data[c.nativeElement.id] = c.nativeElement.innerHTML
            })
            setTimeout(() => {
                this.yet = true;
            })
        }
    }
}

その他のコンポーネント

<ng-translation #translation>
  <span #t id="message1">Translation app</span>
  <span #t id="message2">Hola Mundo</span>
</ng-translation>

@ViewChild("translation") translation:TranslationComponent
  click()
  {
    alert(this.translation.get('message1'));
  }

stackblitzの例

2
Eliseo

「奇妙な」回避策があります2つのコンポーネントを持つことができます

app-text.component.ts

import { Component} from '@angular/core';

@Component({
  selector: 'text',
  template:`<ng-content></ng-content>`
})
export class AppTextComponent{}

およびapp-translation.component.ts

import { Component, QueryList, ElementRef, ContentChildren } from '@angular/core';
import { AppTextComponent } from './app-text.component';

@Component({
  selector: 'app-translation',
  template: `<ng-content></ng-content>`
})
export class AppTranslationComponent{
  @ContentChildren(AppTextComponent, { read: ElementRef }) divs: QueryList<ElementRef>;
  constructor() { }

  translate(id: string): string {
    let nativeElement: any = this.divs.find(e => e.nativeElement.id == id);
    return nativeElement ? nativeElement.nativeElement.innerText : "";
  }
}

次に、コンポーネントに次のようなものを含めることができます

  <app-translation #translations style="visibility:collapsed">
    <text id="message1">Translation app</text>
    <text id="message2">Hola Mundo</text>
  </app-translation>

//In your code you can use a ViewChild and the function "traslate"
  @ViewChild('translations') t;

  alert(this.t.translate("message1"));
1
Eliseo

このパッケージを試すことができます ngx-dy-i18n

ネイティブソリューションをサポートします

0
AMINEMx