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

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

评论

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

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

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

如果最终将本地化的字符串而不是资源文件存储在数据库中,则可能需要看一下以下讨论:stackoverflow.com/questions/2458615/…

@ pete,@ smartcaveman说他正在“为.NET MVC应用程序开发UI”,所以...

#1 楼

您正在开发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()

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

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)。
请记住,在大多数字段(即用户名)中允许使用“奇怪的”字符。

测试

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

评论


关于复合消息-我不得不做一次复数形式。我扩展了String.Format,以便它可以支持这种很酷的语法:“找到{0:是|是} {0} {0:virus | viruses}。”每种语言都可以加载自己的规则,因此您可以执行“ Znaleziono {0} {0:wirusy |wirusów}”。来源在GitHub上:github.com/scottrippey/SmartFormat/wiki

–斯科特·里皮(Scott Rippey)
2011年8月9日23:13



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

– Gregopet
2011年8月10日下午5:32

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

–斯科特·里皮(Scott Rippey)
2011年8月15日在22:42

对于伪本地化,我在pseudolocalize.com上构建了一个免费的在线伪本地化工具。

–JerSchneid
2014年5月25日下午3:38

#2 楼

您应该考虑一些基本的事情:

外部化所有字符串资源

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

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

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


好->接受器(法语-400%扩展)


我建议您进行某种形式的操作伪翻译作为起点(http://en.wikipedia.org/wiki/伪本地化)。或者,您可以通过Google翻译或Bing翻译资源。这样可以很好地指示实际的翻译效果。

注意图像中的文本

如果在应用程序中使用任何图像,请确保它们不会不能包含任何文本-显然不能翻译。

从不对Windows文件夹的任何路径进行硬编码

很明显,但我以前已经看过。例如,C:\Program Files在某些国际版本的Windows(例如Windows)上翻译。在德语操作系统上是C:\Programme。西欧。

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

例如,这看起来无害:

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


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

时间/日期设置

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

评论


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

–smartcaveman
2011年3月10日在18:33

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

–taylonr
2011年3月10日在18:45

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

–奈良
2011年4月2日在6:49

@ Jimmy-C好答案!

– klabranche
2011年4月2日在15:52

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

–Crippledsmurf
2011年6月29日14:11

#3 楼

亚洲语言的特殊注意事项

除了此处已提供的所有出色答案之外,还有一些亚洲语言的注意事项:

请注意不同长度的文本

中文和韩文的文字往往比等效的英文文字短得多(因为您通常需要更少的块状字符来写相同的东西),因此页面实际上可能看上去是空白的,但是却被德文塞满了。需要在此处进行一些动态大小调整,以使其看起来不错。

但是,日语字符通常会更长,甚至比等效的英语字符还要长。

请注意基线布局和“向上滑动”的外观

亚洲字符通常布置在基线上,不包括后裔(即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”做爱可能很安全-我们还不那么奇怪...

评论


最后一段让我微笑。

– BoltClock
2011年4月7日在7:13

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

–Paweł Dyda
2011年4月8日13:00

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

–巴特·弗里德里希斯(Bart Friederichs)
2012年10月29日13:31

#4 楼

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

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


通过这种方式,您可以为所使用的每种语言创建一个新的资源文件(.NET将对此提供帮助。)并在每个文件中都具有本地化的字符串。

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

评论


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

–Paweł Dyda
2011年4月8日13:03

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

–taylonr
2011年4月8日13:12

#5 楼

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

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

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

评论


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

–smartcaveman
2011年3月29日13:51

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

–西蒙·穆里尔(Simon Mourier)
2011年3月29日14:12

#6 楼

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

评论


为了方便快捷地进行伪本地化,我在pseudolocalize.com上构建了一个免费的在线工具

–JerSchneid
2014年5月25日下午3:39

#7 楼

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

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

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

请非常注意在SQL数据库中以日期格式存储的proc中的美国格式中的文本

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

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

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

#8 楼

您需要考虑:


多语言路由
将所有硬编码字符串移动到资源文件中

属性示例:

型号:

[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)


#9 楼

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

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


在Visual Studio中进行编辑很麻烦
限制分发和管理编译/发布/运行应用程序后,本地化资源的数量。

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

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

评论


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

–smartcaveman
2011年7月6日在17:27

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

– Gregopet
2011年8月10日下午5:42

#10 楼

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

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

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

#11 楼

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


所有信息都应国际化。请考虑图形可能包含我们要国际化的信息。
字段或字符串的大小,取决于语言,因为它可能导致我们遇到问题。
字的顺序取决于语言,因此一种语言的顺序将与另一种语言相同。
我们必须考虑到日期格式将从一种语言更改为另一种语言


#12 楼

在土耳其测试:


在最好的情况下,软件国际化是困难的,但它总是让我感到惊讶的是,一个特定的国家出现在国际化问题的讨论中的频率是多少? br />
如果您关心本地化或国际化,请强制您的代码在合理的可能范围内尽快在土耳其语区域设置下运行。对于大多数(但绝不是全部)文化和区域设置而言,这是您代码运行的强大领头羊。它可以在大多数其他平台上运行。