C++ Builder 本地化 (多语言) 功能

作者: 玄坴 | 来源:发表于2022-01-03 19:39 被阅读0次

    C++ Builder 参考手册本地化 (多语言) 功能


    本文介绍 C++ Builder 自带的本地化 (多语言) 功能

    1. C++ Builder 自带的多语言功能简介
      1.1. 实现多语言的方式
      1.2. 发现的问题
    2. 创建一个 VCL 项目,添加多语言功能
      2.1. 创建一个 VCL 项目
      2.2. 添加语言 (英语)
      2.3. 翻译语言 (中文到英语)
      2.4. 英语/中文界面测试
      2.5. 程序实现切换语言功能
      2.6. 在隐藏的控件里面做可以切换语言的字符串
      2.7. 在 .rc 文件里面做可以切换语言的字符串

    1. C++ Builder 自带的多语言功能简介

    这是 C++ Builder 自带的,也是 RAD Studio (包括 Delphi 和 C++ Builder) 自身的多语言实现的方式。

    1.1. 实现多语言的方式

    • 通过加载 dll 的方式切换语言,每种语言一个 dll,后缀名为语言的简称,例如 CHS, CHT, ENU 等
    • 通过 Resource DLL Wizard 添加和更新语言;
      Form 上的控件自动生成表格,只需要把标题或文字翻译成对应的语言;
      资源文件 (.rc 文件) 里面的字符串可以生成对应的翻译文字表格;
    • 通过修改注册表 HKEY_CURRENT_USER\Software\Embarcadero\Locales 里面的注册表项更换显示语言的 dll,注册表项为应用程序完整的路径和文件名 (注册表项为 Application->ExeName),注册表内容为语言简称,即与需要显示语言的 dll 后缀名相同,
      例如注册表项 "D:\Test\App.exe" 的值为 "ENU",那么运行 D:\Test\App.exe 时会加载 App.ENU 这个 dll 文件。

    1.2. 发现的问题

    • 主要是编译 .rc 文件的问题,不使用 .rc 文件不会出现 (Delphi 可以不使用 .rc 文件在资源里面添加字符串,所以问题主要出在 C++ Builder):
      由于 C++ Builder 编译 .rc 文件仍然采用古老的 Borland 编译器,即使是最新 11.0 版本,所以 .rc 文件只支持 ANSI 编码,只能用当前操作系统支持的语言的 ANSI 字符集,如果遇到外国字符或其他 UNICODE 符号就会无法编译,.rc 保存为 UTF-8 编码也会无法编译,对于多语言来说是个严重的障碍;
      如果把 .rc 文件的编译器切换到 Windows SDK Resource Compiler,虽然可以编译 UTF-8 编码的 .rc 文件了,支持 UNICODE 了,但是 Resource DLL Wizard 多语言向导会工作异常,无法正确处理 .rc 文件里面的字符串。
      所以建议在 Form 上放置一个隐藏的 Panel,把要翻译的字符串通过 Label 控件放在隐藏的 Panel 里面,因为 Form 里面控件的文字始终能够正常翻译,也支持 UNICODE。
    • 切换语言必须通过修改注册表,而且必须是固定的 Embarcadero\Locales 注册表位置,修改完注册表需要退出重新运行才能生效,没发现立即生效的方法;
    • 顺便说一下 Delphi,文档说的是使用 resourcestring 关键字,把字符串放在资源里面,而在 C++ 里面可以用 System::LoadResourceString 读取 Delphi 资源 resourcestring 关键字里面的字符串。

    2. 创建一个 VCL 项目,添加多语言功能

    2.1. 创建一个 VCL 项目

    选择菜单 File -- New -- Windows VCL Application - C++ Builder 创建一个新的 VCL 项目,然后添加几个控件,用于测试多语言功能:

    新创建一个 VCL 项目

    把这个项目保存到新创建的项目文件夹里面,项目名称为 TestLocalization:

    新创建的 VCL 项目文件

    2.2. 添加语言 (英语)

    • 要求在添加语言之前,必须先把程序编译通过,那么先编译这个新创建的应用程序,无论是 Alt-F9 编译,还是直接 F9 运行,还是其他方法,只要生成了 exe 就说明编译通过了。
    • 选择菜单 Project -- Languages -- Add...
      也可以选择菜单 File -- New -- Other,左面点选 C++ Builder 大类,然后右面选择 Resource DLL Wizard
    Project -- Languages -- Add... Add Languages

    选择添加语言的项目,默认就是当前的项目,基础语言 (Base Language) 为当前操作系统默认的语言 0804 就是简体中文,这是应用程序自身的语言 (可以点击选择更换基础语言),直接点击 "Next >" 按钮进行下一步:

    选择多语言支持的语言

    选择多语言支持的语言,可以多选,每个语言将生成一个对应的 dll 项目,可以编译为 dll 语言 (资源) 文件,Local ID 为语言的 LCID,Extension 为语言文件的后缀,美国英语对应的是 .ENU 后缀名。选择语言之后,点击 "Next >" 按钮进行下一步:

    生成的项目文件存放位置

    这是项目文件存放位置,可以点击 Path 栏里面的路径更改保存位置,默认就在要添加语言项目的文件夹里面,创建语言后缀名相同的名称的文件夹里面,点击 "Next >" 按钮继续:

    创建新的语言项目

    这是语言的状态,"英语 (美国)" 的状态为 "Create New"
    点击 "Next >" 继续:

    添加新的语言
    • Skip DRC files that are not found: 跳过找不到的 DRC (Delphi Resource String File) 文件
    • Show statistics when done: 结束时显示总结。

    点击 "Finish" 结束添加语言。

    是否重新编译

    提示 Resource DLL Wizard 需要重新编译项目,选择 "Yes"

    添加语言结束

    添加语言结束:

    新增了一个 TestLocalization.ENU 项目

    可以看到新增了一个 TestLocalization.ENU 项目,这个项目可以编译生成 TestLocalization.ENU 文件,在 exe 相同文件夹里面,是美国英语的资源文件。

    这时候,项目组 ProjectGroup1 也需要保存,如下截图:

    项目组

    选择 File - Save All 保存所有文件,或者点击工具栏上的 "Save All" 按钮:

    Save All - 保存所有文件

    将提示把项目组文件存盘,例如保存为 Localization.groupproj

    把项目组文件存盘

    以后再打开这个项目组文件,就会同事打开项目文件和所有的语言翻译 dll 项目

    项目组

    2.3. 翻译语言 (中文到英语)

    双击英文翻译项目 TestLocalization.ENU 里面的 Unit1.dfm

    翻译语言

    打开的不是 Form 画面设计,而是这个 Form 的翻译,这里只需要翻译一些控件的标题或文字,如上截图的画圈部分:

    翻译

    可以看到,在 "英语 (美国)" 栏里面翻译了的项目,Status 栏自动变成了 Translated,表示 "已经翻译",而其他没有翻译的,是 Untranslated 即 "没翻译",那些项目也不需要翻译。

    保存翻译

    点击翻译表格左上角的保存按钮,把翻译内容存盘,如上截图画圈的按钮位置。

    编译语言项目:

    编译 TestLocalization.

    在 TestLocalization.ENU 项目点击右键,选择 Make,或者选择菜单 Project - Make all projects 编译所有项目。

    会在 TestLocalization.exe 相同文件夹里面生成 TestLocalization.ENU 文件,即为英语资源文件。

    2.4. 英语/中文界面测试

    直接运行项目,和添加语言之前没有区别,是设计时的中文界面:

    直接运行:中文界面

    选择菜单:Project -- Languages -- Set Active...

    剪貼簿23.png 选择 "英语 (美国)"

    选择 "英语 (美国)",然后点击 "Finish" 按钮。

    再运行程序,就变成英文界面了:

    运行:英文界面

    这里 "中文" 按钮在语言翻译表格里面没有翻译为英文,所以切换到英文界面也是 "中文",这有助于切换到一个陌生的语言再切换回去。

    如果要切换到中文界面,再选择一次菜单:Project -- Languages -- Set Active... ,选择 "中文 (简体,中国)" 就可以了。

    2.5. 程序实现切换语言功能

    前面内容演示了如何测试多语言界面,但是程序发布的时候,要在程序里面切换语言,而不是在编译器里面切换。

    这个演示程序里面:Button1 是 "English",Button2 是 "中文",现在实现这两个按钮的功能。

    由于需要修改注册表,所以加入了头文件 #include <System.Win.Registry.hpp>

    #include <System.Win.Registry.hpp>
    

    注册表位置:HKEY_CURRENT_USER\Software\Embarcadero\Locales
    注册表项:应用程序的完整路径和文件名,即 Application->ExeName
    如果注册表项的值为 "ENU",程序运行时会加载与 exe 文件同名的后缀为 .ENU 的资源 dll 文件;把注册表项的值改为 CHS,即简体中文,应用程序运行时找不到后缀为 .CHS 的资源文件,就不加载资源文件了,使用设计界面时的默认文字,即简体中文。

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"ENU");
        reg->CloseKey();
        delete reg;
        ShowMessage(L"语言已经更改,关闭程序重新运行将使用更改之后的语言。");
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"CHS");
        reg->CloseKey();
        delete reg;
        ShowMessage(L"语言已经更改,关闭程序重新运行将使用更改之后的语言。");
    }
    

    更改语言,即修改注册表项之后,需要退出重新运行,才能生效。

    由于修改了程序,所以要更新语言翻译的项目,才能在切换到非默认的语言里面生效:选择菜单 project -- Languages -- Update Localized Projects 更新本地化项目:

    更新本地化项目

    选择之后,即没有成功的提示,也没有失败的提示,就是没有问题了,然后要重新编译所有的项目:选择菜单 Project -- Make All Projects
    这样修改程序在所有的语言都生效了。

    例如运行在英文界面,点击 "中文" 按钮,有如下提示:

    在英文界面,点击 "中文"

    退出、重新运行:

    切换到了中文界面

    2.6. 在隐藏的控件里面做可以切换语言的字符串

    由于刚才的例子,在 C++ 代码里面有字符串:

    ShowMessage(L"语言已经更改,关闭程序重新运行将使用更改之后的语言。");
    

    这样的字符串不能被语言翻译向导收录并自动切换语言,而需要想其他办法,用隐藏的控件的文字来翻译 (例如 Label 的 Caption 属性) 就是一个办法。如果要翻译的文字很多,可以把所有这些 Label 放在一个 Panel 里面,Panel 隐藏 (Visible 属性设为 false)。

    Label3 放在隐藏的 Panel1 里面

    以上截图:Panel1 的 Visible 属性设为 false 专门用来放翻译用的字符串的,里面的 Label3 的 Caption 设为 ShowMessage 的提示信息。

    ShowMessage(L"语言已经更改,关闭程序重新运行将使用更改之后的语言。");
    改为 ShowMessage(Label3->Caption);
    就可以应用翻译了。

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"ENU");
        reg->CloseKey();
        delete reg;
        ShowMessage(Label3->Caption); // L"语言已经更改,关闭程序重新运行将使用更改之后的语言。"
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"CHS");
        reg->CloseKey();
        delete reg;
        ShowMessage(Label3->Caption); // L"语言已经更改,关闭程序重新运行将使用更改之后的语言。"
    }
    

    由于更改了程序,仍然需要

    • 选择菜单 project -- Languages -- Update Localized Projects 更新本地化项目,
    • 然后双击英文翻译项目 TestLocalization.ENU 里面的 Unit1.dfm 打开翻译表格,
    • 找到表格里面的 Label3 的 Caption 属性,翻译为英语:
    翻译 Label3->Caption
    • 要重新编译所有的项目:选择菜单 Project -- Make All Projects
      这样修改程序在所有的语言都生效了。
    英文效果 中文效果

    2.7. 在 .rc 文件里面做可以切换语言的字符串

    在项目里面添加 TestLocalization_res.rc 文件

    在项目里面添加一个 TestLocalization_res.rc 文件,内容如下:

    STRINGTABLE
    BEGIN
      101 "语言已经更改,关闭程序重新运行将使用更改之后的语言。"
    END
    

    这是 ID 为 101 的字符串内容

    由于更改了程序,仍然需要

    选择菜单 project -- Languages -- Update Localized Projects 更新本地化项目

    剪貼簿34.png

    更新之后,在语言项目里面也会增加一个 TestLocalization_res.rc 文件,双击这个文件,出现的是翻译表格。

    翻译、存盘

    仍然是把 "英语 (美国)" 栏的内容翻译之后,点击表格左上角的存盘按钮保存。

    ShowMessage(L"语言已经更改,关闭程序重新运行将使用更改之后的语言。");
    改为 ShowMessage(LoadStr(101)); 即使用 ID 为 101 的字符串

    要重新编译所有的项目:选择菜单 Project -- Make All Projects
    这样修改程序在所有的语言都生效了。

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"ENU");
        reg->CloseKey();
        delete reg;
        ShowMessage(LoadStr(101)); // Label3->Caption // L"语言已经更改,关闭程序重新运行将使用更改之后的语言。"
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
        TRegistry *reg = new TRegistry;
        reg->RootKey = HKEY_CURRENT_USER;
        reg->OpenKey(L"Software\\Embarcadero\\Locales", true);
        reg->WriteString(Application->ExeName, L"CHS");
        reg->CloseKey();
        delete reg;
        ShowMessage(LoadStr(101)); // Label3->Caption // L"语言已经更改,关闭程序重新运行将使用更改之后的语言。"
    }
    
    运行:英文界面 运行:中文界面

    相关:


    C++ Builder 参考手册本地化 (多语言) 功能

    相关文章

      网友评论

        本文标题:C++ Builder 本地化 (多语言) 功能

        本文链接:https://www.haomeiwen.com/subject/hiwcxrtx.html