应用程序国际化和本地化,第3部分:技术挑战

照片作者迈克尔·季季季奇在…上不鞭笞

在这个由四部分组成的教程的第三部分中,学习如何解决语言的各种考虑因素和细微差别。这包括多元化,可访问性,格式化日期和数字,等等!

查看本系列的第2部分在这里.

让Unicode带路

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

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

Unicode联盟考虑的另一个问题是如何通过使用字形群,以便确定一组字符可以拆分的适当位置,同时仍保留有意义的文本块。这可能是一篇完整的文章,但可以肯定地说String.slice(…)如果出于任何原因需要手动操作字符串,则这将是不够的。

特定于区域设置的格式

货币格式的差异

当然,这不仅适用于货币,也适用于类似的事物百分比,用于表示两个用户之间的匹配百分比。以下是百分比如何188bet金宝搏官网本地化的示例:

百分比格式的差异

这些API功能强大,是最新浏览器(以及最新节点版本)的一部分。它们还提供了格式化数字的方法,例如在某些地区使用不同的数字集,本地化距离/速度/公制测量,等等。

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

利用intlapi的示例

还值得一提的是,在像这样对值进行本地化时,另一件经常被忽略的事情是,“按字母顺序排序”的概念会随着使用的语言而改变,因为在给定语言中使用的字形会改变,并且简单的.sort(…)默认情况下肯定不会考虑区域设置。幸运的是,CLDR再次将我们包括在内提供整理规则因此,排序也可以本地化国际API还公开了折叠器为此目的。

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

可达性

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

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

对于开发者来说,这意味着我们还应该确保我们为确保应用程序可访问所做的所有工作都应该与我们为实现应用程序国际化所做的工作直接挂钩。如果我们通过中高音咏叹调-*属性等等,我们还应该确保它们也被正确地翻译,这是很容易被忽略的。

此外,我们还应该把重点放在通过易访问性工具和用户可以采取的手势解析文档,确保这些也已正确本地化。确保文档被正确标记(例如,使用HTML)是很重要的属性),以便其他软件(如辅助访问工具)可以知道相关文档使用的是某种语言。至于手势,想象一下习惯了从右到左的语言,如阿拉伯语或希伯来语:如何正确定位“向左滑动”和“向右滑动”等功能?当然,这些都是从西方的经验中诞生的,而且考虑到它在最初设计的布局和脚本中会如何保持是很有意思的。

API设计、重新设计?

在应用程序中处理可本地化内容时,内容协商与合作特别是accept languages标头的角色这对于了解用户向您的web服务器或服务发出请求时希望接收的区域设置至关重要。尽管这是HTTP内容协商的一个特定功能,但是可以抽象地跨各种协议应用统一方式的概念,即在整个系统中传播用户的区域设置代码。当然,还有其他表示语言偏好的方法,否则最常见的可能是使用URL查询参数,例如www.somesite.com/home?lang=en。当然,在更隐式的基于头的方法和更显式的基于参数的方法之间存在权衡,并且应该考虑应用程序中的其他因素,例如请求/响应缓存机制。

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

获取“api/菜单/比萨配料”-->[“奶酪”、“意大利香肠”、“素食”]
发布“api/my_pizza/add_Toping”->(“辣香肠”)-->{success:true}

如果我们想支持这些返回的数据点的翻译/披萨馅料这样我们的用户就可以看到文本的本地化版本,端点在/添加浇头可能没有能力理解除[“奶酪”、“意大利香肠”、“素食”],因此,如果我们将这些值翻译成另一种语言的等效值,我们的客户端将发送虚假请求。将其与以下内容进行对比:

获取“api/菜单/比萨配料”-->[
{id:1220,名字:“Cheese”},
{id:1234,名字:“意大利香肠”},
{id:1002,名字:“素食者”}
]
发布“api/my_pizza/add_Toping”->(1234)-->{success:true}

通过以更规范化的格式构造API和服务的输入和输出,我们现在可以轻松地转换名称田野/披萨馅料有效负载,无需担心通过添加对其他语言的支持而破坏我们的软件。这对一些人来说似乎是显而易见的,但我要强调的是,在高速情况下,很容易忽略一些您目前没有设计的东西(事后诸葛亮是20:20),因此,可以理解的是,对于最初不希望支持本地化等功能的软件,为了简单起见,工程师可以很容易地选择前一个示例。

最后,值得花点时间分析当前应用程序的体系结构,并质疑它是否必要(以及随后是否可能)支持多种语言和地区。如果您的服务需要适应特定地区的特定语言、文化或法律要求,那么这种可变性如何适应您的API和服务的当前体系结构。可能需要专门用于determinin任务的服务g给定区域或区域的特征映射。

样式、主题、资源

天真的案例转换会导致误译

好吧,现在我们实际上误译了两条土耳其语的信息,因为我的名字不是土耳其语NİCK这个城市的名字不是CİNCİNATTİ,而不考虑标志符号应该成为İ当用土耳其语大写时。

当涉及到软件的样式时,要记住的另一个重要部分是确保我们的组件可以根据其内容轻松扩展和增长考虑到一个仅用几个单词或字母的短语在翻译成其他语言时可以很容易地加倍或三倍(反之亦然)。。这当然是设计问题的一部分,但我们也有责任确保我们的设计中考虑了可变长度字符串,以便翻译不会导致我们的组件以任何方式剪裁或断裂。

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

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

慎用开始终止价值观左边正当这些值将允许我们的样式表轻松地跨语言扩展从左到右脚本和从右向左剧本!整洁的

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

一个有趣的讨论点是OkCupid目前对本地化资产的态度。也许您的应用程序使用了大量静态图像188bet金宝搏官网。通常,我们会发现直接将文本烘焙到这些图像中,这使我们的开发人员不必担心这些资产的样式,我们只需将它们放入其中,它们看起来就正确了。但是,现在这意味着这些资产也需要本地化,如果您计划将其扩展到几项(更不用说十个了)对于语言而言,基于特定语言环境创建/导出/导入这些资产的繁琐工作对于设计师和开发人员来说将线性增加。正是出于这个原因,我们决定尝试删除资产中的嵌入式语言,并使用能够在多种语言和文化中工作的更中性的资产。下面是一个非常简单的例子来说明这一点:

基于文本的资源与基于插图的资源和本机文本

左边用红色标出的元素实际上是从CDN加载的图像资产、文本和所有内容。在右侧的绿色中,图像已与文本分离,因此文本内容和图像资产可以独立于React/CSS内呈现,而无需为每种语言向CDN部署大量图像。

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

它真的是常数吗?

嗯,最终的结果是,在导入文件时应用了转换,因为它被定义为一个常量,因此在初始评估之后,它从未被重新评估过(在本例中,它还没有执行正确评估的最新数据)。

对我们来说,对代码库的各个部分进行共有是很常见的,这通常涉及到将原始数据类型(如字符串)作为常量声明一次,并在代码库中的整个文件和模块中重用它们。但是,当您使用React Providers和Context之类的工具跨组件或应用程序应用区域设置时,您的“常量”现在会根据应用程序的状态进行更改。这些真的是常数了吗?这当然是一个很小的区别,但突出了一个事实,即在国际化的背景下,像声明常量这样的小事需要重新考虑。

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

查看本系列的第4部分在这里.

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

阅读OkCupid工程团队每天联系数百万人的188bet金宝搏官网故事