字符串和标签的本地化和全球化的最佳实践


124

我是拥有20多个开发人员的团队的成员。每个开发人员都在一个单独的模块上工作(大约10个模块)。在每个模块中,我们可能至少有50个CRUD表单,这意味着我们目前有近500个添加按钮保存按钮编辑按钮等。

但是,由于我们要全球化应用程序,因此我们需要能够翻译应用程序中的文本。例如,在任何地方,“ 添加 ”一词对于法国用户来说都应该变得愚蠢

到目前为止,我们所做的是,对于UI或表示层中的每个视图,我们都有翻译的键/值对字典。然后,在渲染视图时,我们使用此字典翻译所需的文本和字符串。但是,使用这种方法,我们在500个字典中增加了500个。这意味着我们违反了DRY原则。

另一方面,如果我们将通用字符串集中化(例如将add放在一个地方,并要求开发人员在任何地方使用它),则会遇到无法确定集中式字典中是否已定义字符串的问题。

另一种选择是没有翻译词典,并使用在线翻译服务,例如Google Translate,Bing Translator等。

我们遇到的另一个问题是,在按时交付项目的压力下,一些开发人员忘记了翻译键。例如,对于添加按钮的文本,开发人员使用添加,而另一个开发人员使用new,等等。

应用程序的字符串资源的全球化和本地化的最佳实践或最著名的方法是什么?


2
谈话亚历克斯·塞克斯顿的主题客户端国际化从JS欧盟会议是一个良好的开端。
2013年

Answers:


51

据我所知,有一个很好的库,要求localeplanetJavaScript中的本地化和国际化。此外,我认为它是本机的,并且不依赖于其他库(例如jQuery)

这是图书馆的网站:http : //www.localeplanet.com/

还请参阅Mozilla的这篇文章,您可以找到用于客户端翻译的非常好的方法和算法:http : //blog.mozilla.org/webdev/2011/10/06/i18njs-internationalize-your-javascript-with-来自json和服务器的小帮助/

所有这些文章/库的共同点是它们使用i18n类和get方法(在某些方面还定义了一个较小的函数名称,如_)来检索或将其转换keyvalue。在我的解释中key,您想要value翻译的字符串和意思翻译的字符串。
然后,您只需要一个JSON文档来存储keyvalue

例如:

var _ = document.webL10n.get;
alert(_('test'));

这里是JSON:

{ test: "blah blah" }

我相信使用当前流行的库解决方案是一个好方法。


1
没有冒犯,但是这不是阿夫辛已经尝试过的吗?他的问题在于,不同的开发人员很难记住要使用的密钥。我同意您所描述的方法是正确的方法。我不知道怎么回事。谢谢你的伟大的联系顺便说一句。
Spock

47

当您面临要解决的问题时(坦率地说,如今不是谁?),我们电脑人通常采取的基本策略称为“分而治之”。它是这样的:

  • 将特定问题概念化为一组较小的子问题。
  • 解决每个较小的问题。
  • 将结果合并为特定问题的解决方案。

但是,“分而治之”并不是唯一可行的策略。我们还可以采用更通用的方法:

  • 将特定问题概念化为更一般问题的特例。
  • 以某种方式解决了普遍的问题。
  • 使一般问题的解决方案适应特定问题。

-埃里克·利珀特

我相信,在服务器端语言(例如ASP.Net/C#)中已经存在许多解决此问题的解决方案。

我已经概述了该问题的一些主要方面

  • 问题:我们只需要加载所需语言的数据

    解决方案:为此,我们将每种语言的数据保存到单独的文件中

例如 res.de.js,res.fr.js,res.en.js,res.js(用于默认语言)

  • 问题:每个页面的资源文件应该分开,这样我们只能获取所需的数据

    解决方案:我们可以使用一些已经存在的工具,例如 https://github.com/rgrove/lazyload

  • 问题:我们需要一个键/值对结构来保存我们的数据

    解决方案:我建议使用JavaScript对象而不是字符串/字符串。我们可以从IDE的智能感知中受益

  • 问题:常规成员应存储在公共文件中,所有页面都应访问它们

    解决方案:为此,我在Web应用程序的根目录中创建一个名为Global_Resources的文件夹,并为每个名为“ Local_Resources”的子文件夹存储一个全局文件的文件夹。

  • 问题:每个子系统/子文件夹/模块成员应在其作用域上覆盖Global_Resources成员

    解决方案:我考虑了每个文件

应用结构

root/
    Global_Resources/
        default.js
        default.fr.js
    UserManagementSystem/
        Local_Resources/
            default.js
            default.fr.js
            createUser.js
        Login.htm
        CreateUser.htm

文件的相应代码:

Global_Resources / default.js

var res = {
    Create : "Create",
    Update : "Save Changes",
    Delete : "Delete"
};

Global_Resources / default.fr.js

var res = {
    Create : "créer",
    Update : "Enregistrer les modifications",
    Delete : "effacer"
};

所需语言的资源文件应加载到从Global_Resource选择的页面上-这应该是所有页面上加载的第一个文件。

UserManagementSystem / Local_Resources / default.js

res.Name = "Name";
res.UserName = "UserName";
res.Password = "Password";

UserManagementSystem / Local_Resources / default.fr.js

res.Name = "nom";
res.UserName = "Nom d'utilisateur";
res.Password = "Mot de passe";

UserManagementSystem / Local_Resources / createUser.js

// Override res.Create on Global_Resources/default.js
res.Create = "Create User"; 

UserManagementSystem / Local_Resources / createUser.fr.js

// Override Global_Resources/default.fr.js
res.Create = "Créer un utilisateur";

manager.js文件(此文件应最后加载)

res.lang = "fr";

var globalResourcePath = "Global_Resources";
var resourceFiles = [];

var currentFile = globalResourcePath + "\\default" + res.lang + ".js" ;

if(!IsFileExist(currentFile))
    currentFile = globalResourcePath + "\\default.js" ;
if(!IsFileExist(currentFile)) throw new Exception("File Not Found");

resourceFiles.push(currentFile);

// Push parent folder on folder into folder
foreach(var folder in parent folder of current page)
{
    currentFile = folder + "\\Local_Resource\\default." + res.lang + ".js";

    if(!IsExist(currentFile))
        currentFile = folder + "\\Local_Resource\\default.js";
    if(!IsExist(currentFile)) throw new Exception("File Not Found");

    resourceFiles.push(currentFile);
}

for(int i = 0; i < resourceFiles.length; i++) { Load.js(resourceFiles[i]); }

// Get current page name
var pageNameWithoutExtension = "SomePage";

currentFile = currentPageFolderPath + pageNameWithoutExtension + res.lang + ".js" ;

if(!IsExist(currentFile))
    currentFile = currentPageFolderPath + pageNameWithoutExtension + ".js" ;
if(!IsExist(currentFile)) throw new Exception("File Not Found");

希望能帮助到你 :)


7
对于这种方法,我唯一不喜欢的是本地化和开发紧密耦合……因此,当添加英语(无论默认为)字符串时,其余的语言都必​​须通过代码进行更新。我宁愿使用某种翻译文件中的工具创建JSON。仍然是一个很好的代表!
Nate-Wilkins

与本地化的方式相同,您可以在此查询中看到:stackoverflow.com/q/53864279/4061006。唯一的事情是如何将Global_Resources / default.js转换为Global_Resources / default.fr.js?您使用哪个工具/工具包将那些文件转换为所需的语言。因为我也需要这个
Jayavel

您应该在每个键旁边存储一个易于理解的注释,描述字符串的去向及其含义,以便您在添加新语言时忘记为翻译者(或您自己)提供更多上下文信息弦的意思。例如,"Create" : {"message": "Create", "description": "text on the button that opens the editor with a blank Foo"}本地化Chrome扩展程序一样执行类似的操作。或创建一个包含这些注释的单独文件。
鲍里斯

13

jQuery.i18n是一个轻量级的jQuery插件,用于在您的网页中启用国际化。它允许您将自定义资源字符串打包在'.properties'文件中,就像在Java Resource Bundles中一样。它根据提供的语言或浏览器报告的语言来加载和解析资源包(.properties)。

要了解更多信息,请看一下如何使用JQuery将页面国际化?


链接不见了
Alexander Farber
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.