不可否认,Chrome的国际化做的非常优秀,在Chrome中添加一种新的语言支持非常方便。
http://www.chromium.org/developers/design-documents/ui-localization
如果使用virtual studio 2008打开chrome for windows的工程,可以看到如下的项目:
其中每一个项目对应一种语言支持,所以如果需要添加新的语言支持,只需要新建一个新的语言项目。
实际上,每一个语言项目内的所有文件都是编译生成的中间文件,在文件夹【src\chrome\app\locales】中存放了这所有的项目文件,但每一个项目仅仅存在一个vcproj文件,例如zh-CN.vcproj,项目中包含的文件实际存在于【src\chrome\Debug/Release\grit_derived_sources】目录下。那这些文件怎么生成的呢,这需要了解一下google自己开发的一个python项目。
该项目的源码在目录【src\tools\grit】下,全部使用python语言。该目录下的readme是这么说的:
GRIT (Google Resource and Internationalization Tool) is a tool for Windows projects to manage resources and simplify the localization workflow. |
在命令行输入命令【python grit.py】(该文件是整个grit的入口)有如下输出
GRIT - the Google Resource and Internationalization Tool Copyright (c) Google Inc. 2009 Usage: grit [GLOBALOPTIONS] TOOL [args to tool] Global options: -i INPUT Specifies the INPUT file to use (a .grd file). If this is not specified, GRIT will look for the environment variable GRIT_INPUT. If it is not present either, GRIT will try to find an input file named 'resource.grd' in the current working directory. -v Print more verbose runtime information. -x Print extremely verbose runtime information. Implies -v -p FNAME Specifies that GRIT should profile its execution and output the results to the file FNAME. Tools: TOOL can be one of the following: build A tool that builds RC files for compilation. newgrd Create a new empty .grd file. rc2grd A tool for converting .rc source files to .grd files. transl2tc Import existing translations in RC format into the TC sdiff View differences without regard for translateable portions. resize Generate a file where you can resize a given dialog. unit Use this tool to run all the unit tests for GRIT. count Exports all translateable messages into an XMB file. For more information on how to use a particular tool, and the specific arguments you can send to that tool, execute 'grit help TOOL' |
有兴趣可以研究一下代码,python还是很有趣的东东!!!
grit接收一个输入文件,然后生成项目所需的.h和.rc等文件。当然输出什么文件需要用户在输入文件中指定。
grit接收grd类型的文件作为输入,然后根据输入文件中的指定输出匹配的文件。locale相关的输入文件存放在目录【src\chrome\app\resources】下,最关键的几个文件是【locale_settings.grd】和【generated_resources.grd】(此文件放在目录src\chrome\app下,个人觉得放那很诡异)。在chrome中有若干项目仅仅包含grd文件并将其生成目标文件,而其他一些项目则依赖这些文件。chrome_strings项目就如此。它就将相关的grd文件生成locale下各种语言项目依赖的.h和.rc文件。
所有grd文件都是一个xml文件,格式都符合grit的一个规范,下面是【generated_resources.grd】的部分内容:
DE<<?xml version="1.0" encoding="UTF-8"?> |
说明:
Output节表示输出文件,例如上面的文件会生成一个 generated_resources.h、若干rc文件(generated_resources_zh-CN.rc)和若干pak文件(generated_resources_zh-CN.pak)。
Translations节表示翻译文件,一般来说每一种支持的语言都应该有一个翻译文件。
Messages节表示定义的默认字符串(不同的grd文件有不同的作用,其他文件的message节里面的内容不一定是字符串,也可能是其他类型。),
当grit解析收到locate 相关的grd文件时,首先生成默认的资源文件,这里默认的资源文件是“en-US”。当发现Output节有其他语言的输出时,则查找对应的xtb翻译文件,如果grd文件中的message选项指定需要翻译,则通过message中的name属性查找xtb中对应的record,然后将替换之。
在grd文件中有很多可选的选项,具体可以参考chrome自带的grd文件或者grit源代码。目前本人未找到google官方的帮助文档。
Xtb文件也是一个xml文件,典型的内容格式如下:
DE<<?xml version="1.0" ?> |
DE<<?xml version="1.0" ?> |
两者区别主要是ID的表示方式。后者ID和grd中的name是一致的,而前者则通过某种算法将grd中的name转换为由数字组成的ID。
chrome通过添加“自定义编译规则(Custom Build Rules)”来通过vs2008自动编译所有自定义格式文件。例如grd文件的规则如下:
如图所示,grd使用一个bat文件编译,并且提供两个参数。正如前面提到的,第二个参数就是目标文件的输出路径。
该bat文件的内容如下:
:: Batch file run as build command for .grd files :: The custom build rule is set to expect (inputfile).h and (inputfile).rc :: our grd files must generate files with the same basename. @echo off setlocal … 忽略 … :: Put cygwin in the path call %SolutionDir%\..\third_party\cygwin\setup_env.bat %SolutionDir%\..\third_party\python_24\python.exe %SolutionDir%\..\tools\grit\grit.py -i %InFile% build -o %OutDir% %PreProc1% %PreProc2% %PreProc3% %PreProc4% %PreProc5 |
从上面内容可以发现,chrome将python解释器直接放到源码【src\third_party\python_24】里。然后通过它调用grit.py文件实现文件的编译。
关于grd的自定义编译规则文件可以查看文件【src\tools\grit\build\grit_resources.rules】。 msdn上【http://msdn.microsoft.com/en-us/library/03t8bzzy.aspx 】也许有些帮助。
当通过grd文件生成locale下语言项目依赖的文件后,Chrome将这些项目打包生成一个语言Dll,这些Dll可以在目录【src\chrome\Debug/Release\locales】下找到。当Chrome启动时,它会通过某种途径查找locale类型,然后找到对应的Dll来load。
Chrome查找locale类型通过【src\chrome\common\l10n_util.h】的GetApplicationLocale函数实现。
该函数首先检查命令行有没有通过“--lang”指定locale,如果没有,则检查当前的配置文件中是否指定locale。如果未指定,则获取操作系统的locale,如果再获取失败,则使用默认的en-US。当然在返回之前,Chrome总会检查当前的语言文件目录是否存在该语言的Dll。
chrome自己弄了一套本地配置系统,下面是一个典型的配置文件格式,内容为语言选项
{ "intl": { "app_locale": "zh-CN" } } |
当找到locale后,chrome通过【src\chrome\common\resource_bundle_win.cc】中的LoadResources函数加载对应的Dll。
当程序中需要使用多国语言的字符串时,可以参考下面的代码
DE |
其中 IDS_ABCDEFG就是定义在grd中的name 。
Chrome中有两个grd文件比较重要:
src\chrome\app\generated_resources.grd :该文件定义了多国语言字符串(string),例如按钮的文字,窗口的标题等。
src\chrome\app\resources\locale_settings.grd :该文件定义了多语言配置,例如窗口的大小,某些控件的尺寸。考虑到不同语言的字符串差异,同一个窗口在不同语言下要求的宽度等参数可能不一样。此外还包含字体的大小、名称等。
UI主题和国际化一样,同样适用grit 将grd翻译成目标文件,然后再生成主题Dll。生成主题的grd文件是【src\chrome\app\theme\theme_resources.grd】。该文件在项目chrome_resources中。该项目生成的rc文件被项目theme_dll使用并生成一个主题Dll。
主题Dll在目录【src\chrome\Debug/Release\themes】下。在我这个chrome源码版本中,只有一个主题Dll。名字为“default.dll”。这个Dll在【src\chrome\common\resource_bundle_win.cc】中的函数LoadThemeResources()被load。
主题通常都由一些图片组成,这些图片存放在目录【src\chrome\app\theme】下,基本上时png图片格式。
这些图片通过theme_resources.grd 来生成dll。这个文件的部分格式如下:
DE<<?xml version="1.0" encoding="UTF-8"?> |
当用户需要使用图片时,可以参考如下代码:
DE |
其中 IDR_ABCDEFG为在 theme_resources.grd中每一张图片分配的name。
如果查看项目生成的chrome.exe、chrome.dll文件的属性,可以发现如下:
实际上这些参数通过项目chrome_exe、chrome_dll中的一个.rc.version文件来获取,之所以讲这些是因为.rc.version的处理和前面提到的grd文件有异曲同工之妙。version文件典型的内容如下:
/ // // Version // ... 省略 ... BEGIN VALUE "CompanyName", "@COMPANY_FULLNAME@" VALUE "FileDescription", "@PRODUCT_FULLNAME@" VALUE "FileVersion", "0.0.0.0" VALUE "InternalName", "chrome_exe" VALUE "LegalCopyright", "@COPYRIGHT@" ... 省略 ... END END ... 省略 ... END
|
Version文件的编译命令如下:
D:\chrometrunk\chrometrunk\src\chrome\/../chrome/tools/build/win/version.bat "D:\chrometrunk\chrometrunk\src\chrome\/../chrome/" "D:\chrometrunk\chrometrunk\src\chrome\Debug\obj\chrome_exe" "D:\chrometrunk\chrometrunk\src\chrome\Debug\obj\chrome_exe/chrome_exe_version.rc" |
此类型的编译规则文件见【src\chrome\tools\build\win\version.rules】。该规则的核心就是version.bat文件。
version.bat的内容如下:
:: Batch file run as build command for vers.vcproj @echo off setlocal set InFile=%~1 set SolutionDir=%~2 set IntDir=%~3 set OutFile=%~4 set VarsBat=%IntDir%/vers-vars.bat :: Put cygwin in the path call %SolutionDir%\..\third_party\cygwin\setup_env.bat :: Load version digits as environment variables cat %SolutionDir%\VERSION | sed "s/\(.*\)/set \1/" > %VarsBat% :: Load branding strings as environment variables set Distribution="chromium" if "%CHROMIUM_BUILD%" == "_google_chrome" set Distribution="google_chrome" cat %SolutionDir%app\theme\%Distribution%\BRANDING | sed "s/\(.*\)/set \1/" >> %VarsBat% set OFFICIAL_BUILD=0 if "%CHROME_BUILD_TYPE%" == "_official" set OFFICIAL_BUILD=1 :: Determine the current repository revision number set PATH=%~dp0..\..\..\..\third_party\svn;%PATH% svn.exe info | grep.exe "Revision:" | cut -d" " -f2- | sed "s/\(.*\)/set LASTCHANGE=\1/" >> %VarsBat% call %VarsBat% ::echo LastChange: %LASTCHANGE% :: output file cat %InFile% | sed "s/@MAJOR@/%MAJOR%/" ^ | sed "s/@MINOR@/%MINOR%/" ^ | sed "s/@BUILD@/%BUILD%/" ^ | sed "s/@PATCH@/%PATCH%/" ^ | sed "s/@COMPANY_FULLNAME@/%COMPANY_FULLNAME%/" ^ | sed "s/@COMPANY_SHORTNAME@/%COMPANY_SHORTNAME%/" ^ | sed "s/@PRODUCT_FULLNAME@/%PRODUCT_FULLNAME%/" ^ | sed "s/@PRODUCT_SHORTNAME@/%PRODUCT_SHORTNAME%/" ^ | sed "s/@PRODUCT_EXE@/%PRODUCT_EXE%/" ^ | sed "s/@COPYRIGHT@/%COPYRIGHT%/" ^ | sed "s/@OFFICIAL_BUILD@/%OFFICIAL_BUILD%/" ^ | sed "s/@LASTCHANGE@/%LASTCHANGE%/" > %OutFile% endlocal |
注意上述红色标示的部分
VERSION 部分是获取Chrome预先写好的版本参数文件【src\chrome\VERSION】,内容如下
MAJOR=2 MINOR=0 BUILD=175 PATCH=0 |
BRANDING 部分是获取Chrome预先写好的公司参数文件【src\chrome\app\theme\chromium\BRANDING】,内容如下
COMPANY_FULLNAME=The Chromium Authors COMPANY_SHORTNAME=The Chromium Authors PRODUCT_FULLNAME=Chromium PRODUCT_SHORTNAME=Chromium COPYRIGHT=Copyright (C) 2006-2009 The Chromium Authors. All Rights Reserved. |
如果熟悉Linux的话,估计不会对sed这条命令陌生。这条命令存在与目录【src\third_party\cygwin】中。sed命令将上述两个文件的内容经过处理,在每一行之前加入set。然后输出到%VarsBat%文件【src\chrome\Debug\obj\chrome_exe\vers-vars.bat】中。最终 vers-vars.bat文件的格式类似【set MAJOR=2】。很显然,当执行这个bat,即把所有的参数添加的环境变量了。
最后一条命令将version文件中【%***%】替换成同名环境变量的值,并输出到一个rc文件【src\chrome\Debug\obj\chrome_exe/chrome_exe_version.rc"】中。
最后在chrome_exe项目的rc文件【src\chrome\app\chrome_exe.rc】中,【chrome_exe_version.rc】被include进去。源码如下:
DE<#else // APSTUDIO_INVOKED |