最佳实践JavaScript和多语言
什么是多语言网站使用DOM使用JavaScript操作的最佳做法? 我使用JavaScript构build网站的一些dynamic部分。 我的第一个想法是使用文本string和语言代码作为索引的数组。 这是一个好主意吗?
当我之前build立了多语种网站(不是很大的网站,所以这可能不能很好地扩展),我保留了一系列“语言”文件:
- lang.en.js
- lang.it.js
- lang.fr.js
每个文件都声明一个基本上只是从关键字到语言短语的地图的对象:
// lang.en.js lang = { greeting : "Hello" }; // lang.fr.js lang = { greeting : "Bonjour" };
dynamic加载其中一个文件,然后您只需从您的地图中引用密钥即可:
document.onload = function() { alert(lang.greeting); };
当然,还有很多其他的方法可以做到这一点,还有很多方法可以做到这一点,但更好:把它封装到一个函数中,这样就可以优雅地处理你的“字典”中丢失的短语,甚至完成整个事情使用OOP,让它pipe理包括文件在内的dynamic,甚至可以为你绘制语言select器等。
var l = new Language('en'); l.get('greeting');
在devise多语言支持时,需要注意以下几点:
1 – 从数据分离代码(即不要硬编码string到你的function)
2 – 创build格式化钩子函数来处理本地化差异。 允许可格式化的string( “{0}” )优于连接( “欢迎使用”+值 ),原因很多:
- 在某些语言中,一个数字格式为1.234.678,00,而不是1,234,567.00
- 多元化往往不如在单数的末尾附加“s”那么简单
- 语法规则是不同的,可以影响事物的顺序,所以你应该允许在翻译挂钩之后添加dynamic数据:例如, “Welcome to {0} ”在日语中变成“{0} he youkoso” (这发生在几乎所有的语言,介意你)。
3 – 确保您可以在翻译挂钩运行后实际格式化string,以便您可以重复使用键。
4 – 不要在任何环境下将数据库输出连接到翻译工具 。 如果您有多语言数据,请在数据库中创build单独的表/行。 我已经看到人们经常会这样理解(通常是国家和州/省的forms)。
5 – 创build显式编码实践规则来创build密钥。 格式化工具函数(看起来像translate(“hello world”))会把一个键作为一个参数,而且键略有变化会使维护非常烦人。例如,在下面的例子中,最后可能会出现三个键: “input你的名字”,“input你的名字:”,“input你的名字:”,select一种格式(例如,不用冒号,修剪),并在代码评论中发现差异,不要以编程方式进行过滤,因为它可以触发虚假阳性。
6 – 注意在翻译表中可能需要HTML标记(例如,如果您需要在一个句子中加粗一个单词,或者有脚注医学参考)。 广泛的testing。
7 – 有几种导入语言string的方法。 理想情况下,你应该有一个language.lang.js文件的多个版本,用服务器端代码在它们之间切换,并从HTML文件的底部引用文件。 通过AJAX拉取文件也是一种select,但可能会引入延迟。 将language.js合并到你的主代码文件是不可取的,因为你失去了文件caching的好处。
8 – testing你的目标语言。 这听起来很愚蠢,但是我曾经看到一个严重的错误,因为程序员没有在密钥中检查“é”的存在。
function Language(lang) { var __construct = function() { if (eval('typeof ' + lang) == 'undefined') { lang = "en"; } return; }() this.getStr = function(str, defaultStr) { var retStr = eval('eval(lang).' + str); if (typeof retStr != 'undefined') { return retStr; } else { if (typeof defaultStr != 'undefined') { return defaultStr; } else { return eval('en.' + str); } } } }
把这个添加到你的页面后,你可以像这样使用它:
var en = { SelPlace:"Select this place?", Save:"Saved." }; var tr = { SelPlace:"Burayı seçmek istiyor musunuz?" }; var translator = new Language("en"); alert(translator.getStr("SelPlace")); // result: Select this place? alert(translator.getStr("Save")); // result: Saved. alert(translator.getStr("DFKASFASDFJK", "Default string for non-existent string")); // result: Default string for non-existent string var translator = new Language("tr"); alert(translator.getStr("SelPlace")); // result: Burayı seçmek istiyor musunuz? alert(translator.getStr("Save")); // result: Saved. (because it doesn't exist in this language, borrowed from english as default) alert(translator.getStr("DFKASFASDFJK", "Default string for non-existent string")); // result: Default string for non-existent string
如果您用没有定义的语言给class级打电话,英语( en )将被选中。
刚刚在javascript中发现了一篇关于i18n的好文章:
http://24ways.org/2007/javascript-internationalisation
尽pipe使用i18n + javascript进行简单的Googlesearch显示了很多select。
最后,这取决于你想要多深 。 对于几种语言,单个文件就足够了。
您可以使用像Jquery这样的框架,使用span来标识文本(带有一个类),然后使用每个span的id来find所选语言的相应文本。
1行的JQuery,完成。
在阅读了nickf和Leo的精彩回答之后,我创build了下面的CommonJS风格的language.js来pipe理我所有的string(也可以用Mustache来格式化它们):
var Mustache = require('mustache'); var LANGUAGE = { general: { welcome: "Welcome {{name}}!" } }; function _get_string(key) { var parts = key.split('.'); var result = LANGUAGE, i; for (i = 0; i < parts.length; ++i) { result = result[parts[i]]; } return result; } module.exports = function(key, params) { var str = _get_string(key); if (!params || _.isEmpty(params)) { return str; } return Mustache.render(str, params); };
这就是我如何得到一个string:
var L = require('language'); var the_string = L('general.welcome', {name='Joe'});
你应该看看在经典的JS组件中已经做了什么 – 像Dojo,Ext,FCKEditor,TinyMCE等。你会发现很多好主意。
通常,它最终会成为您在标签上设置的某种属性,然后根据属性的值,将标签的内容replace为在翻译文件中find的翻译。
要记住的一件事是语言集的演变(当你的代码发展,你需要翻译整个事情)。 我们保留在PO文件(Gnu Gettext)中的翻译,并且我们有一个将PO文件转换为准备使用JS文件的脚本。
此外:
- 总是使用UTF-8 – 这听起来很愚蠢,但如果你从开始(HTML头+ JS编码)不在utf-8,你会很快崩溃。
- 使用英文string作为您的翻译的关键 – 这样你就不会结束如:lang.Greeting ='你好世界' – 但郎['你好世界'] ='你好世界';
对于Spring bundle和JavaScript,有一个简单的解决scheme:在模板中生成i18n数组(例如JSP)并在JavaScript中使用它:
JSP:
<html> <script type="text/javascript"> var i18n = []; <c:forEach var='key' items='<%=new String[]{"common.deleted","common.saved","common.enabled","common.disabled","...}%>'> i18n['${key}'] = '<spring:message code="${key}"/>'; </c:forEach> </script> </html>
而在JS中:
alert(i18n["common.deleted"]);
另请参阅parsingspring:i18n国际化的javascript中的消息