หน้าเว็บ

วันศุกร์ที่ 8 กุมภาพันธ์ พ.ศ. 2556

การเขียนเว็บ (JSF) ที่รองรับหลายภาษา : java


1. config default locale  และ  กำหนดที่อยู่ไฟล์ภาษา faces-config.xml   ในที่นี้ default locale คือ locale thai  และ ไฟล์ภาษาเก็บไว้ที่ classpath : locale/message*.properties
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.0"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

    <application>
        <locale-config>
            <default-locale>th_TH</default-locale>
        </locale-config>
        
        <resource-bundle>
            <base-name>locale.message</base-name>
            <var>message</var>
        </resource-bundle>
    </application>
</faces-config>
2. นำไฟล์ภาษา (.properties file)ไปวาง  ตามที่ config ไว้  ชื่อ file ภาษาขึ้นต้นด้วยชื่อตามที่ config ไว้  เช่น message  จากนั้น  ให้ตามด้วย _ locale code ของภาษานั้นๆ  เช่น ภาษาอังกฤษ _en  ภาษาไทย _th_TH  เป็นต้น

message_en.properties
#
welcome=learning change language in web application
#
message_th_TH.properties
#
welcome=เรียนรู้การเปลี่ยนภาษาในเว็บแอพพลิเคชัน
#
3. เขียน controller หรือ managed bean เพื่อ control การเปลี่ยนภาษา
LanguageMB.java
package com.blogspot.na5cent.internationalleaning.controllers;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

/**
 *
 * @author Redcrow
 */
@ManagedBean
@SessionScoped
public class LanguageMB implements Serializable {

    private static final Locale THAI_LOCALE = new Locale("th", "TH");
    //
    private String currentLocaleCode;
    private static Map<String, Locale> locales;

    static {
        locales = new HashMap<String, Locale>();
        locales.put("ภาษาไทย", THAI_LOCALE);
        locales.put("english language", Locale.ENGLISH);
    }

    @PostConstruct
    public void postConstruct() {
        currentLocaleCode = THAI_LOCALE.toString();
    }

    public void onChangeLanguage() {
        Locale currentLocale = THAI_LOCALE;
        for (Entry<String, Locale> entry : locales.entrySet()) {
            Locale locale = entry.getValue();
            if (locale.toString().equals(currentLocaleCode)) {
                currentLocale = locale;
                break;
            }
        }

        FacesContext.getCurrentInstance().getViewRoot().setLocale(currentLocale);
    }

    //getter and setter
    public void setCurrentLocaleCode(String currentLocaleCode) {
        this.currentLocaleCode = currentLocaleCode;
    }

    public String getCurrentLocaleCode() {
        return currentLocaleCode;
    }

    public Map<String, Locale> getLocales() {
        return locales;
    }
}

        อันนี้ผมทดลองเช็คดู status locale ปัจจุบันของ LanguageMB  ผ่านการ inject เข้ามาใน CurrentLocaleMB  เผื่อเราจะได้เอา locale นั้นไปทำอย่างอื่นด้วย
CurrentLocaleMB.java
package com.blogspot.na5cent.internationalleaning.controllers;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;

/**
 *
 * @author Redcrow
 */
@ManagedBean
@RequestScoped
public class CurrentLocaleMB {

    @ManagedProperty(value = "#{languageMB}")
    private LanguageMB languageMB;
    
    public String getLocale(){
        return languageMB.getCurrentLocaleCode();
    }

    public void setLanguageMB(LanguageMB languageMB) {
        this.languageMB = languageMB;
    }
}

4. เขียนส่วนของ view (html) ครับ  ซึ่งในที่นี้  เราจะครอบด้วย <f:view/>  เพื่อใช้สำหรับการกำหนด locale
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view locale="#{languageMB.currentLocaleCode}"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:p="http://primefaces.org/ui" 
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:f="http://java.sun.com/jsf/core">
    <html>
        <h:head>
            <title>international learning</title>
        </h:head>
        <h:body>
            <h:form>
                <h:outputText value="#{message.welcome}"/>
                <br/>
                <h:selectOneMenu value="#{languageMB.currentLocaleCode}">
                    <f:selectItems value="#{languageMB.locales}"
                                   var="locale"                                   
                                   itemLabel="#{locale}"
                                   itemValue="#{locale}"/>      
                    <p:ajax listener="#{languageMB.onChangeLanguage()}"
                            onsuccess="location.reload(true);"
                            event="change"/>
                </h:selectOneMenu>
            </h:form>
            
            <h:outputText value="current locale => #{currentLocaleMB.locale}"/>
        </h:body>
    </html>
</f:view>
5. ผลลัพธ์



7 ความคิดเห็น:

  1. สอบถามหน่อยครับ ตัว .properties นี้สามารถเขียนเป็นภาษาไทยได้ด้วยหรอครับ
    ผมใช้ eclipse เขียนนะครับ
    ไม่รู้ว่ามันเกี่ยวกันหรือเปล่านะ ..

    ตอบลบ
  2. ได้ครับ
    แล้วก็น่าจะได้ทุกภาษาน่ะครับ

    ตอบลบ
  3. ถ้าผมไม่ได้ใช้ JSF ละครับ
    พอที่จะมีแนวทางอื่น หรือว่าหลักการทำ Application 2 ภาษา
    เช่น ผมใช้ JSP + Servlet + Bean ธรรมดานะครับ
    ผมจะมีแนวทางการทำ app 2 ภาษาอย่างไรดีครับ

    ซึ่งส่วนนี้ผมกำลังศึกษาอยู่ครับ ว่าต้องทำอย่างไร
    ถ้ามีตัวอย่างก็จะดีเป็นอย่างยิ่งครับ
    ขอบคุณมากครับ

    ตอบลบ
  4. เขาใช้ Resource Bundle ครับ
    ประมาณนี้

    http://www.mytechnotes.biz/2012/11/introduction-to-java-internationalization.html

    แค่เราเปลี่ยน locale ให้ตรง เดี๋ยว resource bundle จะไปอ่านค่าจาก properties file นั้นๆ ตาม key ที่เราใส่ไป มาให้เองครับ

    ตอบลบ
  5. สอบถามเรื่องเกียวกับ Memory หน่อยครับ
    ถ้าทำ file properties แล้วใน file ก็มีขนาด ประมาณ 1 Mbs.
    ในการ Load แต่ละครั้งจะ ช้าหรือเปล่าครับ

    ตอบลบ
  6. ก็ไม่ช้าน่ะครับ เพราะตัว Properties file มัน extends มาจาก Hashtable ครับ
    load ครั้งเดียวตอนแรก ก็มีเปลือง memory อยู่บ้างครับ

    ตอบลบ