带有i18n的Angular Universal(服务器端渲染)

时间:2016-12-12 11:11:01

标签: angular internationalization webpack angular-universal

我尝试使用角度通用的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 文件。

然后我将此文件复制到我想要支持的每个语言环境中作为&#34; 消息。[locale] .xlf &#34;在&#34; locale&#34;夹。 准备好后,我会创建一个&#34; 消息。[locale] .ts &#34;对于包含其内容的导出字符串的每个xlf文件:

./ 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);

这有效并使客户端&#34;应用程序按预期工作。 &#34; 关于&#34;被&#34; A propos &#34;取代。 但是,因为角度通用预渲染服务器端的页面使用快递文本在客户端引导完成之前不会被翻译。

因此,当您第一次进入该页面时,您会看到&#34; 关于&#34;在客户端踢出之前大约1秒钟,用#34; A propos &#34;替换它。

解决方案似乎很明显,只需在服务器端运行翻译服务即可!但我不知道该怎么做。

我的 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 方法。 &#34; createEngine &#34;上的提供商键参数对象已经存在于original server.ts code

我错过了什么?

1 个答案:

答案 0 :(得分:3)

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

来自Angular docs on i8n

  

与AOT编译器合并AOT(Ahead-of-Time)编译器是其中的一部分   构建过程,产生一个小的,快速的,可立即运行的   申请包。

     

使用AOT编译器进行国际化时,必须预先构建一个   为每种语言单独的应用程序包并提供服务   基于服务器端语言检测的适当包或   网址参数。

     

您还需要指示AOT编译器使用您的翻译   文件。为此,您可以使用ng serve或ng build三个选项   命令:

     

- i18nFile:转换文件的路径。   --i18nFormat:转换文件的格式。   --locale:区域设置ID。下面的示例显示了如何提供本指南前面部分中创建的法语文件:

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