web-dev-qa-db-ja.com

Angular Universal with i18n(サーバーサイドレンダリング)

Angular公式の国際化ツールをangularユニバーサルで使用しようとしています。これまでのところ、次の手順を使用してクライアント側のレンダリングを翻訳できます(これに感謝します)回答 https://stackoverflow.com/a/40930110/1110635 ):

テンプレートのドキュメントに記載されているように、「i18n」属性を追加します。

./src/+app/about/about.component.html:

<h1 i18n="H1 of the about component">About</h1>
...

それから私は走ります:

./node_modules/.bin/ng-xi18n

ベースmessages.xlfファイルを生成します。

次に、サポートするロケールごとにこのファイルを「locale」フォルダーに「messages。[locale] .xlf」としてコピーします。準備ができたら、エクスポートされたコンテンツの文字列を含むxlfファイルごとに「messages。[locale] .ts」を作成します。

./locale/messages.fr.ts:

// TRANSLATION_FR is only for "messages.fr.ts" of course.
// I would create a TRANSLATION_ES const inside "messages.es.ts" for spanish for example.
export const TRANSLATION_FR: string = `<?xml version="1.0" encoding="UTF-8" ?>
<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 id="004b222ff9ef9dd4771b777950ca1d0e4cd4348a" datatype="html">
        <source>About</source>
        <target>A propos</target>
        <note priority="1" from="description">H1 of the about component</note>
      </trans-unit>
    </body>
  </file>
</xliff>
`;

最後に、私のclient.tsファイルは次のようになります。

./src/client.ts:

[...]

// i18n
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID  } from '@angular/core';
import { TRANSLATION_FR } from '../locale/messages.fr';

import { MainModule } from './browser.module';

export const platformRef = platformUniversalDynamic();

// on document ready bootstrap Angular 2
export function main() {
  return platformRef.bootstrapModule(MainModule, {
      providers: [
          {provide: TRANSLATIONS, useValue: TRANSLATION_FR},
          {provide: TRANSLATIONS_FORMAT, useValue: "xlf"},
          {provide: LOCALE_ID, useValue: 'fr'}
      ]
  });
}
bootloader(main);

これは機能し、「クライアント側」アプリケーションを期待どおりに機能させます。 「About」は「Apropos」に置き換えられます。 [〜#〜] but [〜#〜]、なぜならangularユニバーサルは、テキストの表現を使用してサーバー側でページを事前レンダリングするクライアント側のブートストラップが完了するまで変換されません。

したがって、最初にページにアクセスすると、クライアント側が開始する前に約1秒間「About」が表示され、「A propos」。

解決策は明らかなようです。サーバー側で翻訳サービスを実行するだけです。しかし、私はそれをどのように行うのか分かりません。

私のserver.tsは次のようになります:

./src/server.ts

[...]

// i18n
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID  } from '@angular/core';
import { TRANSLATION_FR } from '../locale/messages.fr';

const app = express();
const ROOT = path.join(path.resolve(__dirname, '..', 'dist'));

// Express View
app.engine('.html', createEngine({
    ngModule: MainModule,
    providers: [
      /**
       * HERE IS THE IMPORTANT PART.
       * I tried to declare providers but it has no effect.
       */
      {provide: TRANSLATIONS, useValue: TRANSLATION_FR},
      {provide: TRANSLATIONS_FORMAT, useValue: "xlf"},
      {provide: LOCALE_ID, useValue: 'fr'}
    ]
}));
app.set('port', process.env.PORT || 3000);
app.set('views', ROOT);
app.set('view engine', 'html');
[...]

function ngApp(req, res) {
    res.render('index', {
      req,
      res,
      preboot: false,
      baseUrl: '/',
      requestUrl: req.originalUrl,
      originUrl: `http://localhost:${ app.get('port') }`
    });
}
app.get('*', ngApp);

// Server
let server = app.listen(app.get('port'), () => {
    console.log(`Listening on: http://localhost:${server.address().port}`);
});

クライアント側のようにbootstrapModuleメソッドに直接アクセスすることはできません。 「createEngine」パラメータオブジェクトのprovidersキーは、 originalserver.tsコード

何が足りないのですか?

29
Stnaire

解決策は、各言語のパッケージを事前にビルドし、プロキシにデフォルトとして機能するバンドルを検出させることです。

i8nのAngularドキュメント から:

AOTコンパイラとのマージAOT(Ahead-of-Time)コンパイラは、小さくて高速ですぐに実行できるアプリケーションパッケージを生成するビルドプロセスの一部です。

AOTコンパイラを使用して国際化する場合は、言語ごとに個別のアプリケーションパッケージを事前に構築し、サーバー側の言語検出またはurlパラメータのいずれかに基づいて適切なパッケージを提供する必要があります。

また、翻訳ファイルを使用するようにAOTコンパイラに指示する必要があります。これを行うには、ngserveまたはngbuildコマンドで次の3つのオプションを使用します。

--i18nFile:翻訳ファイルへのパス。 --i18nFormat:翻訳ファイルのフォーマット。 --locale:ロケールID。以下の例は、このガイドの前のセクションで作成されたフランス語ファイルを提供する方法を示しています。

ng build --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr
4
jornare