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

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 参考手册本地化 (多语言) 功能

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容