.NET中有效的本地化策略[关闭]


121

我正在为.NET MVC应用程序开发UI,在不久的将来它将要求所有内容的国际本地化。我对.NET总体上非常熟悉,但是从来没有一个项目需要如此高度地关注国际可访问性。

该项目最初是用英语完成的。在这一点上,我应该采取什么措施来简化将来的本地化工作?


2
好问题!我正面临着类似的情况,很乐意看到专家对此进行评估。

有人对资源管理有任何好的标准吗?本地化的值可能还包括图像,而不仅仅是字符串。

1
这是WPF / silverlight UI还是Winforms?从我的经验(有限的经验)来看,WinForms的本地化经验比WPF / Silverlight更为简单。
PeteStensønes2011年

1
如果你最终在数据库中存储你的本地化字符串,而不是资源文件,你可能想看看这个讨论:stackoverflow.com/questions/2458615/...

1
@ Pete,@ smartcaveman说他正在“为.NET MVC应用程序开发UI”,所以……
BrunoSalvino 2011年

Answers:


74

您正在开发ASP.Net MVC应用程序,对吗?其他答案似乎特定于桌面应用程序。让我捕捉一下常见的事情:

语言环境检测

应用程序正确检测用户的语言环境非常重要。在桌面应用程序中,CultureInfo.CurrentCulture拥有首选的格式设置区域(应用于格式化数字,日期,货币等),而CultureInfo.CurrentUICulture拥有首选的用户界面区域设置(应用于显示本地化消息的区域)。 。对于Web应用程序,应该将两种区域性都设置为auto(以自动从AcceptLanguage标头中检测区域设置),除非您想要实现一些高级的区域设置检测工作流(即,希望支持按需更改语言)。

外化字符串

所有字符串都应来自资源,即Resx文件。在Winforms App中,可以通过将窗体Localizable属性设置为true来轻松实现。您还需要手动(不幸的是)外部化来自模型的字符串。这也相对简单。在Asp.Net中,您需要手动外部化所有内容...

版面

您绝对需要允许字符串扩展。在Winforms世界中,可以通过TableLayoutPanel实现此功能,应使用TableLayoutPanel确保布局将自动调整以容纳更长的文本。在网络世界中,您有点不走运。您可能需要实现CSS本地化机制-一种修改(覆盖)CSS定义的方法。这将使本地化人员可以按需修改样式问题。确保呈现的页面中的每个HTML元素都有唯一的ID-它将可以精确定位。

文化特定问题

避免使用可能特定于西方文化的图形,颜色和声音。如果您确实需要它,请提供本地化方法。避免使用对方向敏感的图形(因为当您尝试本地化为阿拉伯语或希伯来语时会出现问题)。另外,不要假设整个世界都使用相同的数字(即阿拉伯语不是这样)。

ToString()和Parse()

除非不支持,否则请确保在调用ToString()时始终传递CultureInfo。这样,您就可以评论自己的意图。例如:如果您在内部使用某个数字,并且由于某种原因需要将其转换为字符串,请使用:

int i = 42;
var s = i.ToString(CultureInfo.InvariantCulture);

对于将要显示给用户使用的数字:

var s = i.ToString(CultureInfo.CurrentCulture); // formatting culture used

同样适用于Parse(),TryParse()甚至ParseExact()-如果不正确使用CultureInfo,可能会引入一些讨厌的错误。那是因为Microsoft中一些可怜的人,满怀良好的意愿,决定将CultureInfo.CurrentCulture视作默认值是一个好主意(如果您不传递任何内容,将使用它)-毕竟有人使用ToString( )他/她想将其显示给用户,对吗?事实并非总是如此-例如,尝试将应用程序版本号存储在数据库中,然后将其转换为Version类的实例。祝好运。

日期和时区

确保始终在UTC中存储和实例化DateTime(使用DateTime.UtcNow代替DateTime.Now)。在显示时将其转换为本地格式的本地时间

DateTime now = DateTime.UtcNow;
var s = now.ToLocalTime().ToString(CultureInfo.CurrentCulture);

如果您需要在正文中发送带有时间参考的电子邮件,请确保包含时区信息-包括UTC偏移量和城市列表:

DateTime someDate; // i.e. from database
var formattedDate = String.Format("{0} {1}", 
             someDate.ToLocaleTime().ToString(CultureInfo.CurrentCulture),
             TimeZoneInfo.Local.DisplayName);

复合消息

您已经被警告不要连接字符串。相反,您可能会使用如上所示的String.Format()。但是,我必须指出,您应尽量减少使用复合消息。那只是因为目标语法规则通常是非常不同的,所以翻译人员可能不仅需要重新排列句子(可以通过使用占位符和String.Format()解决),还可以根据什么将被替代。让我给你举一些例子:

// Multiple plural forms
English: 4 viruses found.
Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów.

// Conjugation
English: Program encountered incorrect character | Application encountered incorrect character.
Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.

其他串联问题

串联不限于字符串。避免将控件放在一起,例如:

在[带数字的文本框]天中再次提醒我。

应该将其重新设计为:在此天数内再次提醒我:[文本框]。

字符编码和字体

始终保存,传输Unicode中的任何文本(即UTF-8)。请勿对字体进行硬编码-本地化可能需要对其进行修改,这将关闭默认的字体后备机制(对于Winforms)。请记住,在大多数字段(即用户名)中允许使用“奇怪”字符。

测试

您可能需要实现所谓的伪翻译,即为德国文化创建资源并复制带有前缀和后缀的英文字符串。您还可以包装占位符以轻松检测复合字符串。伪翻译的目的是检测可本地化的问题,例如硬编码的字符串,布局问题和复合消息的过度使用。


5
关于复合消息 -我不得不做一次复数形式。我进行了扩展String.Format,使其可以支持这种很酷的语法:"There {0:was|were} {0} {0:virus|viruses} found."每种语言都可以加载自己的规则,因此您可以做到"Znaleziono {0} {0:wirusy|wirusów}." 这一点。源代码在GitHub上:github.com/scottrippey/SmartFormat/wiki
Scott Rippey

2
@Scott Rippey您是否注意到波兰语示例中写着“ Znaleziono 4 wirusy。 Znaleziono 5wirusów”。<-波兰语与许多其他语言一样,具有两种以上的复数形式,区分它们的规则也可能很复杂。在这里我必须离开波兰语,因为我不会讲波兰语,但是用我的语言,101事物的复数形式与1事物的复数形式相同。您可以看一下GNU gettext如何解决此问题:gnu.org/s/hello/manual/gettext/Plural-forms.html
gregopet 2011年

2
@gregopet我的波兰语示例是人为设计的,因为我不会说,但这正是SmartFormat项目所做的。这是一个更好的示例:"{0} {0:plik|pliki|plików}"。格式化程序具有波兰语规则,该规则确定要使用的三种形式中的哪一种,并正确确定特殊情况。我目前正在努力添加更多规则,因此,gettext本文将非常有用,谢谢。
Scott Rippey

对于伪本地化,我在pseudolocalize.com上
JerSchneid 2014年

74

您应该考虑一些基本事项:

外部化所有字符串资源

您的所有资源都应包含在可以进行本地化的外部文件中。如果您也想将错误消息本地化,请不要忘记错误消息。

留出足够的空间来扩展字符串

例如,某些语言中的字符串通常最多长30%(例如希腊文),因此请确保以某种方式设计UI,以便在必要时可以扩展字符串。这是法语的一个极端示例:

确定->接受者(法语-400%扩展)

我建议您以某种伪翻译作为起点(http://en.wikipedia.org/wiki/Pseudolocalization)。或者,您可以通过Google翻译或Bing翻译资源。这样可以很好地指示实际翻译的外观。

注意图像中的文字

如果您在应用程序中使用任何图像-确保它们不包含任何文本-这显然无法翻译。

永远不要硬编码Windows文件夹的任何路径

很明显,但是我过去已经看过。例如,C:\Program Files在某些国际版本的Windows(例如,C:\Programme在德语OS)上进行了翻译。

避免使用特定于语言环境的术语

例如,如果您以表格的形式向某人要求其“高中”,则在西欧几乎没有意义。

避免通过字符串连接创建字符串

例如,这看起来无害:

strWelcome = ReadExternalString("Welcome"); 
strMessage = strWelcome + ", " + UserName;

但是,例如日语单词的顺序会有所不同,因此最终可能没有任何意义。

时间/日期设置

始终确保从操作系统获取时间/日期格式。


@Jimmy C,您如何构建字符串以实现与语言无关的逻辑一致性?
smartcaveman 2011年

14
@Smart在您的资源中执行诸如“ {0},{1}”之类的操作,然后在对它进行本地化时,使用string.format并传入问候语和用户名。此外,这还为您带来了“当前{0}的速度为{1} {2}”的好处,并且您可以传入“ Engine”,“ 50”和“ MPH”,翻译句子时,可以移动{ 0}
等到

4
好名单JimmyC。“从不对Windows文件夹的任何路径进行硬编码”使我想起“始终使用Path.Combine”而不是Windows路径的字符串连接。

@ Jimmy-C好答案!

1
Environment.GetFolderPath可以用于获取常见路径(例如“我的文档”)的有效路径,而不必依赖于这些文件夹的英文名称。
Crippledsmurf

24

亚洲语言的特殊注意事项

除了这里已经给出的所有出色答案之外,还有些亚洲语言的注意事项:

当心不同长度的文本

中文和韩文文本往往比等效的英文文本短得多(因为您通常需要更少的块状字符来写相同的东西),因此页面实际上可能看上去是空白的,但是却被德语完全塞住了……您需要这样做这里有些动态大小看起来不错。

但是,就字符数而言,日语文本通常倾向于更长,甚至比等效的英语文本更长。

提防基线布局和“向上滑动”外观

亚洲字符通常布置在基线上,不包括后裔(即y,g,q,j等的下部)。在格式化屏幕元素(通常是按钮)时,其内部带有文本,如果如果文字仅是亚洲语言(即没有西方字母),则文字看起来像是向上移动。

数字格式和本地化的数字单位

处理数字格式不同。不同的亚洲国家/地区使用不同的数字格式方式。与货币相同。例如,在东亚,10,000(wan)是一个常见单位。在印度,通常有100,000(十万)。

当地货币

一些国家的货币有很多零,没有小数点(例如日本,印度尼西亚,意大利),而其他国家的小数点后最多有两位数。

当心不同的单词顺序

单词顺序可能并不总是相同。如果您的字符串来自不同数据的组合,则最好以字符串格式使用{0},{1}等,而不是硬编码单词顺序。

使用特定于语言环境的排序

每种语言和语言环境的排序是不同的-您应始终依赖于O / S特定于语言环境的排序。

请注意全角/半角字符

注意“全角”和“半角”字符之间的差异。括号,标点符号等可以具有不同于标准ASCII的“全角”版本。如果您要根据这些字母进行搜索或字符串分割,则需要先将所有全角符号转换为等价的半角。

句点不是点...逗号不是逗号...

当心数据输入的陷阱-例如,在中文中,句点不是点“。”。逗号是全角,而不是“,”。如果进行数据输入的用户可能会意外打开亚洲语言IME,请不要尝试搜索西方标点符号。

电话号码

不要以电话号码格式假设任何内容。并不总是有区号等,并且可以采用不同的格式。通常,每个国家/地区都有一个格式字符串。

不要以为人们只有一个手机号码或一个传真号码等。在亚洲,情况并非如此。

地址-比您想象的要密集

对于地址,不要假设任何东西。不一定总是有邮政编码。邮政编码可能并不总是数字。一个国家可能没有省/州。一个国家可能只是一个大城市(例如新加坡)。对于某些亚洲国家/地区,房屋的最小单位可能是“ X房Y单元Z区Z层A楼B组C房地产D”。通常,在字段数和地址中允许的字符数上要非常宽松

称呼

称呼不仅限于先生,太太等。尽管您可以安全地使用“ M”和“ F”进行性爱,但我们还不那么奇怪...


1
最后一段让我微笑。
BoltClock

哦,我们(i18n伙计们)甚至还没有开始...我们只能挠头:)如果我们要谈论诸如GB18030支持之类的特定问题,那么我们的帖子对SO来说太长了:)谢谢无论如何,为了您的笔记,我错过了很多东西。
帕维尔Dyda

关于最后一个,我相信英国现在正式接受“其他”作为性爱。想想跨性别者。
巴特·

11

一些基本步骤是确保屏幕上显示的任何字符串都不是代码中的文字。如果您正在执行Winforms,则每个表单都将具有UI资源。对于对话框,报告等,请确保您使用项目资源文件。

因此,您的代码中可能会出现诸如Resources.UploadFailed之类的内容,而不是代码中的“ Upload failed”(上载失败)

这样,您可以为您使用的每种语言创建一个新的资源文件(.Net将对此提供帮助。)并在每个文件中包含本地化的字符串。

编辑 我忘记了在执行UI时要提及的内容,请确保您不只是在其中添加内容。根据您要本地化的语言,房地产可能是个问题。我从事的项目中,德语和葡萄牙语是字符串增长的两个最大罪犯。如果我们不小心,英语,法语和意大利语的字符串会很好用德语。


1
根据我的L10n经验,俄语是最坏的情况。在Winforms中,只要使用TableLayoutPanels的正确用户,就可以优雅地处理字符串增长。
帕维尔Dyda

是的,我的经验仅限于7种语言:英语,德语,葡萄牙语,意大利语,法语,西班牙语和日语。但是我可以看到俄语很糟糕,因为它们往往有很多后缀和前缀
taylonr 2011年

9

我建议您在程序集上运行FXCop或Visual Studio Code Analysis(它们完全相同)。

它们擅长检测未使用适当的面向区域性重载的.NET代码,例如:CA1305:指定IFormatProvider

我还必须补充一点,这些工具也令人沮丧,因为它们通常会在您的代码中检测到成千上万的问题,但是,即使您不遵循每个规则,也应该学到很多东西。


这是默认设置吗,还是我需要为其指定一些设置以搜索特定于全球化的规则?
smartcaveman 2011年

@smartcaveman-这是默认设置(嗯,实际上,有些人认为这些工具中有很多默认规则:-)
Simon Mourier 2011年

7

除了特定的资源加载方式之外,我还要确保首先使用伪本地化版本进行测试。否则,您直到最后都不会注意到省略国际化注意事项的地方。


为了方便快捷地进行
伪本地化

6

除了所有其他有用的提示以外,这里还缺少一些提示:

考虑到一些国家使用多种语言。例如,在加拿大,用户希望能够轻松地在英语和法语之间切换。

如果您问用户一个需要一个字母答复的问题,不要指望用户按“ Y”键说“是”。

在存储过程中要非常注意,SQL DB中的日期是美国格式的

在数据库中放置文本字符串使您以后可以添加其他语言而无需重新部署。

发送书面文本文件进行翻译时,请始终包含上下文描述,以确保翻译人员选择正确的单词。例如,没有上下文,您可以将“ pitch:”转换为与声音或踢足球的地方有关的内容

地址标签始终需要转换。加拿大的省,美国的州,英国的县


5

您需要考虑:

  1. 多语言路由

  2. 将所有硬编码字符串移动到资源文件

属性的示例:

模型:

[Display(Name = <Resource for display name>.<field for this property>)]
[Required(ErrorMessage = <Resource for error message>.<field for this validate message>)]
public string TestProperty { get; set; }

视图:

@Html.LabelFor(m=>m.TestProperty)
@Html.EditorFor(m => m.TestProperty)
@Html.ValidationMessageFor(m => m.TestProperty)

5

这是其余答案中未提及的内容。

根据您的应用程序及其本地化的复杂性,我强烈建议您实施替代资源提供程序,并将本地化的资源保留在数据库中。使用默认的ASP.NET本地化方案,所有资源都保存在RESX文件中,该文件:

  1. 在Visual Studio中进行编辑很麻烦
  2. 编译/装运/运行应用程序后,限制本地资源的分配和管理。

作为一个可能的用例,请考虑为您的应用程序提供语言包以及通过UI导入和导出语言的功能。RESX文件在这里无济于事。

在这种情况下,替代资源提供者将非常有帮助。有关如何实现的更多信息,请参见此处。当然,这种情况很少见,在企业应用程序中更常见,但仍然有效。


1
感谢您抽出宝贵的时间查看这些出色的答案,并且仍然在贡献新的和有用的东西。
smartcaveman 2011年

+1; 我在Asp.NET中构建了一个广泛的Web应用程序,最后我们通过数据库进行了翻译。经常会添加新功能,但是由于我们的翻译人员不是使用的特定术语的专家,因此我们能够快速解决诸如“为什么将Y用作X的单词Y,这显然是错误的?”之类的愤怒的客户电子邮件。
gregopet

3

最重要的是用各种语言管理内容。我自己开发了一些websistes,以各种语言管理内容是最大的挑战。

我正在使用数据库存储资源/内容。它使我可以灵活地添加所需的任何语言支持。如果未找到特定语言的资源,我已经实现了退回到英语的逻辑。

您以后可以使用翻译器将英语值转换为任何语言。


2

国际化中要考虑的事项摘要:

  • 所有信息应国际化。考虑到图形可能包含我们要国际化的信息。

  • 字段或字符串的大小,取决于语言,因为这可能会给我们带来问题。

  • 单词的顺序取决于我们所使用的语言,因此一种语言的顺序将与另一种语言相同。

  • 我们必须考虑到日期格式将从一种语言更改为另一种语言


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.