如何正确定位数字?


38

在前端应用程序中本地化数字时应注意哪些注意事项?

示例:在巴西葡萄牙语(pt-BR)中,我们用点分隔小数,用逗号分隔小数。在美国英语(en-US)中则相反。在pt-BR中,我们显示以千位分隔的数字,与en-US相同。但是,今天阅读有关印度英语(en-IN)的信息时,我偶然发现了这个宝石:

印度编号系统是数字分组的首选。用文字或口语表达时,小于100,000 / 100 000的数字与标准英语中的数字相同。在印度编号系统的子集中表示的数字包括100,000 / 100000以上。

https://zh.wikipedia.org/wiki/Indian_English#Numbering_system

意思是:

1000000 units in pt-BR are formatted 1.000.000
1000000 units in en-US are formatted 1,000,000
1000000 units in en-IN are formatted 10,00,000

除了逗号和点以及其他特定的分隔符外,似乎遮罩也是一个有效的问题。

在前端应用程序中本地化数字时,我还应该注意哪些其他警告?特别是如果我要向非拉丁字符集显示数字?


3
与金钱打交道时变得更加有趣!:-)
Stephan Bijzitter '16

4
没有谈论以6为底(两次3根手指)的火星编号系统;-)但是日语也很奇怪:man = 10.000写为1.0000,oku = 100.000.000在日本写为1.0000.0000和cho。 ..猜测
qwerty_so

6
为什么有这个担心?您不能遵循操作系统设置吗?
Jan Doggen '16

3
@JanDoggen,因为这是软件工程领域有趣的问题之一,“如何正确地向人们展示数据”。我在设计系统时应该担心的是这个问题的领域。正如我们的朋友斯蒂芬所说,我什至没有谈论金钱,也没有谈论日期和时间。只是原始数字。
马查多

5
@JanDoggen,这在处理在线软件时变得更加复杂。用户可能在美国英语计算机上的印度,但正在阅读巴西葡萄牙语的网页。您的服务器可能是中文。无论用户使用的是什么操作系统,或者服务器在哪里,您的应用都必须了解用户的需求。因此,您的1,000.00美元变成67.545,00卢比:一种美元,以本地汇率转换,但以葡萄牙语格式显示。
noderman '16

Answers:


87

大多数编程语言和框架已经具有可用于此目的的明智的工作机制。

例如,C#生态系统具有System.Globalization命名空间,该命名空间允许您指定所需的名称Culture

Console.WriteLine(myMoneyValue.ToString("C", "en-US"));

这不是您要重新发明的东西。使用您喜欢的语言或框架提供的国际化功能。


2
我知道System.Globalization和其他可为我处理这类复杂性的框架。我不知道他们正在解决什么问题。例如,我看到的几个应用程序在ToString上使用特定的掩码,例如.ToString(“#,## 0.00”,locale),但是如果我向印度人显示此数字,则该掩码本身是无效的。因此,除了“不要使用特定的蒙版”之外,我还应该注意什么?
马查多

7
我一无所知。如果您正确使用框架,它应该可以正常工作。在某些情况下,有一些国际化问题的具体案例,但是我们在这里没有做完整的清单来解决这些问题。请参阅此示例
罗伯特·哈维

5
这是唯一正确的答案:设置您的语言环境,然后在显示给用户之前通过i18n层推送您的值,然后让框架作者处理。这对于数字,货币值,翻译后的字符串,日期以及所有内容均适用。

2
完美的答案。处理此类常见问题时,应始终考虑“不要重新发明轮子”。可惜我不能多次投票。
BgrWorker '16

3
@Machado“例如,我看到的几个应用程序在ToString上使用特定的掩码,例如.ToString(”#,## 0.00“,locale),但是如果我向印度人显示此数字,则该掩码本身无效”。-可能不清楚,但请注意,格式字符串中的位置在很大程度上不相关,并且“#,0.00”将具有相同的效果。,只是表示“以语言环境指定的方式使用数字组分隔符”。
hvd

23

这里已经有一些很好的答案,但是他们没有提到我认为重要的一点,不要忘记:确保无论数字格式化发生在哪里,都清楚(或可以控制)输出用于什么:

  • 当用于用户界面时,必须应用本地化格式

  • 当该数字将被写入文件,通过网络发送或以机器可读形式使用该数字的另一种形式时,请确保该数字不是按照当前区域性进行格式化,而是按照固定设置进行格式化(例如,在.NET环境中,请使用InvariantCulture)。

否则,在使用区域性A写入或发送数字以及使用区域性B读取或接收数字时,您会遇到问题。

以我的经验,这是正确进行数字本地化的最大障碍之一:为了集中化数字格式和转换,人们开始创建通用的可重用函数以进行格式化,然后开始在整个范围内使用它们。地点。但是,一旦在程序的其他位置也需要以机器可读的字符串格式显示数字,就需要两个变体:本地化格式和非本地化格式。这带来了混淆两种转换形式的高风险(尤其是当开发人员和测试机器的默认语言环境设置类似于用于非UI格式的“固定”设置,而部分用户基础却没有)。

附录:如果事先不清楚该数字是由机器处理还是由人(或两者)处理,则此问题可能会变得非常棘手。例如,作为日志文件输出的一部分。在这种情况下,最好坚持不使用分隔符(除该点作为小数点分隔符以外)的“中性”标准。


2
更糟糕的是,许多现代制图语言将标准库中的明显/默认功能“本地化”。因此,如果开发人员不了解或不关心本地化,则最终的应用程序可能会失灵,而不仅仅是在国外系统上难看。
彼得·格林

4
我不同意同样的看法。在用户界面中不遵循本地数字约定的工具仍然可以使用。由于数字约定不匹配而导致无法读取其自身数据文件或无法与其服务器通信的工具极有可能无法使用。
彼得·格林

5
此事的轶事:en-ZA的十进制分隔符在Win 7和Win 8之间更改。以前本地存储的值开始无法反序列化
Caleth

1
@PeterGreen:在用户界面中未遵循本地数字约定的工具可能仍然可用,或者对于某些用例可能完全不可用。我会非常谨慎地做出这样的假设。如此多的开发人员将数字本地化错误的原因恰恰是-做出了这样的假设。
布朗

1
@DocBrown我要维护的最可怕的旧代码受标准库的本地化整数/浮点解析例程的影响。我认为可以公平地说,在某些情况下,当这些作业的默认例程未本地化时,不关心本地化而编写的程序可能无法使用,但是,如果默认例程已本地化,则该程序始终会在运行时就被破坏。在全局语言环境不是英语的计算机上执行。
塞巴斯蒂安·雷德尔

9

正确的本地化非常困难。大多数编程生态系统都在尝试本地化解决方案,但以我的经验,它们或多或少都被破坏了。因此,我建议:

  • 不要尝试自动化本地化。它并不总是有效。您很难发现问题并使用户感到沮丧。

  • 保持一致:请勿混用不同的语言和格式约定,例如,英文文本中的Brasilian样式小数点分隔符。

  • 明确支持给定的语言环境集。与您的翻译一起工作,找出正确的日期和数字格式。尽管大多数(但不是全部)问题可以委托给现有库,但您最终可能会创建自己的本地化工具包。

  • 使每个用户都可以配置简单的格式选择:日期和时间格式,小数点分隔符,首选货币等。这对于旅行者,外籍人士或需要独立于语言的多种地区或文化混合的其他人特别有用。


18
还应注意,许多用户讨厌被认为“适合其区域设置”的约定,认为这是一种可怕的传统做法,根本不希望进行分组或进行其他分组。因此,可能应该有一些选项可以将其关闭或手动覆盖它。
R ..

2

一个重要的考虑:您应该决定多少就足够了。因为如果您陷入试图完美定位的困境,它将变得越来越复杂。

请使用“您已选择n个项目”之类的典型标签。如果仅选择一项,则读取错误。丑陋但实用的解决方案是写“您选择了n个项目”。但是,如果要正确执行操作,则需要两个不同的文本,具体取决于n。如果您尝试在多个语言环境中执行此操作,则会很快变得非常复杂,因为不同的语言具有不同的语法。有些语言对一个,两个和多个项目具有不同的共轭形式,依此类推。因此,有识之士总是会抱怨现有的本地化框架不足。

但是,您必须选择自己的战斗,并决定什么水平的成熟度就足够了。对于许多目的,用于格式化数字和日期的标准本地化库就足够了。


这可以通过ICU(MessageFormat)解决。缺点是许多语言都无法使用ICU。但是,开发人员仍然需要以正确的方式构造消息。实际上,不仅限于工程方面。userguide.icu-project.org/formatparse/messages
noderman '12

这也可以通过GNU gettext中更广泛使用的ngettext函数来解决,但是MessageFormat类似乎还可以解决ngettext不能解决的一些额外问题。
hvd

2

您可能并不了解所有语言警告。您在谈论数字,但是有复数形式,性别和排序规则。您需要知道它们的存在,并依靠其他人(尤其是ICU和CLDR项目)所做的大量工作。

大多数现代语言都实现了这些项目的部分或全部功能,但是即使没有实现,阅读这些项目也可以使您对要查找的内容有个很好的了解。

http://site.icu-project.org

http://cldr.unicode.org

更新资料

CLDR调查工具提供对所有模式的访问。这将向您展示如何格式化某些语言和区域的数字。例如,葡萄牙语(葡萄牙):

http://st.unicode.org/cldr-apps/v#/pt_PT/Number_Formatting_Patterns/

如果您真的想检查所有数据(并可能使用它),则可以从GitHub下载JSON格式的CLDR:

https://github.com/unicode-cldr/cldr-json#cldr-json

有关下载的更多信息,请参见:

http://cldr.unicode.org/index/downloads


感谢您的输入,但到目前为止,我对数字最感兴趣。:)
马查多

当然。我刚刚编辑了回复,包括指向调查工具的链接,您可以在其中缩小搜索范围。
noderman '16

我尝试更改“巴西”以检查差异,但似乎并未为此启用可视化功能:st.unicode.org/cldr-apps/v#/pt_BR/Number_Formatting_Patterns否则,该工具似乎还不错。
马查多

那是因为巴西是母语。调查工具实际上是用于更改CLDR数据的,因此其根需要特殊帐户。您可以转到GitHub并直接获取所有信息:github.com/unicode-cldr/cldr-numbers-modern/tree/master/main具体来说,巴西在这里:github.com/unicode-cldr/cldr-numbers-modern/ blob / master / main / pt /…
noderman '16

0

好吧,虽然我对这里的所有答案都感到满意,但我对每个答案都分别标记为正确答案并不真正满意。

到目前为止,这是在数字本地化时应注意的事项:

对于人类

  • 数千个分隔符并不总是分隔成千上万个。参见问题中的印度案例;
  • 千位和十进制字符会因文化而异。例如,德语用空格将成千上万的空格分隔,英语用逗号分隔,而葡萄牙语用点分隔。
  • 从左到右和从右到左的语言之间是否存在相关差异,我们没有信息。
  • 提供一组特定的受支持的本地化并向您的用户清楚表明;
  • 允许您的用户将默认的本地化更改为支持的本地化之一,他们会很高兴,并感谢您,因为您是个慷慨的上帝。:);

对于计算机

  • 请记住,机器不是宽大的,在对数字进行序列化和反序列化时应始终采用相同的格式;
  • 坚持使用单一格式;
  • 使用最小可能的格式。避免千位分隔,小数应足以进行序列化和反序列化。

对于开发人员

  • (如下面的@hyde所建议):使用现有库进行本地化;
  • 如果可以,请使用本机测试人员并指定本地化/国际化测试用例,否则请信任该库;
  • 请记住,本地化是一个主要解决的问题。每种主要语言都有一个本地或外部库,可以本地化数字,日期和时间。

1
缺少的项目:对于开发人员:使用现有库进行本地化。如果可以,请使用本机测试人员并指定本地化/国际化测试用例,否则请信任该库。
海德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.