首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 字串資源管理與多語言支援架構設計

     編輯:J2ME

前言

硬編碼字串散落代碼各處,維護困難且無法多語言。J2ME 無標準 ResourceBundle,需自行實現輕量級字串資源管理器。本文設計支援 **靜態存取、資源檔外部化、多語言熱切換、命名空間隔離** 的 StringManager。

設計目標

  1. 靜態方法全域存取:StringManager.get("MainMenu.Exit")
  2. 字串存於外部資源檔 (JAR 內),非硬編碼
  3. 語言切換:setLang("en") 即時生效
  4. 鍵名規範:類名.功能鍵 (如 GameCanvas.Score) 避免衝突
  5. 資源格式簡輕:純文本 key=value 或 key\tvalue,換行分隔

資源檔結構

/res/strings/
├── game.zh_TW   # 繁體中文
├── game.en      # 英文
└── game.ja      # 日文

檔案內容範例 (game.zh_TW):

MainMenu.Start    開始遊戲
MainMenu.Option   設定
MainMenu.Exit     離開
GameCanvas.Score  分數:
GameCanvas.Life   生命:
Alert.GameOver    遊戲結束
Alert.NewRecord   新紀錄!

分隔符支援 空格、\t、=,解析器自適應。

核心實現:StringManager

public class StringManager {
    private static StringManager instance; // 單例
    private String currentLang = "zh_TW";
    private String currentRes  = "game";
    private Hashtable table = new Hashtable();
    private boolean loaded = false;

    private StringManager(String lang) { this.currentLang = lang; }

    // 靜態工廠:取得單例並可切換語言
    public static StringManager getInstance(String lang) {
        if (instance == null) instance = new StringManager(lang);
        else if (!instance.currentLang.equals(lang)) instance.setLang(lang);
        return instance;
    }

    // 靜態快捷存取
    public static String get(String key) {
        return (instance != null) ? instance.getString(key) : key;
    }

    // 切換語言 (重置載入狀態)
    public void setLang(String lang) {
        if (!currentLang.equals(lang)) {
            currentLang = lang;
            loaded = false;
        }
    }

    // 載入指定資源檔
    public void load(String resName) {
        if (loaded && currentRes.equals(resName)) return;
        currentRes = resName;
        table.clear();

        InputStream is = getClass().getResourceAsStream("/res/strings/" + resName + "." + currentLang);
        if (is == null) { loaded = true; return; } // 找不到檔案靜默失敗

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = is.read(buf)) != -1) bos.write(buf, 0, len);
            String content = new String(bos.toByteArray()); // 資源檔存 UTF-16BE 可直接 new String(bytes)
            parseContent(content);
            loaded = true;
        } catch (IOException e) {
            System.err.println("Load strings failed: " + e);
        } finally {
            try { is.close(); } catch (IOException ignored) {}
        }
    }

    // 解析 key=value 格式
    private void parseContent(String content) {
        int i = 0, n = content.length();
        StringBuilder key = new StringBuilder();
        StringBuilder val = new StringBuilder();
        boolean readingKey = true;

        while (i < n) {
            char c = content.charAt(i++);
            if (readingKey) {
                if (c == ' ' || c == '\t' || c == '=') {
                    readingKey = false;
                } else {
                    key.append(c);
                }
            } else {
                if (c == '\n' || c == '\r') {
                    String k = key.toString().trim();
                    String v = val.toString().trim();
                    if (k.length() > 0) table.put(k, v);
                    key.setLength(0); val.setLength(0);
                    readingKey = true;
                } else {
                    val.append(c);
                }
            }
        }
        // 最後一行
        String k = key.toString().trim();
        String v = val.toString().trim();
        if (k.length() > 0) table.put(k, v);
    }

    public String getString(String key) {
        Object v = table.get(key);
        return (v != null) ? (String)v : key; // 找不到回傳鍵名,便於除錯
    }
}

使用範例

// MIDlet 啟動時初始化
StringManager.getInstance("zh_TW").load("game");

// 代碼中取用
String exitLabel = StringManager.get("MainMenu.Exit"); // → "離開"
String scoreFmt  = StringManager.get("GameCanvas.Score"); // → "分數:"

// 語言切換 (如選單選項)
public void switchLanguage(String lang) {
    StringManager.getInstance(lang).load("game");
    // 刷新當前顯示畫面
    currentDisplayable.repaint();
}

擴展建議

需求擴展方向
多資源檔同時載入Hashtable 單例管理多個 resource name
參數化字串 (printf)值存 "分數:%d",get(key, args...) 內部 String.format (MIDP 2.0) 或手工替換
複數形式支援引入 key[0] key[1] 區分單複數,或整合 ICU4J 輕量子集
資源檔加密/壓縮建構期預處理加密,載入時解密解壓
IDE 整合編寫 Eclipse 外掛/腳本:掃描代碼 StringManager.get() 自動同步資源檔鍵值

總結

StringManager 以 單例 + 靜態門面 + 純文本資源 + 簡易解析器 實現 J2ME 字串資源化與多語言。核心優勢:零依賴、記憶體佔用極低 (單語言約 2~5KB)、熱切換無需重啟。配合建構腳本自動提取鍵值,可構建專業級本地化流程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved