chrome UI 学习笔记3--国际化 (转)

不可否认,Chrome的国际化做的非常优秀,在Chrome中添加一种新的语言支持非常方便。

http://www.chromium.org/developers/design-documents/ui-localization

Locale 项目

如果使用virtual studio 2008打开chrome for windows的工程,可以看到如下的项目:



其中每一个项目对应一种语言支持,所以如果需要添加新的语言支持,只需要新建一个新的语言项目。

实际上,每一个语言项目内的所有文件都是编译生成的中间文件,在文件夹【src\chrome\app\locales】中存放了这所有的项目文件,但每一个项目仅仅存在一个vcproj文件,例如zh-CN.vcproj,项目中包含的文件实际存在于【src\chrome\Debug/Release\grit_derived_sources】目录下。那这些文件怎么生成的呢,这需要了解一下google自己开发的一个python项目。



GRIT 软件

该项目的源码在目录【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等文件。当然输出什么文件需要用户在输入文件中指定。


Grd文件

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"?>

<!-- This file contains definitions of resources that will be translated for
each locale. -->

<grit base_dir="." latest_public_release="0" current_release="1"
      source_lang_id="en" enc_check="möl">
  <outputs>
    <output filename="grit/generated_resources.h" type="rc_header">
      <emit emit_type='prepend'></emit>
    </output>
    <output filename="generated_resources_zh-CN.rc" type="rc_all" lang="zh-CN" />
    <output filename="generated_resources_zh-TW.rc" type="rc_all" lang="zh-TW" />
    <output filename="generated_resources_zh-CN.pak" type="data_package" lang="zh-CN" />
    <output filename="generated_resources_zh-TW.pak" type="data_package" lang="zh-TW" />
  </outputs>
  <translations>
    <file path="resources/generated_resources_zh-CN.xtb" lang="zh-CN" />
    <file path="resources/generated_resources_zh-TW.xtb" lang="zh-TW" />
  </translations>
  <release seq="1" allow_pseudo="false">
    <messages fallback_to_english="true">
      <!-- TODO add all of your "string table" messages here. Remember to
      change nontranslateable parts of the messages into placeholders (using the
      <ph> element). You can also use the 'grit add' tool to help you identify
      nontranslateable parts and create placeholders for them. -->

      <message name="IDS_SHOWFULLHISTORY_LINK" desc="The label of the Show Full History link at the bottom of the back/forward menu.">
        Show Full History
      </message>
    </messages>
  </release>
</grit>DE<

说明:

  1. Output节表示输出文件,例如上面的文件会生成一个 generated_resources.h、若干rc文件(generated_resources_zh-CN.rc)和若干pak文件(generated_resources_zh-CN.pak)。

  2. Translations节表示翻译文件,一般来说每一种支持的语言都应该有一个翻译文件。

  3. 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" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
<translation id="6779164083355903755">删除(&amp;R)</translation>
<translation id="3581034179710640788">此网站的安全证书已过期!</translation>
<translation id="8275038454117074363">导入</translation>
</translationbundle>DE<

或者

DE<<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
<translation id="IDS_WEB_FONT_FAMILY">Simsun</translation>
<translation id="IDS_WEB_FONT_SIZE">84%</translation>
<translation id="IDS_UI_FONT_FAMILY">default</translation> 
</translationbundle>DE<

两者区别主要是ID的表示方式。后者IDgrd中的name是一致的,而前者则通过某种算法将grd中的name转换为由数字组成的ID


Grd文件的编译

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

从上面内容可以发现,chromepython解释器直接放到源码【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 】也许有些帮助。



Locale初始化

当通过grd文件生成locale下语言项目依赖的文件后,Chrome将这些项目打包生成一个语言Dll,这些Dll可以在目录【src\chrome\Debug/Release\locales】下找到。当Chrome启动时,它会通过某种途径查找locale类型,然后找到对应的Dllload

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&rb = ResourceBundle::GetSharedInstance();
std::wstring str = l10n_util::GetString( IDS_ABCDEFG )DE<


其中 IDS_ABCDEFG就是定义在grd中的name 


Chrome中有两个grd文件比较重要:

  1. src\chrome\app\generated_resources.grd :该文件定义了多国语言字符串(string),例如按钮的文字,窗口的标题等。

  2. src\chrome\app\resources\locale_settings.grd :该文件定义了多语言配置,例如窗口的大小,某些控件的尺寸。考虑到不同语言的字符串差异,同一个窗口在不同语言下要求的宽度等参数可能不一样。此外还包含字体的大小、名称等。



UI主题



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"?>
<grit latest_public_release="0" current_release="1">
  <outputs>
    <output filename="grit/theme_resources.h" type="rc_header">
      <emit emit_type='prepend'></emit>
    </output>
    <output filename="theme_resources.rc" type="rc_all" />
    <output filename="theme_resources.pak" type="data_package" />
  </outputs>
  <release seq="1">
    <includes>
      <include name="IDR_BACK" file="back.png" type="BINDATA" />
      <include name="IDR_BACK_D" file="back_d.png" type="BINDATA" />
    </includes>
  </release>
</grit>DE<


当用户需要使用图片时,可以参考如下代码:


DE&rb = ResourceBundle::GetSharedInstance();
    SkBitmap* img_ = rb.GetBitmapNamed(IDR_ABCDEFG);DE<


其中 IDR_ABCDEFG为在 theme_resources.grd中每一张图片分配的name


Chrome的版本信息

如果查看项目生成的chrome.exechrome.dll文件的属性,可以发现如下:



实际上这些参数通过项目chrome_exechrome_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文件的编译

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

#include "chrome_exe_version.rc"
#endif DE<

你可能感兴趣的:(chromium)