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

VC++ 多語言介面支援輕量級方案:INI 配置 + 控制項 ID 映射自動載入

     編輯:VC 教學

設計目標

  • 零程式碼修改新增語言:僅增減 INI 檔
  • 零硬編碼控制項 ID:自動遍歷視窗控制項
  • 輕量、無第三方依賴、易維護

核心設計:INI 結構 = 控制項 ID → 顯示文字

[Login Dialog]
1001 = 用戶帳號
1002 = 用戶密碼
1017 = 登  錄
1018 = 退  出

[Main Window]
1001 = 檔案(&F)
1002 = 編輯(&E)
1003 = 視圖(&V)
...
  • Section = 視窗/對話方塊識別
  • Key = 控制項 ID (整數,對應 GetDlgCtrlID())
  • Value = 該語言下的顯示文字

語言管理類實作

class CLanguageManager {
    struct ItemContext {
        UINT uCtrlID;
        CString strText;
    };
    vector m_vItems; // 所有語言項

    CIniFile m_ini; // 簡易 INI 讀取類

public:
    BOOL Load(LPCTSTR iniPath, LPCTSTR section) {
        m_ini.SetFile(iniPath);
        CStringArray keys, values;
        if (!m_ini.GetSectionValues(section, keys, values)) return FALSE;
        
        m_vItems.clear();
        for (int i = 0; i < keys.GetSize(); ++i) {
            ItemContext ctx;
            ctx.uCtrlID = _ttoi(keys[i]);
            ctx.strText = values[i];
            m_vItems.push_back(ctx);
        }
        return TRUE;
    }

    BOOL ApplyToWindow(CWnd* pWnd) {
        if (!pWnd) return FALSE;
        
        // 1. 視窗標題
        UINT id = pWnd->GetDlgCtrlID();
        SetControlText(pWnd, id);
        
        // 2. 遞迴所有子控制項
        CWnd* pChild = pWnd->GetWindow(GW_CHILD);
        while (pChild) {
            id = pChild->GetDlgCtrlID();
            SetControlText(pChild, id);
            pChild = pChild->GetNextWindow(GW_HWNDNEXT);
        }
        return TRUE;
    }

private:
    void SetControlText(CWnd* pCtrl, UINT ctrlID) {
        for (const auto& item : m_vItems) {
            if (item.uCtrlID == ctrlID) {
                pCtrl->SetWindowText(item.strText);
                break;
            }
        }
    }
};

簡易 INI 讀取類 (無 API 依賴)

class CIniFile {
    CStringArray m_lines;
    CString m_path;
public:
    void SetFile(LPCTSTR path) { m_path = path; Load(); }
    
    BOOL GetSectionValues(LPCTSTR section, CStringArray& keys, CStringArray& values) {
        keys.RemoveAll(); values.RemoveAll();
        BOOL bInSection = FALSE;
        
        for (int i = 0; i < m_lines.GetSize(); ++i) {
            CString line = m_lines[i];
            line.Trim();
            if (line.IsEmpty() || line.Left(2) == _T("//")) continue;
            
            if (line[0] == _T('[')) {
                int end = line.Find(_T(']'));
                if (end > 0) {
                    CString sec = line.Mid(1, end-1); sec.Trim();
                    bInSection = (sec.CompareNoCase(section) == 0);
                }
                continue;
            }
            
            if (!bInSection) continue;
            
            int eq = line.Find(_T('='));
            if (eq > 0) {
                CString key = line.Left(eq); key.Trim();
                CString val = line.Mid(eq+1); val.Trim();
                keys.Add(key); values.Add(val);
            }
        }
        return keys.GetSize() > 0;
    }

private:
    void Load() {
        m_lines.RemoveAll();
        CStdioFile file;
        if (!file.Open(m_path, CFile::modeRead | CFile::typeText)) return;
        CString line;
        while (file.ReadString(line)) m_lines.Add(line);
        file.Close();
    }
};

使用範例

// 應用程式啟動時
CLanguageManager g_langMgr;

BOOL CMyApp::InitInstance() {
    // 載入預設語言 (可從註冊表讀取上次選擇)
    g_langMgr.Load(_T("lang_chs.ini"), _T("Login Dialog"));
    g_langMgr.Load(_T("lang_chs.ini"), _T("Main Window")); // 累加多 Section
    // ...
}

// 視窗建立後套用
void CLoginDlg::OnInitDialog() {
    CDialog::OnInitDialog();
    g_langMgr.ApplyToWindow(this);
}

// 切換語言
void CMainFrame::OnLanguageChinese() {
    g_langMgr.Load(_T("lang_chs.ini"), _T("Login Dialog"));
    g_langMgr.Load(_T("lang_chs.ini"), _T("Main Window"));
    g_langMgr.ApplyToWindow(this); // 主視窗
    g_langMgr.ApplyToWindow(m_pLoginDlg); // 模態對話方塊需單獨套用
}

優缺點分析

優點缺點
極簡部署:文字檔即語言包不支援複雜格式 (複數、性別、語序調整)
無需重新編譯新增語言控制項 ID 衝突風險 (同 ID 不同視窗需不同 Section 隔離)
執行時動態切換不支援右-to-左 (RTL) 語言佈局反轉
零第三方庫依賴大型專案項目多時 INI 檔維護成本高

進階擴充建議

  • Section 命名規範:[ClassName::DialogID] 如 [CLoginDlg::IDD_LOGIN]
  • 語言列舉:掃描目錄 lang_*.ini 自動建構語言選單
  • 編輯器工具:開發小工具載入所有 INI 對比缺漏 Key,支援 Excel 匯入匯出
  • 遷移至 XML/JSON:結構化支援巢狀、屬性、陣列,適合大型專案

此方案以 INI + 控制項 ID 映射 + 自動遍歷 三大核心,以最小代價實現多語言支援,極適合中小型 VC++ 專案快速落地國際化。

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