`
qualenac
  • 浏览: 62117 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类

Rails的国际化和本地化技术[转]

阅读更多

http://rc.org.cn/viewthread-282

skyover 发表于: 2007-7-07 23:11 来源: Ruby Community

问题描述

我们在开发rails或者ruby程序过程中经常会面临这样的问题,就是如何让我们开发出来的程序支持多国语言,而不只是英语或者中文,以及如何让rails的英文提示都变成中文的,甚至其他语言的文字。比如,当我们使用rails的校验机制对用户输入的表单数据进行校验时,我们希望呈现给用户的错误提示全部是中文的而不是中英文混杂的,甚至最好能根据用户浏览器的语言偏好信息来选择页面使用的语言文字。

有很多种方法能够实现这种需求,但是比较完整和比较系统的方法是使用Ruby-Gettext包来实现Rails程序、Ruby程序的国际化和本地化。Ruby-Gettext是Masao Mutoh开发的一个利用GNU gettext库实现的ruby国际化程序库。Ruby-Gettext包的文档在这里,用Ruby-Gettext对Rails进行I18n和L10n的一个示例截屏在这里。其中对中文的支持效果如下:

图-1. 用ruby-gettext进行中文本地化后的rails程序效果,摘自Masao Mutoh的ruby-gettext文档


图1.png


图1

可以看到用ruby-gettext做出来的rails本地化(中文)非常完整,并且下面会看到,让它支持其他语言也是易如反掌。不需要对代码有任何的修改,只需把要翻译的内容交给翻译者,然后把翻译后的文件放入系统中就完成了L10n(本地化)的工作。下面让我们一起来探索如何使用Ruby-Gettext轻松进行国际化和本地化的开发吧!
知识要求

这里假设读者已经掌握了常用的Ruby程序开发技术以及初步的Rails程序开发技术,知道Rails中的数据库迁移(migration)的概念。知道ruby gems 包管理系统的相关知识。知道常用的Mysql数据库使用知识。知道常用的Linux日常命令。

第一个I18n(国际化)的ruby程序hello_i18n !

“等一下,我们的这篇文章不是探索rails国际化和本地化技术的吗,为什么要研究ruby程序的国际化和本地化呢?”,也许你会这样问。这是因为通过对一个很简单的ruby程序的国际化和本地化实现进行探索,可以很好地说明Ruby-Gettext的安装、使用以及工作原理。可以循序渐进地让我们学会如何对rails进行国际化和本地化开发。

下面我们先列出完成一个ruby程序国际化和本地化的操作步骤清单,然后逐一讲解。

   1. 安装ruby-gettext gem包。
   2. 编写hello_i18n.rb Ruby程序。
   3. 抽取代码中需要翻译的内容串,创建POT文件
   4. 创建、翻译PO文件并创建MO文件
   5. 运行本地化后的程序

安装ruby-gettext gem包

运行下面的命令进行安装:(注:$符号是命令提示符,表示这是一条shell命令,不需要输入的)

CODE:

$ gem install gettext如果正常,会得到下面的提示,否则可能是网络或者ruby gem服务器暂时有问题,可以多试几次。因为我的操作系统是Linux,所以我选择2。如果你是在windows下,那么就选择1。

清单-1. 安装gettext gem的提示

CODE:

Bulk updating Gem source index for: [url]http://gems.rubyforge.org[/url]
Select which gem to install for your platform (i686-linux)
1. gettext 1.9.0 (mswin32)
2. gettext 1.9.0 (ruby)
3. gettext 1.8.0 (mswin32)
4. gettext 1.8.0 (ruby)
5. Skip this gem
6. Cancel installation
> 2
Building native extensions. This could take a while...
Successfully installed gettext-1.9.0
这样我们就安装好了Ruby-Gettext gem。可以用“ruby --version”来查看ruby解释器的版本信息,我使用的ruby解释器的版本是“ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux]”,如果你的操作系统是windows那么你最好使用ruby one click安装包。可以用“gem -version”来查看gem的版本信息,我使用的gem版本是“0.9.2”。检查一下是否Ruby-Gettext安装是否正确。执行irb然后输入下列语句:

清单-2. 检查Ruby-Gettext gem是否正确安装

CODE:

irb(main):001:0> require 'rubygems'
=> true

irb(main):002:0> require 'gettext'
=> true

irb(main):003:0> GetText
=> GetText
如果你的结果和上面一样,那么恭喜你,你已经正确地安装了Ruby-Gettext gem!如果提示“没有定义GetText这个常量”,那么说明你安装Ruby-Gettext gem有问题,或者是使用了旧版本的gem和ruby。可以根据你的gem和ruby环境下正确使用gem的方法进行调整,只要能正确装载Ruby-Gettext gem并可以找到GetText符号就可以。然后按照你的这个可行的方法修改下面代码中使用Ruby-Gettext gem的方法。

编写hello_i18n.rb文件

用你最喜欢的ruby开发工具或者文本编辑工具创建一个文件“hello_i18n.rb”,它的内容如下:



清单-3. hello_i18n.rb的代码

CODE:

require 'rubygems'
require 'gettext'
include GetText

bindtextdomain("hello_i18n")
print _("Hello I18N World\n")
重点在“print _("Hello World\n")”这个写法上,其中的“_("Hello World\n")”就完成了国际化(支持多种语言),因为当运行时,gettext会根据系统的“地区”设置自动选择合适的语言文字替换此处的字符串。我们检查一下程序是否书写正确,运行下面的命令:


清单-4. 运行没有本地化的 hello_i18n.rb

CODE:

$ ruby hello_i18n.rb
Hello I18N World
如果你也出现上面的提示,那么恭喜你,你的国际化程序写对了!很简单吧!下面我们开始进行本地化工作。

抽取代码中需要翻译的内容串,创建POT文件

什么是POT文件? 它是Portable Object Template的缩写,下面的小节会介绍,这里我们只需要知道它是用来作为翻译原始模板的文件,包含需要被翻译的内容就可以了。执行下面命令:

CODE:

$ rgettext hello_i18n.rb -o hello_i18n.pot文件的内容如下:

清单-5. hello_i18n.pot的内容

CODE:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#

#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2007-05-20 18:17+0800\n"
"PO-Revision-Date: 2007-05-20 18:17+0800\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email]LL@li.org[/email]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: hello_i18n.rb:7
msgid "Hello I18N World\n"
msgstr ""
翻译PO文件并创建MO文件

“.pot”文件是PO模板文件,顾名思义,就是用来被翻译的原始文件,所以,我们不能在它里面进行修改,而需要把它拷贝为一个PO文件,让翻译人员在PO文件上进行翻译编辑工作。一种语言对应一个PO文件,如果你要进行多种语言的本地化工作,那么就需要拷贝多个PO文件给不同的翻译人员进行翻译。


清单-6. 拷贝.pot文件到.po文件

CODE:

$ cp hello_i18n.pot hello_i18n.po接着,我们用文本编辑器打开 hello_i18n.po 文件进行翻译,需要注意的是,你的编辑器必须支持UTF-8编码方式。因为,PO文件的内容必须都用UTF-8来编码。

清单-7. 翻译后的hello_i18n.po文件

CODE:

#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2007-05-20 19:22+0800\n"
"PO-Revision-Date: 2007-05-20 19:22+0800\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email]LL@li.org[/email]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: hello_i18n.rb:7
msgid "Hello I18N World\n"
[color=Red]msgstr "你好国际化和本地化的世界\n"[/color]
注意其中的红色字体那一行,原来是空着的,现在翻译为与msgid对应的中文内容。

接着我们需要用这个PO文件生成供程序读取的MO文件,以便gettext能够快速读取。因为我们的代码中函数“bindtextdomain()”没有带上MO查找路径参数,所以,gettext会在默认的路径中查找MO文件,一般会在“/usr/share/locale/#{lang}/LC_MESSAGES/”或者“/usr/local/share/locale/#{lang}/LC_MESSAGES/”中查找,因为/usr/share/locale中放置了很多系统使用的MO文件,为了方便调试和开发,我们选择把我们的MO文件放置在目录“/usr/local/share/locale/zh_CN/LC_MESSAGES/”中。如果该目录不存在,我们可以用下面的命令创建它:


清单-8. 创建MO存放目录

CODE:

$ mkdir -p /usr/local/share/locale/zh_CN/LC_MESSAGES/然后我们用PO文件创建MO文件:

清单-9. 创建MO文件

CODE:

$ rmsgfmt hello_i18n.po -o /usr/local/share/locale/zh_CN/LC_MESSAGES/hello_i18n.mormsgfmt是ruby-gettext提供的一个生成MO文件的程序,也可以使用GNU的msgfmt程序来生成MO文件。

如果你使用的是windows系统,或者想知道具体的MO文件查找目录都有哪些,并且是以什么顺序查找的,那么可以在生成MO文件之前用“-d”选项运行,这时因为Ruby-Gettext找不到任何MO文件,所以会提示错误,并把MO文件查找目录按照先后顺序列出来。如下:

清单-10. 以调试方式运行ruby程序以显示MO查找路径

CODE:

$ ruby -d hello_i18n.rb
Exception `LoadError' at /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27 - no such file to load -- gettext

Bind the domain 'hello_i18n' to 'Object'. Current locale is #<Locale::Object:0xb78fbb20 @variant=nil, @charset="UTF-8", @orig_str="zh_CN.UTF-8", @script=nil, @country="CN", @modifier=nil, @language="zh">
MO file is not found in
[color=Red]/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/hello_i18n.mo
/usr/share/locale/zh_CN/LC_MESSAGES/hello_i18n.mo
/usr/share/locale/zh/LC_MESSAGES/hello_i18n.mo
/usr/local/share/locale/zh_CN.UTF-8/LC_MESSAGES/hello_i18n.mo
/usr/local/share/locale/zh_CN/LC_MESSAGES/hello_i18n.mo
/usr/local/share/locale/zh/LC_MESSAGES/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh_CN.UTF-8/LC_MESSAGES/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh_CN/LC_MESSAGES/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh/LC_MESSAGES/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh_CN.UTF-8/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh_CN/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/data/locale/zh/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/locale/zh_CN.UTF-8/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/locale/zh_CN/hello_i18n.mo
/usr/lib/ruby/gems/1.8/gems/gettext-1.9.0/locale/zh/hello_i18n.mo[/color]
Hello I18N World
上面清单中红色的部分就是gettext查找MO的目录及其顺序,从高到低,先查找前面的目录,如果没有找到,再查找后面的目录。可以看到,最先查找的目录是“/usr/share/locale/zh_CN.UTF-8/LC_MESSAGES/”,因为在我的系统中,“区域(locale)”环境变量$LANG是“zh_CN.UTF-8”。


运行本地化后的程序

现在,ruby程序的国际化和本地化都已经做完了,是时候我们查看最终成果了。再次运行ruby程序:

清单-11. 运行本地化后的程序

CODE:

$ ruby hello_i18n.rb
你好国际化和本地化的世界
如果你也得到上面的结果,那么恭喜你成功国际化并本地化了一个Ruby程序!


关于国际化、本地化技术的常用术语和概念解释
常用术语

区域(locale):对某个国家的文化习惯的一种正式描述,与该国家或语言有关的翻译被称作这种语言或者国家的区域(locale)。
i18n 和 l10n:他们分别是internationalization(国际化) 和localization(本地化)的缩写。国际化是指让同一个程序能支持多个不同的区域(locale),而本地化是指让程序能够支持用户所选择的区域(locale)。粗略地说,对于多语言的系统而言,国际化通常由程序员实现,而本地化通常由翻译员实现。
NLS:Native Language Support,本地语言支持,是指与国际化和本地化相关的所有活动或者产品功能,是指能够让一个程序支持多语言交互能力。
Gettext:是一个GNU软件项目,是很多GNU程序实现多语言支持的基础,它提供了简单、统一的方式来使国际化、本地化工作尽量简单和尽量不影响原有的程序代码。它的主页在这里。

包含翻译信息的文件

在上面我们提到并且使用了POT, PO文件和MO文件,这里我们进一步对这些文件进行一下解释。

“.po”文件中的字母缩写PO代表Portable Object(可移植对象)的意思,为的是与.mo文件区别,这里MO代表的是Machine Object(机器对象)的意思。PO文件适合于人的读写、编辑,因为它是一个纯文本文件,包含原始的用于翻译的字符串和翻译成某种目标语言后的字符串。一个PO文件仅用于一种目标语言。如果一个package(软件包)支持多种语言,那么一种语言就要有一个这样的PO文件与之对应,于是整个包就由这样一组PO文件组成。

以“.pot”结尾的文件是一种用于翻译的基本模板文件,它一般包含在软件的分发包中,以PO文件格式书写。在上面的例子中,我们正是把一个POT文件拷贝成PO文件,然后编辑PO文件的,每一种语言的PO文件都是从POT文件拷贝而来进行翻译的,而不直接修改POT文件。

“.mo”文件是用于机器读取的文件,它以二进制方式存储,只适合机器解读。它是由rmsgfmt (或msgfmt )读取PO文件进行编译后生成的。

最新回复

skyover at 2007-7-08 01:09:08
下面我们正式地来国际化、本地化一个Rails应用程序“MyBlog”。

先列出需要执行的操作步骤,然后在逐一讨论。操作步骤如下:

   1. 创建一个数据库
   2. 生成Rails应用程序框架代码
   3. 配置Rails使用的数据库连接参数
   4. 创建一个model “article”
   5. 编写数据库迁移(migration)代码并执行数据库迁移操作,生成数据库结构
   6. 设置ruby解释器使用的编码方式和声明ruby-gettext相关的包
   7. 创建一个脚手架model和controller
   8. 初始化ruby-gettext包
   9. 国际化model
  10. 创建Rake任务来完成抽取.pot文件,然后翻译.po文件,最后创建.mo文件的操作
  11. 使用浏览器查看本地化后的效果
  12. 国际化模板



虽然看上去步骤挺多,但是只有红色的才是国际化相关的。下面我们逐一进行介绍。

创建一个数据库

创建一个mysql数据库,mysql的版本必须是4.1以上的版本,这样才支持数据库缺省字符集,这里我们要使用utf8字符集编码。

清单-12 创建数据库

CODE:

mysql> create database blog_development default character set utf8;
Query OK, 1 row affected (0.00 sec)
生成Rails应用程序框架代码

确认你的rails版本是1.2.3及以上的,然后用下面的命令创建一个rails应用程序。

清单-13 创建Rails程序框架

CODE:

rails blog配置Rails使用的数据库连接参数

编辑conf/database.xml文件,设置正确的数据库连接属性,如下:

清单-14 数据库连接参数配置

CODE:

development:
adapter: mysql
database: blog_development
username: root
password:
host: localhost
创建一个model “article”

使用下面的命令创建一个model “article”

清单-15 创建一个model “article”

CODE:

$ ./script/generate model article

exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/article.rb
create test/unit/article_test.rb
create test/fixtures/articles.yml
create db/migrate
create db/migrate/001_create_articles.rb
编写数据库迁移(migration)代码并执行数据库迁移操作,生成数据库结构和数据

编辑migrate文件“db/migrate/001_create_articles.rb”,创建相关的表和字段

清单-16 编辑migrate文件

CODE:

class CreateArticles < ActiveRecord::Migration
  def self.up
    create_table :articles do |t|
      t.column :title, :string, :default => ''
      t.column :description, :text
      t.column :lastupdate, :date
    end
  end

  def self.down
    drop_table :articles
  end
end
执行migrate操作,创建数据库表

清单-17 执行migrate操作,创建数据库结构

CODE:

$ rake db:migrate

== CreateArticles: migrating ==================================================
-- create_table(:articles)
-> 0.0032s
== CreateArticles: migrated (0.0034s) =========================================
检查表是否正确创建(可以跳过)

清单-18 检查是否正确创建了数据库表

CODE:

mysql> use blog_development;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> desc articles;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | YES | | | |
| description | text | YES | | NULL | |
| lastupdate | date | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
设置ruby解释器使用的编码方式和声明ruby-gettext相关的包

编辑文件 conf/environment.rb 在第一行加入下面的语句:

清单-19 设置解释器使用的编码方式并引入需要的包

CODE:

$KCODE = 'u'
require 'jcode'
# 在最后一行加入下面的语句:
require 'gettext/rails'
创建一个脚手架model和controller,model是Article,controller是Blog

清单-20 创建model和controller

CODE:

./script/generate scaffold Article Blog初始化ruby-gettext包

编辑app/controllers/application.rb,加上下面的语句:

清单-21 初始化ruby-gettext包

CODE:

class ApplicationController < ActionController::Base
  init_gettext "blog"
end
这里的参数“blog”是textdomain,也就是给一组相关的pot/po/mo文件起的一个共同的组名,和bindtextdomain中的参数textdomain含义一样。

下面是init_gettext()方法的API文档:

CODE:

ActionController::Base.init_gettext(textdomain, options = {})绑定'textdomain'到所有的controllers/views/models上。参数:

CODE:

    * textdomain: 文本域
    * options:
          o :charset - 输出字符集. 缺省是"UTF-8"
          o :content_type - 文档类型. 缺省是"text/html"
          o :locale_path - locale目录的路径. 缺省是RAILS_ROOT 或者插件的根目录。
你也可以为每个controller单独地绑定一个“文本域”,如果这样就要在每个controller中加入下面的代码:

CODE:

class BlogController < ApplicationController   init_gettext "blog"   :   : end接下来,我们就可以像在Ruby程序中使用ruby-gettext提供的方法一样,在rails的model, controller, view, helper中使用它们了。


国际化model

让我们先来国际化model,以便让由model产生的校验错误提示信息都是本地语言。

加入验证代码

清单-22 国际化model

CODE:

class Article < ActiveRecord::Base
  # Simple
  validates_presence_of :title
  validates_length_of :description, :minimum => 10
  # With messages (Use N_() here)
  validates_presence_of :title, :message => N_("%{fn} can't be empty!")
  validates_length_of :description, :minimum => 10, :message => N_("%{fn} is too short (min is %d characters)")
  # Your own validations (Use _() instead of N_()).

  protected
  def validate
    unless title =~ /\A[A-Z]+\z/
      errors.add("title", _("%{fn} is not correct: %{title}") % {:title => title})
    end
  end

end
这里的验证代码与一般的验证代码不同之处在于使用了一些Ruby-Gettext提供的方法,如:N_( ), _( )。

_( ) 是GetText._(msgid)方法,它会把msgid映射成为对应的翻译字符串,并返回该翻译串。比如:_(“to be translated”) # => “将被翻译”

而N_( ) 是getText.N_(msgid)方法,它不进行翻译,只是提供一个位置让GetText知道有这样一个msgid存在,它返回msgid本身。

所以_( ) 方法与N_( )方法的主要区别就在于是否进行翻译并返回翻译后的内容。因为Ruby-Gettext对validates_系列函数的底层实现进行了修改,所以,不需要在调用时进行消息(:message)的翻译,而只需要在此创建一个msgid即可,真正的转换工作Ruby-Gettext包会处理。而对于自己实现的验证方法,如在errors中增加的错误提示信息,如:

CODE:

errors.add("title", _("%{fn} is not correct: %{title}") % {:title => title})就需要立刻进行翻译,得到一个翻译后的字符串供方法调用使用。

另外,在上面的代码中还有“_("%{fn} is not correct: %{title}") % {:title => title}”的用法,在是Ruby-Gettext对String类的扩展,允许在字符串中使用命名参数,例子中的含义是把{:title => title}中的title变量值嵌入%{title}这个位置。其中%{fn}是Ruby-Gettext的一个特殊命名参数,表示字段名,如在这里就是“title”,并且该字段名会被进行正确的翻译,如在本例中会被翻译为“标题”。

还有一些其他用法,比如复数情况的翻译等,请参考Ruby-Gettext的API文档说明。

创建Rake任务来完成抽取.pot文件,然后翻译.po文件,最后创建.mo文件的操作

在我们能看到最后的效果前,还需要进行本地化(翻译)工作。我们需要从代码中抽取出.pot文件,然后翻译为.po文件,最后创建供程序使用的二进制的.mo文件。为了使这个过程更加方便,我们利用rake来进行自动化。

首先添加一个rake任务,这是通过创建文件 lib/tasks/gettext.rake 并写入下面的内容来实现的。

清单-23 rake任务代码

CODE:

desc "Update pot/po files."
task :updatepo do
  require 'gettext/utils'
  GetText.update_pofiles("blog", Dir.glob("{app,lib,bin}/**/*.{rb,rhtml}"), "blog 1.0.0")
end

desc "Create mo-files"
task :makemo do
  require 'gettext/utils'
  GetText.create_mofiles(true, "po", "locale")
end
现在可以用rake来轻松生成 pot 文件了,执行下面命令即可。

清单-24 执行抽取POT文件的rake命令

CODE:

$ rake updatepo
(in /home/yangbo/doc/我的作品/src/blog)
po/blog.pot
. done.
然后我们像在国际化Ruby程序时一样拷贝.pot文件生成po文件,需要把PO文件放置到特定的目录 po/zh_CN 下,其中zh_CN是根据本PO文件的目标语言而设定的,例如,要翻译成日语则为po/jp目录。

清单-25 拷贝生成

CODE:

$ cd po
$ mkdir zh_CN
cp blog.pot zh_CN/blog.po
翻译zh_CN/blog.po文件,注意要使用utf-8编码保存本文件。翻译后的文件内容如下:

清单-26 翻译后的PO文件

CODE:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy

msgid ""
msgstr ""
"Project-Id-Version: blog 1.0.0\n"
"POT-Creation-Date: 2007-05-26 13:12+0800\n"
"PO-Revision-Date: 2007-05-26 13:11+0800\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email]LL@li.org[/email]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: app/models/article.rb:-
msgid "article"
msgstr "文章"

#: app/models/article.rb:-
msgid "Article|Title"
msgstr "标题"

#: app/models/article.rb:-
msgid "Article|Description"
msgstr "描述"

#: app/models/article.rb:-
msgid "Article|Lastupdate"
msgstr "更新日期"
这样我们就可以用这个PO文件来生成最后需要的MO文件了。生成MO也可以用我们刚才写好的Rake任务,如下:

清单-27 生成MO文件

CODE:

$ rake makemo
(in /home/yangbo/doc/我的作品/src/blog)
po/zh_CN/blog.po -> locale/zh_CN/LC_MESSAGES/blog.mo
使用浏览器查看本地化后的效果

现在我们终于可以看到最后的效果了。下面我们就来利用Firefox浏览器模拟一个简体中文用户访问我们的blog程序。我们需要设置浏览器的语言选项,以中文优先,比如在firefox中可以如下图所示进行设置:


图2.png


图-2 设置Firefox的语言偏好选择

这样在发送的HTTP请求中会有如下的HTTP头字段信息:

CODE:

Accept-Language: zh-cn,en-gb;q=0.7,en;q=0.3于是rails+ruby-gettext系统会根据该信息选择简体中文locale(区域)进行消息的本地化。设置区域的另一种办法是指定rails程序只使用一种本地化语言,那么不论浏览器选择什么语言,rails程序都只返回该种语言的文字,可以这样设置:

清单-28 固定只显示一种语言

CODE:

class ApplicationController < ActionController::Base
  GetText.locale = "zh_CN"
  init_gettext "blog"
end
为了看到最后的效果,我们启动blog程序的WEBrick服务器,打开浏览器,然后访问这个链接地址“http://localhost:3000/blog/new”,故意空着标题然后提交以便可以得到下面的错误提示页面:


图3.png


图-3 本地化后的model校验错误提示页面

可以看到页面上还有部分文字没有被本地化,它们是view模板中的文字。下面我们接着国际化create方法的模板,将上图中的英文字符串被本地化。

编辑app/views/blog/new.rhtml,修改为下面的内容:

清单-29 国际化new方法的模板

CODE:

<h1><%= _("New article") %></h1>
<% form_tag :action => 'create' do %>
<%= render :partial => 'form' %>
<%= submit_tag _("Create") %>
<% end %>
<%= link_to _('Back'), :action => 'list' %>
编辑 app/views/blog/_form.rhtml,改为下列内容:

清单-30 国际化form嵌套模板

CODE:

<%= error_messages_for 'article' %>
<!--[form:article]-->
<p><label for="article_title"><%= _("Title") %></label><br/>
<%= text_field 'article', 'title' %></p>
<p><label for="article_description"><%= _("Description") %></label><br/>
<%= text_area 'article', 'description' %></p>
<p><label for="article_lastupdate"><%= _("Lastupdate") %></label><br/>
<%= date_select 'article', 'lastupdate' %></p>
<!--[eoform:article]-->
然后执行rake任务更性POT模板和PO模板

清单-31 更性POT、PO文件

CODE:

$ rake updatepo
(in /home/yangbo/doc/我的作品/src/blog)
po/blog.pot
. done.
po/zh_CN/blog.po
. done.
你会发现po/zh_CN/blog.po文件被自动进行了新旧内容的合并,这个功能方便了翻译者对本地化内容的维护。使得我们不必从头再把所有已经翻译过的内容再翻译一次。编辑blog.po文件会发现多了下面的内容:

清单-32 PO文件新增加的内容

CODE:

#: app/views/blog/new.rhtml:5
msgid "Create"
msgstr ""

#: app/views/blog/new.rhtml:8
msgid "Back"
msgstr ""

#: app/views/blog/_form.rhtml:7
[color=Red]#, fuzzy
msgid "Description"
msgstr "描述"[/color]
特别注意红色的fuzzy一行,它表示Description在原来的msgid中已经存在,但原来的msgid是带有上下文方式的(也就是形如 msgid "Article|Description" 方式的msgid),需要翻译者确认原来的翻译是否在这里也适用。确认后需要把#, fuzzy一行去掉,否则,该消息ID的翻译内容不会生成到mo文件中去,最后的效果就是没有该消息ID的本地化翻译内容与之对应了。其余部分用之前的方法进行翻译,然后执行rake命令生成MO文件:

清单-33 生成MO文件

CODE:

$ rake makemo
(in /home/yangbo/doc/我的作品/src/blog)
po/zh_CN/blog.po -> locale/zh_CN/LC_MESSAGES/blog.mo
运行blog网页应用程序,执行之前的创建文章操作,故意空着标题栏,得到完全本地化的页面:

图-4 最后完全国际化和本地化后的页面效果


图4.png


图4

小结

本文介绍了如何使用Ruby-Gettext来进行ruby程序和rails程序的国际化与本地化开发。通过两个例子循序渐进地介绍了使用Ruby-Gettext进行ruby、rails程序国际化开发的方法和相关知识。通过阅读本文,读者可以掌握国际化Ruby、Rails程序的技术。为读者进一步了解、使用Ruby-Gettext打下良好的基础。


作者简介

杨波 <bob.yang.dev (at) gmail.com>
早期使用VC++在windows平台下做桌面软件产品开发,之后多年使用java语言进行开发,主要从事电信增值业务开发,从2006年开始接触和使用ruby和ruby on rails进行一些开发。目前是结信网络有限公司的技术经理,从事特定领域(彩铃)搜索引擎产品和自然语言处理方面的研发工作。也是一个Ruby, Rails的爱好者。

本文章版权归杨波所有,欢迎转载,但必须注明作者。如果需要用于商业目的,请与作者联系

Rails国际化和本地化技术.pdf
(2007-07-08 01:11:33, Size: 378 KB, Downloads: 11)

示例代码hello_i18n.zip
(2007-07-08 01:11:33, Size: 1.61 KB, Downloads: 7)

示例代码——myblog.zip
(2007-07-08 01:11:33, Size: 77 KB, Downloads: 4)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics