Javascript Xpages:我们如何实现客户端JS代码的本地化?
我目前正在开发一个多语言的Xpages驱动的应用程序,使用标准方法通过内部Javascript Xpages:我们如何实现客户端JS代码的本地化?,javascript,dojo,internationalization,xpages,Javascript,Dojo,Internationalization,Xpages,我目前正在开发一个多语言的Xpages驱动的应用程序,使用标准方法通过内部.property资源和资源束本地化静态和动态字符串。在应用程序中,用户可以选择自己喜欢的语言,此决定当前存储在用户配置文档中;我还计划将这些决策存储为浏览器cookie。如果没有用户定义的首选项,浏览器的默认语言将驱动应用程序中使用的区域设置。这适用于所有服务器端元素 现在我必须添加一些客户端脚本,我还需要使用一些本地化字符串。我必须承认,我不知道哪种方法是最好的 主要问题是: 我是否可以使用现有的文件资源/资源包 如果
.property
资源和资源束
本地化静态和动态字符串。在应用程序中,用户可以选择自己喜欢的语言,此决定当前存储在用户配置文档中;我还计划将这些决策存储为浏览器cookie。如果没有用户定义的首选项,浏览器的默认语言将驱动应用程序中使用的区域设置。这适用于所有服务器端元素
现在我必须添加一些客户端脚本,我还需要使用一些本地化字符串。我必须承认,我不知道哪种方法是最好的
主要问题是:
编辑:我考虑过使用,但我不知道如何实现这样一个自定义插件。我使用以下方法:我的所有客户端JavaScript(CSJS)库都存储为数据库设计中的文件资源(参考资料>文件)。在库的代码中,我使用类似EL的符号来标记可翻译部分,例如:
var text="#{TRLT.TextToTranslate}";
每当我想在XPage上使用库时,我不会直接在XPage的资源中引用它们,而是添加对“Helper XPage”(js.xsp)的引用:
PS:我不得不修改这里的代码,因为原始版本对我的通用框架有一些依赖,还有一些额外的缓存和错误处理。因此,我不能保证没有输入错误,但原则上它应该可以工作。另一种方法是直接在浏览器中读取资源包,并在需要时在JavaScript中引用它。因此,要回答您的主要问题:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.resources>
<xp:bundle
src="/labels_en.properties"
var="translations">
</xp:bundle>
</xp:this.resources>
<xp:this.afterRenderResponse><![CDATA[#{javascript:
try {
var externalContext = facesContext.getExternalContext();
var writer = facesContext.getResponseWriter();
var response = externalContext.getResponse();
response.setContentType("application/json");
var jsonOutput = {};
var keys = translations.keySet();
for (var key in keys) {
jsonOutput[key] = translations[key];
}
writer.write( "var translations = " + toJson(jsonOutput) ) ;
writer.endDocument();
} catch (e) {
print(e);
}
}]]>
</xp:this.afterRenderResponse>
</xp:view>
我认为最好的方式是Java方式。在CSJS中,您还可以插入ssjs以从支持的bean中获取标签,这可能对我的博客有所帮助。谢谢你的评论,@FrankvanderLinden。这似乎是维护这些资源的一个非常有用的方法,我将在接下来的几天更权威地阅读它。如果您需要帮助,请告诉我,您有我的博客;-)我使用以下方法:在我的CSJS库中,我使用类似EL的符号来标记可翻译部分,例如
var text=“#{TRLT.TextToTranslate}”代码>。我没有直接引用html头部中的库,而是引用一个行为类似于JavaScript资源(Content Type=text/JavaScript)的帮助器xpage(js.xsp)。这个XPage加载所有CSJS库,将它们连接起来,并用我也用于服务器端翻译的字典中的字符串替换可翻译部分。我可以发布一些代码,但我想对于您的问题有更简单的解决方案……这听起来很有趣。如果你不在乎伟大的东西,我很想看一些例子!关于内部属性格式还有一个问题:您是使用{“key”:“value”}中的JSON格式,还是引擎本身创建和维护的“key=value”中的XSP标准格式?没关系,我刚刚发现:您正在将标准的“key=value”格式转换为JSON对象,对吗?正确。您可以使用标准的key=value
格式;很难决定我应该接受两个相似的答案中的哪一个;我从上面的@MarkLeusink中选择了一个,因为它稍微simpler@LotharMueller:Mark Leusink的解决方案更易于实施,更适合您想要实现的目标。我不使用这种方法的原因是,我的翻译词典相当大(>5Mb),因为它们也包含HTML模板。在HTML页面上加载那么多内容会导致用户第一次访问页面时加载时间过长。如果您还忘记设置缓存控制头,那么每次用户加载页面时都会发生这种情况。当然,我可以为CSJS翻译创建一个额外的字典,但这使得维护起来更加困难
importPackage(java.io);
importPackage(java.lang);
importPackage(java.util.regex);
importPackage(javax.servlet.http);
importPackage(org.apache.commons.io); // AFAIK this package is not installed by default (but generally very helpful)
var i,arr,lng,js,libs,c,s,m,bfr,dct,response,ec,is,os;
//---------------------------- initialize main variables
ec=facesContext.getExternalContext(); // the external context
lng=(param.lng || "en"); // the language can be provided as url parameter, otherwise use a default
dct=(applicationScope["TRLT_"+lng] || {}); // in my case, the dictionaries (HashMaps) containing the translations are stored in the applicationScope, but of course they can be loaded from anywhere (resource bundles etc.)
libs=(param.libs ? fromJson(param.libs) : ["mylib1.js","mylib2.js"]) // the library names can be provided as url parameter, otherwise use a default
//---------------------------- concatenate all libraries
js=new StringBuilder();
for (i=0;i<libs.length;i++) {
if (s=IOUtils.toString(ec.getResourceAsStream(libs[i]),"UTF-8")) js.append("\n\n"+s);
}
js=js.toString();
//---------------------------- search for and replace translateable parts
m=Pattern.compile("[#$]\\{TRLT\\.([^}]+)\\}").matcher(js);
bfr=new StringBuffer();
c=0;
while (m.find() && c<1e6) {
c++;
s=m.group(1);
m.appendReplacement(bfr,dct[s] || s || "");
}
m.appendTail(bfr);
js=bfr.toString();
//---------------------------- create the response and finalize
response=ec.getResponse();
response.setHeader("Cache-Control","max-age="+(60*60*24*365).toFixed(0)); // its important to set the expiration "a bit" into the future to prevent the browser from reloading the js.xsp everytime you reference it on another XPage; in order to force the browser to update the XPage, use versioning (see url parameter "v" in the headTag definition above)
response.setDateHeader("Expires",new Date().getTime()+(1000*60*60*24*365));
response.setHeader("Content-Type","text/javascript; name=\"libs.js\"");
response.setHeader("Content-Disposition","inline; filename=\"libs.js\"");
is=new ByteArrayInputStream(js.getBytes("UTF-8"));
os=response.getOutputStream();
IOUtils.copy(is,os);
is.close();
os.close();
facesContext.responseComplete();
return;
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.resources>
<xp:bundle
src="/labels_en.properties"
var="translations">
</xp:bundle>
</xp:this.resources>
<xp:this.afterRenderResponse><![CDATA[#{javascript:
try {
var externalContext = facesContext.getExternalContext();
var writer = facesContext.getResponseWriter();
var response = externalContext.getResponse();
response.setContentType("application/json");
var jsonOutput = {};
var keys = translations.keySet();
for (var key in keys) {
jsonOutput[key] = translations[key];
}
writer.write( "var translations = " + toJson(jsonOutput) ) ;
writer.endDocument();
} catch (e) {
print(e);
}
}]]>
</xp:this.afterRenderResponse>
</xp:view>
<xp:this.resources>
<xp:bundle var="translations">
<xp:this.src><![CDATA[#{javascript:
var language = "en"; //default language
switch (context.getLocaleString() ) {
case "nl":
language = "nl";
break;
}
return "/labels_" + language + ".properties";}]]></xp:this.src>
</xp:bundle>
</xp:this.resources>