Angular Universal与i18n(服务器端渲染)

31

我尝试使用Angular官方的国际化工具与Angular Universal一起使用。到目前为止,我能够使用以下过程翻译客户端渲染(感谢这个答案https://dev59.com/aJrga4cB1Zd3GeqPrsM-#40930110):

我在我的模板中按照文档中所述添加了“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”被替换为“A propos”。但是,因为Angular Universal在服务器端使用Express预渲染页面,直到客户端启动完成后文本才会被翻译。

因此,当您第一次进入页面时,您将看到关于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方法。在原始的server.ts代码中,"createEngine"参数对象上的providers键已经存在。

我缺少了什么?


嗨,我正在尝试做这件事,但我不想使用*.ts文件进行翻译,但是这很困难。那么,你解决了吗? - IvanMoreno
不,我正在使用ng2-translate,因为我没有找到一种方法让本地模块在服务器端工作。但你可以按照我上面描述的方式做,并让你的构建工具(webpack或gulp或其他任何工具)从.xlf文件中创建.ts文件。 - Stnaire
2
它并没有真正解决这个问题,但您是否考虑过使用广泛采用的 nx-translate 模块?https://github.com/ngx-translate/core - Sonu Kapoor
在这条消息发布几周后,我已经转向使用Angular 1。部分原因是如此,但也因为当时从我的角度来看,Angular 2看起来还没有准备好投入生产。有太多的错误和缺失功能。我主要想使用Angular Universal来使用Angular 2,但它仍需要大量的工作。无论如何,感谢提供的链接,我将在下一个使用Angular 2/4的项目中进行研究。 - Stnaire
1个回答

5
一个解决方案是为每种语言预先构建软件包,并使用代理检测要作为默认值提供的捆绑包。
Angular 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

我认为这是正确的答案。解决方案就是使用适当的命令行选项构建应用程序的服务器端版本,以嵌入区域设置和翻译,基本上与为i18n支持构建浏览器捆绑包时完全相同的活动。请记住,您需要为每个区域设置生成一个Node应用程序(服务器和浏览器捆绑包),并使用代理或类似工具在它们之间切换,因此需要更高级的后端配置。 - Jed Richards
你有 Angular 11+ 的适当命令吗? - D.Pacheco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接