Angular 通用 i18n(服务器端渲染)

Angular Universal with i18n (Server Side Rendering)

我尝试使用 Angular 具有 angular 通用性的官方国际化工具。到目前为止,我能够使用以下过程翻译客户端呈现(感谢这个答案):

我添加 "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);

这有效并使 "client side" 应用程序按预期工作。 “关于”替换为“一个建议”。 但是,因为angular 在服务器端使用 express 通用预渲染页面,直到客户端引导完成后,文本才会被翻译。

因此,当您第一次进入该页面时,您会看到“About”大约 1 秒钟,然后客户端开始将其替换为“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 键已经存在于 original server.ts code.

我错过了什么?

一种解决方案是为每种语言预构建包,并让代理检测哪个包作为默认包。

来自Angular docs on i8n

Merge with the AOT compiler The AOT (Ahead-of-Time) compiler is part of a build process that produces a small, fast, ready-to-run application package.

When you internationalize with the AOT compiler, you must pre-build a separate application package for each language and serve the appropriate package based on either server-side language detection or url parameters.

You also need to instruct the AOT compiler to use your translation file. To do so, you use three options with the ng serve or ng build commands:

--i18nFile: the path to the translation file. --i18nFormat: the format of the translation file. --locale: the locale id. The example below shows how to serve the French language file created in previous sections of this guide:

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