Fork me on GitHub

Programming Design Notes

ZK Internationalization and Localization (I18N)

| Comments

ZK 官方的 I18N 教學非常缺乏彈性。
網址: http://www.zkoss.org/smalltalks/i18n/i18n.dsp

官方的 I18N 教學是一個一個元件去設定語言,如果有一百個元件就會有一百行程式碼,所以另外想了一個方法去解決這個問題。

首先新增一個 package 為 com.blogspot.lawpronotes.controller,並制作一個 Controller,名命為 IndexController。

IndexController:
package com.blogspot.lawpronotes.controller;

import org.zkoss.zk.ui.util.GenericForwardComposer;

public class IndexController extends GenericForwardComposer {

private static final long serialVersionUID = 1L;

@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
}
}


在 / 制作一個 index.zul 頁面

index.zul:
<?page title="Auto Generated index.zul"?>
<zk>
<window title="i18n" border="normal" width="500px"
apply="com.blogspot.lawpronotes.controller.IndexController">
<panel>
<toolbar>
<button id="btnChinese" label="中文"/>
<button id="btnEnglish" label="English"/>
<button id="btnJapanese" label="日本語"/>
<button id="btnFrench" label="Français"/>
</toolbar>
<panelchildren>
<grid>
<rows>
<row>
<label id="lbUsername" />
<textbox id="txtUsername" type="text" width="98%" />
</row>
<row>
<label id="lbPassword" />
<textbox id="txtPassword" type="password" width="98%" />
</row>
<row>
<space />
<button id="btnSubmit" />
</row>
</rows>
</grid>
</panelchildren>
</panel>
</window>
</zk>

現在 index.zul 頁面的 Label 是沒有任何文字的,現在新增五個語言檔案,分別為 i3-label.properties、i3-label_en.properties、i3-label_fr.properties、i3-label_jp.properties 和 i3-label_zh.properties。全部的 properties 檔案都是放到 /WEB-INF 內

***ZK 的 properties 檔案是用 UTF-8 編碼。

i3-label.properties:
#index.zul

/index.zul/lbUsername=Username:
/index.zul/lbPassword=Password:
/index.zul/btnSubmit=Submit

i3-label_en.properties:
#index.zul

/index.zul/lbUsername=Username:
/index.zul/lbPassword=Password:
/index.zul/btnSubmit=Submit

i3-label_fr.properties:
#index.zul

/index.zul/lbUsername=Nom d'utilisateur:
/index.zul/lbPassword=Mot de passe:
/index.zul/btnSubmit=Soumettre

i3-label_jp.properties:
#index.zul

/index.zul/lbUsername=ユーザー名:
/index.zul/lbPassword=パスワード:
/index.zul/btnSubmit=登録

i3-label_zh.properties:
#index.zul

/index.zul/lbUsername=用戶名稱:
/index.zul/lbPassword=密碼:
/index.zul/btnSubmit=確定

properties 檔案內的 /index.zul 是元件的頁面位置和名稱,而 /lbUsername,/lbPassword 和 /btnSubmit 是元件的 ID,這樣確保了名稱不會相同。

現在有了語言檔,可以在 Controller 內讀取語言檔然後再加到元件上。
新增以下的方法到 IndexController 內。
@SuppressWarnings("unchecked")
private void setLanguage(Component rootComponent) {
List<Component> components = (List<Component>) rootComponent
.getChildren();
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
setComponentLanguage(component);
if (component.getChildren().size() > 0)
setLanguage(component);
}
}

private void setComponentLanguage(Component component) {
String path = component.getPage().getRequestPath();
String i18n = Labels.getLabel(path + "/" + component.getId());
if (i18n != null) {
if (component instanceof Label)
((Label) component).setValue(i18n);
else if (component instanceof Button)
((Button) component).setLabel(i18n);
}
}

private void changeLocale(String locale) {
Session session = Sessions.getCurrent();
Locale preferredLocale = Locales.getLocale(locale);
session.setAttribute(Attributes.PREFERRED_LOCALE, preferredLocale);
Locales.setThreadLocal(preferredLocale);
setLanguage(self);
}

而 doAfterCompose 方法則修改為以下這樣:
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
setLanguage(self);
}

現在可以試試打開 index.zul 頁面看看是不是自動加入了文字,成功應該會像以下這樣。


現在頁上的按鈕還沒有作用,可以加入以下的方法去令按鈕產生作用。
public void onClick$btnChinese(){
changeLocale("zh");
}

public void onClick$btnEnglish(){
changeLocale("en");
}

public void onClick$btnJapanese(){
changeLocale("jp");
}

public void onClick$btnFrench(){
changeLocale("fr");
}

完整的 IndexController:
package com.blogspot.lawpronotes.controller;

import java.util.List;
import java.util.Locale;

import org.zkoss.util.Locales;
import org.zkoss.util.resource.Labels;
import org.zkoss.web.Attributes;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.Sessions;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Label;
import org.zkoss.zul.Panel;

public class IndexController extends GenericForwardComposer {

private static final long serialVersionUID = 1L;

@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
setLanguage(self);
}

public void onClick$btnChinese(){
changeLocale("zh");
}

public void onClick$btnEnglish(){
changeLocale("en");
}

public void onClick$btnJapanese(){
changeLocale("jp");
}

public void onClick$btnFrench(){
changeLocale("fr");
}

@SuppressWarnings("unchecked")
private void setLanguage(Component rootComponent) {
List<Component> components = (List<Component>) rootComponent
.getChildren();
for (int i = 0; i < components.size(); i++) {
Component component = components.get(i);
setComponentLanguage(component);
if (component.getChildren().size() > 0)
setLanguage(component);
}
}

private void setComponentLanguage(Component component) {
String path = component.getPage().getRequestPath();
String i18n = Labels.getLabel(path + "/" + component.getId());
if (i18n != null) {
if (component instanceof Label)
((Label) component).setValue(i18n);
else if (component instanceof Button)
((Button) component).setLabel(i18n);
}
}

private void changeLocale(String locale) {
Session session = Sessions.getCurrent();
Locale preferredLocale = Locales.getLocale(locale);
session.setAttribute(Attributes.PREFERRED_LOCALE, preferredLocale);
Locales.setThreadLocal(preferredLocale);
setLanguage(self);
}
}

現在應該能夠立即轉換頁面語言了。





其實還有方法可令轉換語言更好,不用每一個 Controller 也有相同的方法,遲一點再補上來
ZK I18N Advanced

範例下載: i18n.7z (密碼:lawpronotes)

**因 ZK Library 太大,請自行加入 ZK 5.0.1 Library 到 /WEB-INF/lib 下。

相關書籍: ZK Developer's Guide: Developing responsive user interfaces for web applications using Ajax, XUL, and the open source ZK rich web client development frameworkZK: Ajax without the Javascript FrameworkHead First Java, 2nd Edition