Chromium本地化的方法

Chromium的本地化方法

 

 

一、软件环境

      chromium版本:6.0.482.0

      os:windows xp sp2

 

二、chromium的本地化

             chromium中需要本地化的部分有三部分:

             1>chromium项目本地化,2>webkit本地化,3>setup本地化.

             由于对第2种的本地化需求较少,setup部分的本地化较简单,本文只讲述1部分的本地化方法。

 

 

三、chromium项目本地化

 

        1.通过编译chrome项目后,可以发现,在生成的locals中,共有51个.dll文件,分别是不同语言的本地化库。在sln文件中分别对应有这51个项目,而在每个项目中都包含名为generated_resources_xx.rc的资源文件(xx为语言代号,例如zh_CN为简体中文),在其下的stringtable中则是以此种语言的本地化字符串集。细心的朋友可以发现,整个chrome编译之前,这些rc文件是不存在的,它的生成是在编译时动态生成的。生成它的项目正是chrome_strings项目。

 

 

        2.打开chrome_strings项目可以看到,其下包含了三个grd文件:chromium_strings.grd, generated_resources.grd, google_chrome_strings.grd。另外还有一批xtb文件。

    google_chrome_strings.grd文件是用于编译chrome时才使用的,而我们是要编译chromium项目,因此不涉及此文件.

    chromium_string.grd文件涉及到chromium项目的本地化和setup的本地化,其中包含安装卸载软件介绍等字符串的本地化。

    generated_resources.grd主要涉及chromium项目的本地化,几乎包含所有chrome.exe中所要使用到的字符串的本地化。

 

    综上所述,generated_resource.grd是我们需要关注的对象。打开该文件可以看到,该文件由3部分组成:

 

<output>部分包含了两种生成文件,

<output filename="generated_resources_zh-CN.rc" type="rc_all" lang="zh-CN" />

<output filename="generated_resources_zh-CN.pak" type="data_package" lang="zh-CN" />

 

<translations>部分包含一种生成(翻译)文件:

<file path="resources/generated_resources_zh-CN.xtb" lang="zh-CN" />

 

<release>部分包含的是message对,每一个<message></message>中包含了一个所要使用的字符串。

 

    3.本地化原理

             顾名思义,需要本地化,那么首先需要有一个“标准”字符串文件,然后在不同种语言下替换掉该语言。由此我们需要揭开上面所述的四种文件之间(grd, rc, xtb, dll)的生成关系:

    

                             <xtb>

                 grd  --------------->  rc     --------->  dll

 

grd:grd文件就是“标准”字符串文件,在其中定义好项目中所需使用的字符串id与对应的字符串值(一般为英文版本,因为比较通用)。

xtb:针对grd文件的不同语言翻译版本文件,例如,中文环境下的字符串翻译都需要写在generated_resources_zh-CN.xtb中,至于存放格式,这是后面讨论的重点。

rc:本文件对应在不同的语言项目中,并且被该项目所包含以便编译时生成到dll文件中。

dll:由rc文件生成出来的不同语言翻译版本的字符串“库”。

 

    4.如何本地化

           上面提到,对“标准”文件本地化时,要把对应语言的翻译版本写到对应的xtb文件中。因此翻译简体中文版本时,只要将对应“标准”文件中的字符串本地化到generated_resources.xtb文件中,打开此文件可以看到。

      在generated_resources.grd中字符串值

     <message name="IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION" desc="Description for a keyword match.">
        (Keyword: <ph name="KEYWORD">$1</ph>) 

     </message>

   (注:$1是chromium中定义的字符替换标识符,此部分的原理不在本文讨论范围内。)

  在generated_resources_zh_CN.xtb中对应的翻译版本如下:

     <translation id="406259880812417922">(关键字:<ph name="KEYWORD"/>)</translation>

  在generated_resources.zh_TW.xtb中对应的翻译版本如下:

    <translation id="406259880812417922">(關鍵字: <ph name="KEYWORD"/>)</translation>

 

      由此,我们可以预测程序中使用字符串id为IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION的地方,在中文环境下对应使用的字符串是翻译字符串中id=406259880812417922所对应的“(关键字:$1)”, 在繁体环境下对应的是(關鍵字:$1) 但是这是如何对应起来的?我们只能看到在下面的翻译版本和上面message中都含有同一个键“id”,但这两个键的值之间看不出有明显的联系。因此如果找到了这两者之间的联系,那么我们就找到了把“标准”字符串翻译成各种语言版本的根本方法。

      到此,想从项目中去找到这个联系的头绪已经断了,此时我想到了官网。果然,官网上给出了答案:

 

"If you are adding a string to Chromium that you want for a different version of Chromium and you want to have translation in other languages, you need to add translations to the .xtb files in /src/chrome/app/resources.  These files have a transalation id that is based on a hash of the en-US string (see /src/tools/grit/external/FP.py for details on the hash)"


   答案就在/src/tools/grit/external/FP.py文件中,打开该文件看到如下代码:

def UnsignedFingerPrint(str, encoding='utf-8'):
  """Generate a 64-bit fingerprint by taking the first half of the md5
  of the string."""
  hex128 = _new_md5(str).hexdigest()
  int64 = long(hex128[:16], 16)
  return int64

def FingerPrint(str, encoding='utf-8'):
  fp = UnsignedFingerPrint(str, encoding=encoding)
  # interpret fingerprint as signed longs
  if fp & 0x8000000000000000L:
    fp = - ((~fp & 0xFFFFFFFFFFFFFFFFL) + 1)
  return fp

      从这两个python写的函数中可以看到基本的思路:FingerPrint函数接收一个字符串输入,然后调用函数UnsignedFingerPrint对字符串计算md5值hex128,并对hex128按照16进制取前一半,再经常一系列位运算之后返回其值,由此大致可以判断算出来的值是一列数字串,因此,我们再只需要确定输入的字符串的规则即可算出最后的数字串的值。

 

      经过我对输入字符串进行各种可能的测试之后,发现有时算出的值与xtb中的值相同,有时不同,由此断定计算方法中还有未知的部分,因此我们需要找到调用FingerPrint函数的部分是否做了其它处理。因此我在源代码中搜索,结果如愿找到了文件/src/tools/grit/external/tclib.py中有如下代码:

 

def GenerateMessageId(message, meaning=''):
  fp = FP.FingerPrint(message)
  if meaning:
    # combine the fingerprints of message and meaning
    fp2 = FP.FingerPrint(meaning)
    if fp < 0:
      fp = fp2 + (fp << 1) + 1
    else:
      fp = fp2 + (fp << 1)
  # To avoid negative ids we strip the high-order bit
  fpid = str(fp & 0x7fffffffffffffffL)
  return fpid

 

      这个函数中,我们看到了另一个输入输入字符串meaning,根据名字猜测应该是在有被替换的字符串标识符的时候会被使用到,函数的逻辑比较简单,据此,我们得到了计算id值406259880812417922的大致方法。但被输入的两个字符串该选取<message>的哪个部分还是不确定。个人以为,与其一个个这样去输入两个字符串参数,然后用脚本计算id值,何不让编译程序“自动”为我生成,这样也免去我确定输入参数时的各种错误情况。“自动”生成的方法很简单,在这个函数中,计算出id值之后,把它保存到一个文件中就OK了。本函数修改后的代码如下:

 

def GenerateMessageId(message, meaning=''):
  fp = FP.FingerPrint(message)
  if meaning:
    # combine the fingerprints of message and meaning
    fp2 = FP.FingerPrint(meaning)
    if fp < 0:
      fp = fp2 + (fp << 1) + 1
    else:
      fp = fp2 + (fp << 1)
  # To avoid negative ids we strip the high-order bit
  fpid = str(fp & 0x7fffffffffffffffL)

########
  fp2 = file('c:/message_log.txt', 'a')
 fp2.write('message=' + message + ', id=' + fpid + "/r/n")

  fp2.close()

#######
  return fpid

  

      上面#所包含的四行代码将计算出的id值以xtb中的格式保存到c:/message_log.txt文件中,剩下需要做的就是编译chrome_strings项目,再去找到message_log.txt文件中对应所需要计算的<message>值并将id拷贝到xtb文件中,附加上翻译后的字符串即可。

例如,上面所列举的IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION字符串在message_log.txt中对应的一列为:

message=(Keyword: KEYWORD), id=406259880812417922

 

      当然,如果想要深究GenerateMessageId的两个输入参数也是很容易的,稍加改动write语句,把两个输入参数的值输出即可知道输入字符串的规则,但目的还是计算得知id,既然我们已经达到此目标,我就不去深究这个值。

 

      至此,我们的问题全部解决了,再来理一下整体思路,如果要添加一个新的字符串到chromium项目中,并且需要翻译成本地版本,我们需要做的步骤如下:

1.添加字符串到generated_resources.grd文件中。

<message name="IDS_OK" desc="Used for Ok on buttons">
        OK
      </message>

 

2.only编译chrome_strings项目,在message_log中找到下面一行

 message=OK, id=6965382102122355670

 

3.在generated_resrouces_zh_CN.xtb中添加如下一行翻译值

 <translation id="6965382102122355670">确定</translation>

 

4.再编译chrome_string项目,就可以在zh_CN项目的generated_resources.rc的stringtable中找到下面这一行

 IDS_OK        11028    确定

 

  当编译出的chromium程序运行在简体中文环境下时,调用IDS_OK的地方则会显示出“确定”字符串。

 

 

 

后記:虽然本地化的问题已经解决,但我在完成此任务时,出现不少问题,在此列出来主要的几个,让大家少走一些弯路:

1.generated_resources.xtb中的id值不能重复,出现重复时,编译chrome_string项目时会给出提示,但它的提示未明显指出是重复问题。如果出现重复,删掉一条即可,因为id值如果重复,那么说明这两个字符串的值本身就是相同的,那么在生成rc文件时,两个<message>字符串都会去对应到这条id值上,对结果无影响。

 

2.计算出id值后,填到xtb文件中时,如果字符串有有需要被替换的部分,即原字符串中包含诸如<ph name="LANGUAGE">$1<ex>English</ex></ph>的字段,则xtb文件中对应字符串一定要附加上<ph name="LANGUAGE"/>的串,否则项目chrome_strings编译通不过,同样,编译错误俺看不懂。

 

3.有人说,可以直接在生成的rc文件中修改字符串的翻译以达到本地化的目的。当然,我承认这是最直接的方式,但不可忽视的是,如果你所使用的所有字符串是一次性生成,一次性在rc文件中修改完成,那么这种方法OK,没问题。但当你在grd中新添加一条字符串值时,或者做了rebuild时,rc文件会被重新生成,你所做的努力将前功尽弃,必须全盘重来。所以这是一种治标不治本的方法,不推荐使用。

 

 

(第一次写文章,逻辑,思维不甚严密,请见谅,谢谢)

 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页