Java - 針對i18n多國語言的簡易範例實作

針對之前的FileTransferService加入了i18n多國語言部分的處理,只要編輯.properties並且針對裡面的key值作相對應的value設置,在執行FileTranserService-1.0.jar時指定System Properties的語言TAG名,如此就可以載入對應的.properties
針對FileTransferService project新增Message.java及MessageUtils.java在message package下,並且在這一層另新增msg folder,將.properties統一放置此處!

首先說明Message.java
  1. package message;
  2. public class Message {
  3. public static String INPUT_PATH;
  4. public static String INPUT_PATH_NONEXIST;
  5. public static String HELP_MESSSAGE;
  6. static {
  7. MessageUtils.initializeMessages("message", Message.class);
  8. }
  9. }
這支程式定義的變數名稱會與.properties的key相對應,也就是說在這邊新增一個變數,只要在.properties定義一樣名稱的key,那麼在其他程式只要呼叫Message.變數名,就可以取得.properties內key的設定value值,如此一來在呼叫方不用管load properties的行為,只要用就對了! 要注意的是首次呼叫Message.變數名時會呼叫MessageUtils.initializeMessages做初始化動作!

#message.properties內容
INPUT_PATH=Please specify path
INPUT_PATH_NONEXIST=The path non-exist
HELP_MESSSAGE=<<File Transfer Service>>\nStart client mode -> java ....

再來是MessageUtils.java
  1. package message;
  2. import java.lang.reflect.Field;
  3. import java.util.Locale;
  4. import java.util.Properties;
  5. public class MessageUtils {
  6. private static String MSG_FILE_PATH = "msg/%s.properties";
  7. private static String LOCALE_TAG;
  8. static {
  9. LOCALE_TAG = System.getProperty("LOCALE_TAG");
  10. LOCALE_TAG = LOCALE_TAG == null ? "en" : LOCALE_TAG;
  11. }
  12. public static void initializeMessages(String baseName, Class<?> clazz) {
  13. Field fieldArray[] = clazz.getDeclaredFields();
  14. baseName = LOCALE_TAG.equals(Locale.ENGLISH.toLanguageTag()) ? baseName : baseName + "_" + LOCALE_TAG;
  15. Properties props = new Properties();
  16. try {
  17. props.load(Message.class.getResourceAsStream(String.format(MSG_FILE_PATH, baseName)));
  18. } catch (Exception e) {
  19. // TODO Auto-generated catch block
  20. if(props.isEmpty()) {
  21. System.out.println("Cannot found "+baseName+".properties");
  22. }
  23. }
  24. for(Field field : fieldArray) {
  25. try {
  26. field.set(null, props.getOrDefault(field.getName(), ""));
  27. } catch (IllegalArgumentException e) {
  28. // TODO Auto-generated catch block
  29. e.printStackTrace();
  30. } catch (IllegalAccessException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. }
  35. }
  36. }
程式會先根據設定的LOCALE_TAG value來決定要載入哪個語言的.properties
因此要注意的是除了english以外,其他的.properties需要在檔名上設定好這個語言的TAG,如繁體中文是message_zh_TW.properties,tag名可以由Locale.TAIWAN.toLanguageTag()取得!

再來是initializeMessages function,它會載入Message.java指定的.properties,透過呼叫Message.class.getResourceAsStream這個function根據相對路徑找到.properties! 

最後就是呼叫Message.class.getDeclaredFields()取得Message.java宣告的static變數,再將每個變數set對應的.properties下的value值!

再來截一段Main.java使用的狀況
  1. public class Main {
  2. public static final int PORT = 5880;
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. if(args.length == 0) {
  6. System.out.println(Message.HELP_MESSSAGE);
  7. }else {
  8. if(args.length == 1) {
  9. System.out.println(Message.INPUT_PATH);
  10. }else {
  11. .....

喔對了,程式寫好後當然要再次打包成jar檔,在此說明如何修改pom.xml,目的是將msg/*.properties一起打包進message folder,前一篇針對輸出FileTransferService-1.0.jar有詳細說明pom.xml,在此則在此基底下定義resources tag
  1. <build>
  2. <sourceDirectory>${src.dir}</sourceDirectory>
  3. <resources>
  4. <resource>
  5. <directory>${src.dir}/message</directory>
  6. <includes>
  7. <include>msg/*</include>
  8. </includes>
  9. <targetPath>message</targetPath>
  10. </resource>
  11. </resources>
先根據哪個來源目錄,在此是src下的message,要copy進的檔案是什麼? 針對msg/*下所有的檔案,最後是target設在哪裡? 這邊是以target/classes這一層的相對位置,那就是在message目錄下啦!
PS. 如果不定義resources,那麼您將會看到message下只有包進編譯好的Message.class及MessageUtils.class

最後DEMO一下

留言