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][email protected][/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][email protected][/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][email protected][/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)

發佈了7 篇原創文章 · 獲贊 0 · 訪問量 1749
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章