国际化和本土化应用(第3部分):技术挑战

图片由迈克尔DziedzicUnsplash

在这四部分教程的第三部分,学习如何解决语言的各种注意事项和细微差别。这包括多元化,可访问性,格式化日期和数字,以及更多!

请参阅本系列的第2部分在这里

让Unicode引领潮流吧

2003年,统一码联盟发布了该项目的第一个主要版本公共区域设置数据存储库,简称为CLDR,这是一个庞大的XML数据集,包含许多国际化、本地化和翻译特定的数据和规则。从那时起,这个存储库就不断发展,在撰写本文时已经达到了主要的39版。有些事情由CLDR编码包括:

  • 语言名称的翻译
  • 领土和国家名称的翻译
  • 货币名称的翻译,包括单数/复数修改
  • 的翻译工作日时代,一天中的一段时间,完整和简短的形式
  • 时区的翻译和时区的示例城市(或类似的城市)
  • 日历字段的翻译
  • 格式化/解析日期或一天中的时间的模式
  • 用于编写语言的字符示例集
  • 格式化/解析数字的模式
  • 适应语言的单数、复数和序数短语的规则
  • language-adapted规则排序
  • 在传统数字系统中格式化数字的规则(如罗马数字亚美尼亚的数字等)。
  • 把数字拼成单词的规则
  • 规则音译之间的脚本。其中很大一部分是基于BGN / PCGN皈依天主教

利用这些数据就像下载和解析XML一样简单,但是,依赖标准化的、cldr支持的库或api通常是有用的,例如大多数现代浏览器和最新版本的Node提供的Intl api(或类似的特定于语言/平台的CLDR数据实现)。

Unicode联盟考虑的另一个问题是如何通过使用字形集群,以便在保留有意义的文本块的同时,确定一组字符可以被分割的适当位置。仅这一点就可以构成一篇完整的文章,但可以这么说String.slice(…)如果您出于某种原因需要手动操作字符串,这是不够的。

地区特定的格式

当然,每种语言环境都有处理特定数据格式化的独特方法。最常见的例子,也是你以前很可能遇到过的,是货币每种货币都使用一些特定的符号,这样的.最重要的是,根据每个地区表示数字的方式,不同地区之间的货币格式也不同,这是很常见的。例如,让我们用Intl。NumberFormatAPI检查的几个数字:

货币格式的差异

当然,这不仅适用于货币,还适用于诸如百分比, OkCupid上到处都用它来表示两个用户之间的匹188bet金宝搏官网配百分比。以下是百分比本地化的例子:

百分比格式的差异

这些api非常强大,是最新浏览器的一部分(在最新的Node版本中也有)。它们还提供了格式化数字的方法,例如为某些地区使用不同的数字集,本地化距离/速度/度量,等等。

我们还应该确保在应用程序中正确地本地化其他内容,如日期、时间、相对时间,甚至列表:

利用Intl api的例子

还值得一提的是,在本地化值时经常被忽视的另一件事是,“按字母顺序排序”的概念会根据使用的语言而改变,正如给定语言中使用的符号会改变和简单.sort(…)默认情况下肯定不会考虑locale。幸运的是,CLDR让我们再次提供校对规则排序也可以本地化。的Intlapi还公开排序器为这个目的。

当然,所有这些信息的最佳真实来源总是公共区域设置数据存储库的最新版本,并利用该数据源的任何API实现(例如Intlapi)是确保为给定语言环境提供正确数据的好方法。

可访问性

可访问性是许多应用程序的核心特性,这可能是软件领域中最重要的主题之一,特别是在过去几年。Mozilla将可访问性定义为

可访问性是指让你的网站能够被尽可能多的人使用。我们传统上认为这是针对残疾人的,但使网站可访问的做法也有利于其他群体,如使用移动设备的人,或那些网络连接缓慢的人。

如果我们从表面上看这个定义,那么我认为这里有一个扩展国际化应该被认为是可访问性的一个原则.我们正在努力向整个群体开放我们的软件,这些人以前对它有限制或没有有意义的访问权限,并使它对这些人具有可访问性和相关性。

对于开发者来说,这意味着我们还应该确保我们为确保应用程序的可访问性所做的所有工作应该与我们为应用程序的国际化所做的工作直接联系在一起。如果我们通过altaria - *属性之类的东西,我们也应该确保它们被正确地翻译,这是很容易被忽视的。

同时,我们应该关注通过可访问性工具解析我们的文档和我们的用户可以采取的手势,确保这些也正确地本地化。确保文档被正确标记(例如,使用HTML)是很重要的属性),以便其他软件(如易访问性辅助软件)可以知道该文档使用的是某种语言。至于手势,想象一下如果你习惯了从右到左的语言,比如阿拉伯语或希伯来语:你该如何正确定位“向左滑动”和“向右滑动”这样的功能呢?当然,这些都是源自西方经验的功能,而考虑如何将其应用于并非最初设计的布局和脚本是很有趣的。

API设计,重新设计?

本地化应该发生在哪里?

在应用程序中处理可本地化的内容时,内容协商,特别是accept-languages头的角色当用户向你的网络服务器或服务发出请求时,了解他们希望接收到的地点是非常重要的。尽管这是HTTP内容协商的一个特定特性,但可以抽象地跨各种协议应用具有统一方式的概念,即用户的语言环境代码可以在整个系统中传播。当然还有其他表示语言首选项的方法,最常见的方法可能是使用URL查询参数,例如www.somesite.com/home ? lang = en.当然,在更隐式的基于头部的方法和更显式的基于参数的方法之间存在权衡,应该考虑应用程序中的其他因素,如请求/响应缓存机制。

对于许多在设计时没有考虑到国际化的api来说,这可能是一个常见的陷阱,确保每个数据点(或至少它们的一些表示)都有一种方法来实现它是至关重要的唯一标识.在国际化服务或API时,直接使用字符串并不比使用单个id更好,因为它允许客户机和服务器代码删除对变量数据的依赖。例如,让我们抽象地勾勒出一组请求,我们希望在这些请求中获得一些数据,以便在后续的切线请求中使用:

获取“api/menu/pizza_toppings”——>[“Cheese”,“Pepperoni”,“Veggie”]
POST "api/my_pizza/add_topping"——> ("Pepperoni")——> {success: true}

考虑一下,如果我们想支持返回的这些数据点的转换/ pizza_toppings以便我们的用户可以看到文本的本地化版本,端点为/ add_topping可能不具备理解价值观的能力["奶酪”、“意大利辣香肠”、“素食”),所以如果我们把这些值转换成另一种语言的等价值,我们的客户就会发送虚假的请求。将其与以下内容进行对比:

获取“api/menu/pizza_toppings”——> [
{id: 1220, name: "Cheese"},
{id: 1234, name: "Pepperoni"},
{id: 1002, name: "Veggie"}

POST "api/my_pizza/add_topping"——>(1234)——> {success: true}

通过将api和服务的输入和输出结构成更规范化的格式,我们现在可以简单地转换的名字的字段/ pizza_toppings有效负载,不需要担心增加对其他语言的支持而破坏我们的软件。对于某些人来说,这似乎是显而易见的,但我要强调的是,在高速的情况下,很容易忽略一些你目前没有设计的内容(事后是二十20),所以可以理解,对于那些原本不希望支持本地化等特性的软件,工程师为了简单起见很容易选择前一个例子。

最后,值得花点时间分析当前应用程序的体系结构,并考虑是否有必要(以及可能)支持各种语言和地区。如果您的服务需要适应给定语言环境的给定语言、文化或法律需求,那么这种可变性如何适应您的api和服务的当前体系结构呢?可能需要专门用于确定给定地区或区域的特性映射的服务。

风格、主题化、资产

就像我之前提到的,资本化是某些语言的一个非常重要的句法特征。出于这个原因,我认为最好避免使用像CSS这样的代码首字母或Javascript的String.toUpperCase对将显示给用户的消息的大小写执行显式更改。几乎可以保证,这将在某些时候无意中破坏消息的翻译。让我们来看一个例子,例如,我们想要大写一个用户的名字和他们的位置:

Naïve case-transformation导致误译

好吧,现在我们用土耳其语翻译错了两条信息,因为我的名字不是NİCK而这个城市的名字却不是Cİ数控İ奈特İ,而不管这个象形文字应该成为İ在土耳其语中大写。

当涉及到我们的软件样式时,另一个需要记住的重要部分是确保我们的组件可以考虑到他们的内容,很容易扩展和增长.如果一个短语在英语中只有几个单词或字母,那么在翻译成其他语言时,它的长度很容易翻倍或三倍(反之亦然)。这当然是设计问题的一部分,但我们也有责任确保在我们的设计中考虑到可变长度的字符串,这样翻译不会导致我们的组件以任何方式剪辑或损坏。

除了为内容设计不同的预期长度外,我们还应该记住,我们的组件应该以一种能够在各种语言的脚本中使用的方式构建,而不管具体情况如何方向所选脚本的。以这个精心设计的CSS为例:

使您的样式适用于多种文档方向类型

小心使用开始结束价值观与正确的值将允许我们的样式表轻松地跨语言伸缩从左到右脚本和从右到左脚本!整洁!

也许另一个让你的本地化工作脱颖而出的领域是使用为不同地区定制主题.就像我之前提到的,颜色和象征都受文化和语言的影响,所以使用像ThemeProvider从风格的组件基于应用程序的活动区域设置管理主题可能是一种非常有趣的方式,可以让您的产品感觉更自然,在不同的地区和语言中更突出。例如,在西方地区,错误消息的颜色可以是红色,因为这种颜色通常与错误相关,但在一些东亚地区,这种颜色不经常与错误相关。这只是一个小例子,但是特定于区域设置的主题几乎是无限的。

讨论的一个有趣点是OkCupid目前对资产本土化的态度。188bet金宝搏官网也许您的应用程序使用了大量的静态图像。通常情况下,我们会发现这些图像中直接包含文本,这让我们开发人员不必担心这些资产的样式,我们只是将它们放入图像中,它们看起来就正确了.然而,现在这意味着这些资产太需要本地化,如果你计划扩展到一些(更别说十),基于特定地区创建/导出/导入这些资产的单调乏味将会线性增加设计师和开发人员。正因为如此,我们决定尝试在我们的资产中删除嵌入式语言,并使用更多可以在各种语言和文化中工作的中立资产。这里有一个非常简单的例子来说明这一点:

基于文本的资产vs.基于插图的资产和原生文本

左边用红色标出的元素实际上是从CDN加载的图像资源、文本和所有内容。右边的绿色部分,图像已经从文本中分离出来,这样文本内容和图像资源就可以在React / CSS中独立渲染,而不需要为每种语言部署大量的图像到CDN。

我们还创建了一些很酷的自定义文本呈现类,以本地化的方式处理样式。看看这个帖子在这里

它真的是一个常数吗?

我想通过提供一个我遇到的问题的小轶事,以及它在我的代码中引起的哲学/架构观点,来总结更具体的技术考虑。在某种程度上,我准备了一条要翻译的信息,但不明白为什么这条信息没有被正确翻译回来。

它最后变成了翻译应用文件导入时,因为它被定义为一个常数,所以它从来没有重新评估后的最初评估(在这种情况下,它还没有最新的数据进行正确的评价)。

对我们来说,将代码库的各个部分放在一起是很常见的,这通常涉及到接受原始数据类型(如字符串),并将它们声明为常量,然后在代码库中的文件和模块中重用它们。然而,当你使用React Providers和Context之类的东西跨组件或应用程序应用区域设置时,你的“常量”现在会根据应用程序的状态而变化。这些真的是常数吗?这当然是一个很小的差异,但突出了这样一个事实,即像声明常量这样微不足道的事情需要根据国际化重新考虑。

这也是编写软件的一个很好的小练习!解构您的工作并自问您所做的是否在上下文中有意义是一项很难掌握的技能,但在避免这种情况(以及一般情况下构建软件)方面肯定是有价值的。

请参阅本系列的第4部分在这里

188bet金宝搏官网OkCupid科技博客

阅读来自OkCupid工程团队的故事,每天连188bet金宝搏官网接着数百万人

尼克·布兰德

写的

软件工程师·NYC·https://nickbrandt.dev

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网

尼克·布兰德

写的

软件工程师·NYC·https://nickbrandt.dev

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网