一、前言
在 Chromium 内核开发过程中,国际化字符串的加载与 WebUI 内置页面的展示,是两个经常被提及但又容易被忽视的核心环节。
- 
一方面,GRIT(Google Resource and Internationalization Tool)承担了整个字符串资源编译、打包和加载的任务,它决定了开发者在 C++ 代码或者 WebUI 前端中看到的
IDS_XXX字符串是如何被替换成实际文字的。 - 
另一方面,WebUI 内置页(如
chrome://settings/、chrome://newtab/)的展示机制,涉及到 C++ 后端和前端 HTML/JS 的对接,GRIT 中的资源如何最终呈现在用户眼前,也是一个完整的链路。 
本篇文章将深入剖析 GRIT 的编译链路、运行时加载机制、多语言切换原理、资源 ID 分配 ,再结合 WebUI 内置页的对接机制,展示一个完整的前端展示流程。
阅读完这篇文章,你将能够回答:
- 
.grd文件和.xtb文件有什么区别? - 
.grd如何编译成.pak文件,运行时又如何被加载? - 
多语言切换的机制是怎样的?
 - 
WebUI 内置页如何与这些资源对接?
 - 
一个完整的字符串从 定义 → 编译 → 加载 → 前端展示 的链路是什么?
 
二、GRIT 资源体系介绍
1. 什么是 GRIT
GRIT,全称 Google Resource and Internationalization Tool,是 Chromium 用来管理字符串、图片、图标等 UI 资源的工具。它的主要职责是:
- 
资源定义 :通过
.grd文件声明一组资源(通常是字符串)。 - 
国际化支持 :通过
.xtb文件为不同语言提供翻译。 - 
资源编译 :在构建过程中生成
.h头文件和.pak打包文件。 - 
运行时加载 :通过
ui::ResourceBundle和l10n_utilAPI 在代码中加载资源。 
2. .grd 文件
.grd 文件是资源的"清单文件",开发者在其中定义需要本地化的字符串,例如:
<message name="IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY" desc="Balloon content"> <ph name="APP_NAME">$1<ex>Background App</ex></ph> will launch at system startup and continue to run in the background even once you've closed all other <ph name="PRODUCT_NAME">$2<ex>Google Chrome</ex></ph> windows. </message> 
        特点:
- 
name定义了字符串 ID(如IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY)。 - 
desc用于描述字符串用途,方便翻译。 - 
<ph>表示参数占位符。 
3. .xtb 文件
.xtb 文件是 翻译文件 ,用于为 .grd 中的字符串提供多语言版本。
例如 en-US.xtb、zh-CN.xtb,它们内部存放着 <translation> 节点,对应不同语言的翻译。
4. .pak 文件
在编译阶段,GRIT 工具会把 .grd + .xtb 合并,最终生成 .pak 文件。
.pak 文件是一个二进制资源包,存放了 ID → 文本 的映射关系。
例如:
IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY (id=12345)→"某某应用将在系统启动时运行"
三、GRIT 的编译流程
我们来看字符串是如何从 .grd 最终进入到 .pak 的。
1. .grd → .h
在 GN 构建过程中,.grd 文件会通过 grit.py 工具转换成 C++ 头文件,生成的 .h 文件包含一系列 #define 宏:
#define IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY 12345 
        这样,C++ 代码中使用 IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY 时,实际上就是在使用 整型 ID。
2. .grd + .xtb → .pak
构建时,GRIT 工具会:
- 
读取
.grd中定义的 ID。 - 
根据语言选择,加载对应
.xtb文件翻译。 - 
生成
.pak文件,将 ID 和对应的翻译文本打包进去。 
例如:
pak 文件 ├── 12345 → "应用将在系统启动时运行" (中文) ├── 12345 → "The app will launch at system startup" (英文) 
        3. .pak 文件的安装位置
不同平台下,Chromium 会把 .pak 文件放在:
- 
Windows:
chrome.pak/resources.pak - 
Linux:
out/Default/locales/zh-CN.pak - 
macOS:
Chromium.app/Contents/Resources/zh-CN.pak 
四、运行时加载机制
1. ui::ResourceBundle
运行时,Chromium 通过 ui::ResourceBundle 加载 .pak 文件。
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); rb.AddDataPackFromPath(locale_path, ui::SCALE_FACTOR_NONE); 
        - 
AddDataPackFromPath会把.pak文件加载到内存。 - 
内部使用一个
ResourceMap存放 ID → 文本的映射。 
2. l10n_util API
开发者在 C++ 代码中使用 l10n_util::GetStringUTF16(id) 来获取字符串:
base::string16 text = l10n_util::GetStringUTF16( IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY); 
        流程是:
- 
GetStringUTF16→ 查询ui::ResourceBundle→ 找到 ID 对应的文本。 - 
返回
std::u16string,供 UI 展示。 
3. 多语言切换
Chromium 的多语言切换依赖 Locale ,即系统语言或者浏览器启动参数:--lang=zh-CN 
- 
启动时,
ResourceBundle::InitSharedInstanceWithLocale会选择对应语言的.pak文件。 - 
当用户在设置里切换语言时,浏览器需要重启,重新加载另一套
.pak。 
4. 资源 ID 的编译期分配
值得注意的是,ID 是在编译期固定的整数。
例如:
#define IDS_HELLO_WORLD 6001 
        无论语言怎么切换,IDS_HELLO_WORLD 始终是 6001,只有 .pak 文件里绑定的翻译会变化。
五、WebUI 内置页的前端对接
字符串加载只是第一步,最终还需要在 WebUI 页里展示。
1. 内置页 WebUI 概念
- 
内置页的访问方式是
chrome://xxx/。 - 
底层由
WebUIController负责加载页面。 - 
前端通常是 HTML + JS + CSS,存放在
resources/目录。 
2. 字符串注入
C++ 后端会把 .pak 中的字符串传递给前端。常见方式是 LoadTimeData。
webui::LocalizedString localized_strings[] = { {"appInstalledBalloonBody", IDS_BACKGROUND_APP_INSTALLED_BALLOON_BODY}, }; AddLocalizedStrings(source, localized_strings); 
        这样,前端 HTML 就能通过:
const text = loadTimeData.getString('appInstalledBalloonBody'); 
        拿到对应的字符串。
3. 资源绑定流程
整体链路如下:
- 
.grd定义字符串。 - 
编译生成
.pak。 - 
运行时
ResourceBundle加载.pak。 - 
WebUIDataSource→AddLocalizedStrings注入到前端。 - 
前端
loadTimeData.getString()使用。 
4. 实际案例
比如 新标签页(New Tab Page, NTP):
- 
C++ 端:
source->AddLocalizedString("title", IDS_NEW_TAB_TITLE); - 
前端端:
<h1 id="title"></h1> <script> document.getElementById("title").textContent = loadTimeData.getString('title'); </script> 
这样,最终 <h1> 会显示 "新标签页" 或 "New Tab"。
六、GRIT + WebUI 的完整链路
结合上面的分析,我们得到一个完整链路:
- 
开发者定义
.grd文件中声明字符串 ID。
 - 
构建编译
- 
.grd生成.h,定义整数 ID。 - 
.xtb翻译合并,生成.pak。 
 - 
 - 
运行时加载
- 
ResourceBundle加载.pak。 - 
l10n_util根据 ID 获取字符串。 
 - 
 - 
WebUI 注入
- 
C++ 后端使用
AddLocalizedStrings注入前端。 - 
前端用
loadTimeData获取并展示。 
 - 
 
七、对比总结
| 阶段 | 输入 | 输出 | 工具/接口 | 
|---|---|---|---|
| 编译前 | .grd / .xtb | 
.h / .pak | 
grit.py | 
| 编译后 | .pak | 
ID → 文本 | ResourceBundle | 
| 运行时 | ID | 文本 | l10n_util::GetStringUTF16 | 
| WebUI | 文本 | 页面展示 | loadTimeData.getString | 
八、结语
GRIT 与 WebUI 的结合,是 Chromium 国际化 + 内置页面展示 的关键路径。
- 
.grd文件解决了资源声明与 ID 分配; - 
.xtb文件提供了多语言翻译支持; - 
.pak文件把不同语言打包成可分发资源; - 
ui::ResourceBundle在运行时统一加载; - 
WebUI 内置页通过
AddLocalizedStrings与loadTimeData实现最终展示。 
掌握这条链路后,你不仅能理解 字符串是如何出现在页面上的,还能在调试 WebUI 内置页时快速定位问题(如字符串丢失、多语言未生效等)。