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

Posted

技术标签:

【中文标题】Angular Universal 与 i18n(服务器端渲染)【英文标题】:Angular Universal with i18n (Server Side Rendering) 【发布时间】:2017-04-27 05:48:43 【问题描述】:

我尝试将 Angular 官方国际化工具与 Angular Universal 结合使用。到目前为止,我可以使用以下过程翻译客户端渲染(感谢这个答案https://***.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 文件。

然后,我将这个文件作为“messages.[locale].xlf”复制到“locale”文件夹中的每个我想要支持的语言环境。 准备就绪后,我为每个包含导出内容字符串的 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);

这可以使“客户端”应用程序按预期工作。 “关于”替换为“A 提议”。 但是,因为 Angular Universal 使用 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中。

我错过了什么?

【问题讨论】:

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

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

来自Angular docs on i8n:

与 AOT 编译器合并 AOT(Ahead-of-Time)编译器是其中的一部分 生成小型、快速、可立即运行的构建过程 应用程序包。

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

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

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

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

【讨论】:

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

以上是关于Angular Universal 与 i18n(服务器端渲染)的主要内容,如果未能解决你的问题,请参考以下文章

集成 Angular + Nodejs + Spring Boot Java REST API 使 Angular Universal 工作

ngx-translate 与 i18n 的区别

为啥 Angular Universal 中的 res.render 需要这么长时间?

Angular Universal 学习笔记

Angular-universal - 生产问题

如何在 Angular 中将 i18n 模板用于 eslint?