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