所谓的国际化:就是根据特定的locale信息,提取相应的字符串和其它一些东西(比如时间和货币的格式)等等。
显然,有三个问题需要解决:
1. 如何确定locale。
2. 如何保存这些locale相关的字符串和其它信息。
3. 如何根据locale提取字符串和其它相应的信息。
让我们来看看rails如何处理国际化。(指rails2.2之后)
首先看看第一点,如何确定locale
可以通过几种不同的方法来确定locale。
a. url参数
http://www.example.com?locale=cn 或者 http://www.example.com/cn
在服务器端可以通过在before_filter中获取locale信息:
# 通过before_filter before_filter :set_locale def set_locale I18n.locale = extract_locale_from_uri end
要注意的是,如果通过此种方法来确定locale,那么所有的url都得附上locale参数。我们可以通过重载以下方法(url_for等方法均依赖于default_url_options方法)
# app/controllers/application_controller.rb def default_url_options(options={}) logger.debug "default_url_options is passed options:#{options.inspect}\n" { :locale => I18n.locale } end
或者通过设置routes在所有的url中加上prefix:
# routes.rb map.resources :books, :path_prefix => '/:locale'
b. 域名
http://www.example.cn
对域名方式,同样在before_filter中获取locale信息。只不过修改一下extract方法:
def extract_locale_from_subdomain parsed_locale = request.subdomains.first (available_locales.include? parsed_locale) ? parsed_locale : nil end
c. 客户端提供的信息
客户端可以提供一些信息告诉服务端它所接受和期望的语言是什么。可以有以下几种方式来告知:
c.1. Accept-Language
通过在浏览器中设置Accept-Language,服务器端通过获取此http header的信息来确定。
def extract_locale_from_accept_language_header request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first end
c.2. ip地址
根据ip地址来分析用户的locale信息。
c.3. profile
注册用户可以把locale信息保存在个人档案中。
接下来让我们看看rails如何解决第二个问题
如何保存locale相关的字符串和其它信息
rails必须知道,本地化的信息被放置何处。在Rails中有几种方法来保存locale信息。
a. yml
# config/locale/en.yml en: hello_world: Hello World hello_flash: Hello Flash # config/locale/pirate.yml pirate: hello_world: Ahoy World hello_flash: Ahoy Flash
b. 本地化view
一般我们的view template文件是这样的:
app/views/somethings/index.html.erb
当在同个目录下放置一个加上本地化变量的template文件,比如:
app/views/somethings/index.cn.html.erb
当本地locale是cn时,便会render这个文件。
c. 对本地化文件的管理
把所有本地化信息都放置在一个文件中必然会导致混乱,我们可以按照自己的方式来管理这些本地文件,比如:
|-defaults |---es.rb |---en.rb |-models |---book |-----es.rb |-----en.rb |-views |---defaults |-----es.rb |-----en.rb |---books |-----es.rb |-----en.rb |---users |-----es.rb |-----en.rb |---navigation |-----es.rb |-----en.rb
要注意的是,rails默认不会load层级目录中的文件,所以需要:
# config/environment.rb config.i18n.load_path += Dir[File.join(RAILS_ROOT, 'config', 'locales', '**', '*.{rb,yml}')]
好了,我们已经知道如何放置本地化信息,最后来看一下rails如何根据locale获取这些信息。其实,这里要讲的就是rails国际化API。
提取信息
rails提供了一下几个API:
translate # Lookup text translations localize # Localize Date and Time objects to local formats
以及它们的alias:
I18n.t 'store.title' I18n.l Time.now
在需要本地化的地方,只需要这样使用:
# app/views/home/index.html.erb <h1><%=t :hello_world %></h1> <p><%= flash[:notice] %></p <p><%= l Time.now, :format => :short %></p>
好了,本文匆匆到此结束。
如果想跟进一步的了解rails的i18n,可以看一下这篇文章:http://guides.rubyonrails.org/i18n.html
例子:
http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale
http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml