为Angular添加多语言支持

Add multi-language support to Angular

在本教程中,我们将向您介绍使您的应用程序可访问且用户友好的过程,以供世界各地的人们使用。世界上只有大约20%的人会说英语,因此提供其他语言选项可以改善您的用户体验并大大增加您的应用范围。我们将看看Angular的内置国际化工具,并向您展示如何正确使用它们。

我们创建了一个非常简单的演示应用程序来演示该过程。从这里克隆它然后按照安装说明进行操作。

启动应用程序以熟悉它。它只显示和更新具有不同上下文的随机数和值,例如货币,日期等。我们将介绍教程中使用的一些管道和功能。

01.支持语言的关键术语

如果您的网站只是英文版,那么您就错过了大量观众

在谈论翻译应用程序时,有两个词经常互换使用 - 国际化和本地化 - 然而,它们实际上意味着略有不同的东西。国际化是指准备应用程序以支持不同语言的过程。相比之下,本地化是指将您的应用程序实际转换为所需语言的过程。基本上国际化是每个应用程序执行一次的事情,本地化每个地区发生一次 - 至少这是计划。

这些术语在缩短版本中也可能是熟悉的:i18n(其中18是国际化的第一个'i'和最后'n'之间的字母数)和l10n(其中10是'i'之间的字母数和本地化的'n'。

02.什么是本地化?

目前全世界有超过6000种语言使用,其中大部分仅由极少数人使用。然而,即使我们只专注于前三种语言 - 普通话,西班牙语和英语 - 日期格式,语法结构,复数和数字格式也会有显着差异。

如果我们包括第五种使用最广泛的语言 - 阿拉伯语 - 我们会遇到另一种差异;阿拉伯语是一个从右到左(RTL)的脚本,这意味着UI也必须进行镜像。

因此,在本地化期间,我们必须考虑语法,布局和格式差异,当然,我们还必须更改文本本身。 Angular可以帮助解决大部分问题,但您仍需要手动翻译文本。

03. Angular中的语言环境

我们需要为我们需要支持的每个语言环境进行本地化。区域设置是指上述考虑因素的一般偏好集合,这些偏好倾向于在世界的一个区域内共享,通常是一个国家。每个语言环境都由Unicode语言环境标识符表示,该标识符指定语言代码和语言环境扩展。

Angular的默认语言环境是“en-US”,这是在“US”(美国)地区使用的语言代码“en”(英语)。本地化为“en-US”的应用程序与“en-GB”本地化的应用程序略有不同,后者在英国使用英语。例如,在美国,日期(莫名其妙)格式为mm / dd / yyyy,而在英国,我们使用更明智的dd / mm / yyyy方法。这种微小的差异可能导致理解上的重大错误。

为了让事情变得有趣,让我们将我们的演示应用程序本地化为伊拉克语,即“ar-IQ”和英语,即“en-GB”。这次我们将使用英语作为默认值。

04.构建配置

我们的演示项目是使用Angular CLI创建的,其中包括一些有用的工具。我们将为此项目使用Ahead-of-Time(AOT)编译器,因此我们需要对CLI的配置文件进行一些更改:'angular.json'。如果您想使用实时(JIT),则需要稍微不同地配置。

通过AOT构建,您可以获得一个小型,更快的渲染即用型应用程序,无需异步请求即可获取模板和样式表等内容。因此,您必须为每个区域设置创建构建,并使用URL或某种服务器端语言检测逻辑来提供适当的构建。最简单的方法是为每个区域设置创建一个目录,例如www.example.com/en-GB和www.example.com/ar-IQ。权衡的是你无法即时切换语言,但实际上这不太可能是真实用户所需要的。

首先,我们需要为我们的阿拉伯语语言环境添加构建配置。在JSON文件中查找“architect.build.configurations”对象。添加以下块以定义语言环境的配置:

“ar-IQ”:{“baseHref”:“/ ar-IQ /”,“deployUrl”:“/ ar-IQ /”,“outputPath”:“dist / angular-i18n-demo / ar-IQ”,“ i18nFile“:”src / locale / messages.ar -IQ.xlf“,”i18nFormat“:”xlf“,”i18nLocale“:”ar-IQ“

此配置告诉Angular在何处输出已编译的构建以及要使用的转换文件和格式。它还设置区域设置并告诉Angular应用程序将部署到哪个目录。

我们还需要修改'architect.build.options'中的默认选项以使用'en-GB'语言环境。设置以下属性,如图所示。请注意,我们在这里全面启用AOT,因此它将用于生产和开发构建:

“outputPath”:“dist / angular-i18n-demo / en-GB”,“i18nLocale”:“en-GB”,“deployUrl”:“/ en-GB /”,“baseHref”:“/ en-GB / “,”“aot”:是的

Angular支持许多语言环境。确保使用'i18nLocale'属性的正确值。您可以看到完整列表这里

在幕后,上述配置只需从这些区域设置首选项文件中加载和读取。

05.服务配置

除了配置构建输出之外,我们还需要为“ng serve”命令设置开发配置。这更简单,因为我们可以简单地引用我们刚刚添加的构建配置。在'angular.json'中,将以下块添加到'architect.serve.configurations':

“ar-IQ”:{“browserTarget”:“angular-i18n- demo:build:ar-IQ”,“servePath”:“/ ar-IQ /”}

这里我们使用'browserTarget'属性引用构建配置选项,我们也设置'servePath'。在我们提供或构建阿拉伯语应用程序之前,我们需要创建上面“i18nFile”属性中引用的翻译文件。 Angular CLI包括一个用于将标记文本提取到行业标准翻译源文件的工具。

我们稍后将在教程中更详细地介绍这些文件,但是现在我们只需要导出基本的空文件以允许我们编译。

我们将使用'ng xi18n'命令以及以下选项。这是我们唯一一次在“--out-file”文件名中包含区域设置ID:

$ ng xi18n --output-path locale --out-file messages.ar-IQ.xlf --i18n-locale ar-IQ

这应该在src / locale目录中创建一个文件。从现在开始,我们将始终输出名为'messages.xlf'的文件,并手动将其复制到名称中带有区域设置ID的版本上。这样做的原因是为了防止提取工具覆盖我们添加到文件中的任何现有翻译。

06.交换机配置

通过切换配置,您可以默认使用特定于位置的货币

此时我们现在可以编译项目并查看会发生什么,但我们需要告诉'ng Serve'命令使用哪种配置。首先让我们来看看英文版。这里没有变化,因为英语是默认值:

$ Ng服务

正如您所看到的,它看起来很像原始版本,它使用Angular的默认语言环境“en-US”。显着的区别是货币现在指定美元而不仅仅是美元。好的,现在让我们试试阿拉伯语版本。停止英文版并运行:

$ ng serve --configuration = ar-IQ

正如您所期望的那样,此版本存在更明显的差异,特别是日期现在用阿拉伯语编写。 Angular可以这样做,因为某些事物的名称(例如月和日)来自集合列表,并且最终它们与已知数字相关。然而,其他一切仍然是英文。

07.区域设置感知管道

仔细看看'app.component.html'的源代码,你会看到我们使用了许多不同的管道。以下Angular管道是区域设置感知的,这意味着它们根据当前区域设置调整其输出:'DatePipe','CurrencyPipe','DecimalPipe'和'PercentPipe'。

如果您仔细使用这些管道,Angular将为您处理大量的本地化工作。谨慎地说,我们意味着尽可能使用可用的预定义选项。一个很好的例子是我们之前提到的美国与英国日期格式。如果您在英国并且想要使用(合理的)日 - 月 - 年格式显示日期,您可能会因为发现预定义的“短日期”选项呈现为m / d / yy而感到沮丧(例如。10/9/18)并试图硬编码你想要的格式,如下所示:

{{myDate |日期:'dd / MM / y'}}

但我们现在知道我们得到m / d / yy格式,因为Angular默认使用'en-US'语言环境。因此,我们应该使用''shortDate''选项并将我们的应用本地化为'en-GB',而不是硬编码格式。

{{myDate |日期:'shortDate'}}

它需要更多的努力,但随后我们可以添加区域设置到我们内心的内容,并始终具有用户友好的日期格式。

08.覆盖预定义的选项

不幸的是,似乎没有一种简单的内置方式来覆盖预定义的格式。例如,您不能仅仅决定将''shortDate''格式设置为dd / mm / yyyy而不是dd / mm / y,因为无法在运行时修改格式。此外,您无法添加自己的预定义选项。

对于这些边缘情况,您可以创建一个自定义日期管道,它包装Angular“DatePipe”并处理每个区域设置的任何自定义格式。它无法识别的任何内容都会传递给内置的“DatePipe”。

09. CurrencyPipe

现成的'CurrencyPipe'将数字格式化为美元,修剪为小数点后两位,并添加区域设置首选项中定义的分组。

您会注意到,在我们的区域设置中,货币始终为美元。当您使用'en-GB'语言环境时,它不会神奇地切换到Sterling(GBP)。原因是10英镑与10美元不同,因此您必须明确指定您的数字所指的货币。

让我们更新'app.component.html'以使用整个GBP。指定货币代码时,必须使用ISO 4217标准中的正确值(在线可用列表)。

通过添加':'GBP''修改两个货币管道,如下所示:

{{value $ |异步|货币:'GBP'}}

你会开始看到£符号而不是US $。

请记住,它没有做任何巧妙的事情,例如如果您更改货币,则自动将USD转换为GBP中的等值 - 它只是更改它使用的符号。

10.翻译工作流程

好的,所以我们已经配置了两个语言环境,而Angular正在帮我们开箱即用,但文本仍然是英文的。令人遗憾的是,Angular无法自动翻译,但它可以帮助我们完成部分工作流程。这是必须发生的事情:

  • 标记所有组件中的静态文本以进行翻译
  • 导出包含此静态文本的翻译文件
  • 修改翻译文件并添加相关翻译
  • 将翻译的翻译文件合并到应用程序中

Angular帮助我们完成了第2步和第4步,但作为开发人员,我们需要手动执行第1步。步骤3通常由翻译专业人员或机构完成,使用特殊软件来阅读和更新翻译文件。

11.轴细节

为此,我们必须为包含要翻译的固定文本的每个元素添加一个特殊属性。要清楚内容是否来自API,那么这不是固定文本,您需要在API中对其进行本地化。只有在文本直接写入源代码中的HTML模板时才需要添加属性。这里的一个关键点是你应该尝试让你的TypeScript文件与语言环境无关 - 换句话说,避免在组件逻辑中放置任何需要翻译的文本,并将其全部保存在模板中。否则,提取工具将无法提取它。无论如何,将生活和代码中的问题分开是一种很好的做法。

让我们打开'app.component.html'并从'当前值'标题开始。只需将'i18n'属性添加到直接包含文本的元素即可。

当前值

重要的是要理解这只是一个“愚蠢”的自定义属性。它不是一个在运行时触发任何东西的Angular指令,实际上,编译器在转换后将其删除。

无论如何,让我们看看当我们再次运行提取工具来重新生成翻译文件时会发生什么。请记住'--out-file'现在只是'messages.xlf':

$ ng xi18n --output-path locale --out-file messages.xlf --i18n-locale ar-IQ

打开输出XLF文件,您应该看到一个新的翻译单元块,看起来像这样,带有一些额外的上下文信息:

当前值

太棒了,这意味着该工具选择了'i18n'属性。该长ID由工具生成,除非文本发生变化,否则将保持不变。如果您有多个完全相同文本的实例,则它们都将获得相同的ID。不要编辑此ID!

如果您愿意,可以在“i18n”属性中指定自定义ID。如果您这样做,即使文本发生更改,ID也将保持不变,因此您需要确保整个应用中没有任何ID冲突。使用'@@'前缀设置自定义ID。这里的ID将成为“标题”:

当前值

12.添加一些上下文

为了确保翻译能够提供准确的翻译,他们通常需要知道文本正在使用的上下文。“i18n”属性允许我们定义描述和帮助翻译者的意义。格式如下:

文本

让我们用含义和描述更新我们的标题:

当前值

这应该给翻译者足够的背景以提供准确的翻译。重新生成转换文件,您应该看到已输出这些值。值得注意的是,如果您不使用自定义ID,则生成的ID会考虑含义和文本。因此,相同的文本,但具有不同的含义,将获得不同的ID。但是,该描述对ID没有影响。

13.带变量的文本

让我们进入介绍部分。第一段包含文本和将在运行时插值的变量。我们该如何处理?

幸运的是,这很简单。我们需要再次向包含元素添加有意义的“i18n”属性。将其直接添加到段落元素:

再次运行提取工具,您将看到这个新的翻译单元: 昨天的收盘价是

了解如何在输出中详细说明变量插值。关于这一点的好处是它允许翻译者在必要时修改句子的语法结构,而不会破坏绑定。例如,可能存在一种语言,其中句子写得最好:X值是昨天的结束,即在开始时变量。

14.多元化

继续下一段,你会看到一些令人生畏的语法。这称为ICU消息格式,它允许您根据变量的值指定不同的文本块。

当值为零或不为1时,您可以使用此选项将“s”添加到英语单词中。例如,如果'seconds'是包含秒数的变量,我们可以使用此ICU复数表达式:

{{秒}} {秒,复数,一个{秒},其他{秒}}

哪个会输出:

  • 0秒
  • 1秒
  • 2秒

它似乎没有记录,但您也可以使用复数语法中的“AsyncPipe”来处理Observables。

在该示例中,“一个”和“另一个”是复数类别。有许多类别可供选择,但要注意!并非所有语言环境都支持所有类别,并且Angular不会告诉您是否尝试使用当前语言环境不支持的类别。很容易认为你做错了什么,因为“两个”类别不能在你的'en-GB'语言环境中工作,而是你看到了'其他'文本。令人费解的'en'(以及许多其他常用语言)仅支持'one'和'other',即使'zero'和'two'是显式值。

看看这个文件看看实际支持的是什么。

15.多个径向条形图

我们可以通过使用数字而不是类别来解决此限制。只需在值前加上'=':

{观察者,复数,= 0 {无人} = 1 {是一个人} = 2 {是两个人}其他{{{watchers}}人}}现在正在观看。

这已在演示应用中设置,我们只需要将'i18n'属性添加到包含的段落中:

再次运行提取工具以查看其外观。您会看到输出略有不同。它将创建两个翻译单元;一个用于ICU表达式本身,另一个用于将该表达式插入到原始字符串中。

16.选择表达式

如果要根据变量的值显示不同的文本,可以使用“select”ICU表达式,它与上面演示的“复数”语法非常相似。在我们的演示应用程序中,我们监视应用于值的更改并创建一个名为“trend $”的Observable流,根据更改是正数,负数还是零,输出“向上”,“向下”或“稳定”。

然后,我们将“select”ICU表达式连接起来,根据流值输出不同的字符串。在这里,您可以看到正在使用的“AsyncPipe”:

值{trend $ | async,select,up {increase} down {reduced} stable {does not change}}

这比使用'ngIf'或'ngSwitch'来操作DOM更简洁一些,而且它也可以很好地与提取工具一起使用。将'i18n'属性添加到包含元素:

重新生成翻译文件,您将看到该方法类似于复数输出,创建了两个翻译单元。一旦你习惯了它们,ICU表达式就非常方便,而且你可以嵌套它们来创建更复杂的输出。

17.添加翻译

Add multi-language support to Angular: markup

一旦您标记了需要翻译的所有文本,您就可以生成翻译文件

还有一个'i18n'属性要添加:

交易:{{transactions $ |异步|数字}}

现在我们已经标记了所有需要翻译的文本,我们可以最后一次生成翻译文件。创建后,将其重命名为“messages.ar-IQ.xlf”并替换之前的版本。这是我们要发送给翻译专业人员的文件,但出于本教程的目的,Google Translate将会站在这里!

打开XLF文件并复制每个' '元素,重命名' ”。不幸的是它可能非常不整洁,所以它可能有助于美化内容。

要检查我们是否已全部使用,请保存文件并使用阿拉伯语区域设置启动应用程序:

$ ng serve --configuration = ar-IQ

如果您在终端中看到这样的任何消息,则意味着您错过了一个:

Xliff解析错误中的错误:消息* Id *错过翻译(“

希望您不会有任何错误,您将能够在浏览器中看到该应用程序。我们还没有添加任何实际的阿拉伯语,所以它看起来不会有太大的不同。

18.谷歌翻译

Add multi-language support to Angular: Google Translate

Google翻译是一种为您的网站创建翻译的简便方法

让我们从简单的事情开始 - “当前价值”标题。谷歌翻译告诉我它应该是(阿拉伯语文本),所以更新'中的值' '元素:

当前值阿拉伯文在这里

到现在为止还挺好。现在让我们用插值做一个。这是“昨天的收盘价是......”(希望如此!):

阿拉伯文在这里

翻译时使用数字,以便可以看到插值的位置。请注意,当您在Google翻译中看到翻译结果时,它将显示为反转 - 即开头的数字 - 但是当您将其复制并粘贴到翻译文件中时,它将返回到原始订单。这种情况正在发生,因为阿拉伯语是一种RTL语言,所以脚本(几乎)完全镜像。 Google Translate通过向包含元素添加'dir =“rtl”'属性来实现此目的。我们将在下一步中学习如何执行此操作。其余的翻译可以在demo repo,'tutorial'分支中找到。

19.剧本方向

我们需要在应用程序中管理脚本方向,因为Angular不会自动为我们执行此操作。似乎也没有任何方法可以检测当前语言环境是LTR还是RTL语言,因此我们需要对其进行硬编码。如果Angular为此提供内置指令,那就太棒了。

打开'app.component.ts'。从''@ angular / core''导入'Inject','LOCALE_ID'和'HostBinding'。然后按如下方式设置'HostBinding'。这将为AppComponent添加一个'dir'属性,并将默认语言方向设置为'ltr':

@HostBinding('attr.dir')dir ='ltr';

接下来添加一个构造函数并注入'LOCALE_ID'。请记住,这是由我们的配置设置的,因为我们正在使用AOT。

构造函数(@Inject(LOCALE_ID)私有区域设置:字符串){}

最后将以下代码段添加到现有的“ngOnInit”方法中。在这里,我们检查'LOCALE_ID',即'ar-IQ',是否以'ar'开头,是否确实将方向改为'rtl'。

if(this.locale.startsWith('ar')){this.dir ='rtl'; }

如果您计划支持更多语言环境,那么您可能需要重构它以使其更具可伸缩性,但是,由于目前只使用大约10种RTL语言,因此这种方法不应过于笨拙。启动阿拉伯语应用程序,您现在应该看到UI已镜像 - £符号应该在右侧。

20.生产

最后一步是生成并检查我们的生产版本。首先,我们需要对'angular.json'配置进行另一次快速修改。

在'architect.build.configurations'中复制现有的生产对象并将其重命名为“”production-ar-IQ“'。然后将现有“ar-IQ”配置中的属性复制并粘贴到对象中,这样就可以同时拥有生产选项和“i18n”选项。

您还需要更新'architect.serve.configurations'。这次复制现有的“ar-IQ”对象并将其重命名为“production-ar-IQ”,并将'browserTarget'值更改为指向新的'production-ar-IQ'配置。

现在,您可以使用以下命令构建和提供生产阿拉伯语语言环境:

$ ng serve --configuration = production-ar-IQ

好的,我们完成了!我们已经成功地将我们的应用程序国际化,并将其本地化为“en-GB”和“ar-IQ”受众。 Angular使开发人员的过程非常简单,事实上,最难的是弄清楚翻译应该是什么 - 如果出现任何问题,请向任何阿拉伯语发言者道歉!

本文最初发表于创意网页设计杂志Web Designer的第281期。在这里购买问题281要么在这里订阅Web Designer

相关文章:



翻译字数超限