Ruby-Locale for Ruby on Rails HOWTO

ruby-locale-rails-howto

Create Sample Application

Before starting this HOWTO, create non-l10n sample application based on Ruby on Rails first.

This HOWTO explains to change your non-l10n application.

References

Editing files

Configure I18n module

Create the configuration file for i18n. This is the same as "standard" rails i18n way.

# in config/initializer/locale.rb

# Tell the I18n library where to find your translations
I18n.load_path += Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ]

# Tell the supported locales. This is the one of additional setting by Ruby-Locale for Ruby on Rails.
# If supported_locales is not set, the locale information which is given by WWW browser is used.
# This setting is required if your application wants to restrict the locales.
I18n.supported_locales = Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ].collect{|v| File.basename(v, ".*")}.uniq

# Tell the default locale. If this value is not set, "en" is set.
# With this library, this value is used as the lowest priority locale
# (If other locale candidates are not found, this value is used).
I18n.default_locale = "ja-JP" 

For single language application, set both of I18n.supported_locales, I18n.default_locale.

Load libraries

Load Ruby-Locale and Ruby-Locale for Ruby on Rails

# config/environment.rb
Rails::Initializer.run do |config|
 :
 :
 config.gem 'locale'
 config.gem 'locale_rails', :version => '2.0.4'
end

locale_rails depends on Rails version(because of monky patching), so it's better to set the version obviously. See 'Support Matrix' section of README.rdoc what rails version is supported.

ApplicationController

Basically, you need nothing in ApplicationController.

In I18n rails guide, "set_locale" method is introduced.

With this library, you don't need it.

# Don't need this
# app/controllers/application.rb
class ApplicationController < ActionController::Base
  before_filter :set_locale
  def set_locale
    I18n.locale = params[:locale] 
  end
end

Actually, this library has this kind of method in internal.

After this initialization, the application can know the locale in each request.

If you want to do something before/after the initialization process, you can use (before|after)_init_locale.

e.g.)
# app/controllers/application.rb
class ApplicationController < ActionController::Base
  def init_i18n
     OtherL10n.locale = Locale.candidates
  end
  after_init_locale :init_i18n
end

In this sample, OtherL10n is set the locale using Locale.candidates.

after_init_locale is aimed to initialize the L10n library which doesn't depend on Ruby on Rails i18n.

Views/ActionMailer

Your application can use Rails I18n features and they'll be localized to many languages in each request.

For example, to use I18n.t method to translate the messages.

# app/views/home/index.html.erb
<h1><%=t :hello_world %></h1>

Localized templates for Views/ActionMailer

ActionController::Base.render_text is overridden to find localized templates such as foo_ja.hml.erb, foo_ja_JP.html.erb.

(e.g.)

/app/views/blog/list.html.erb
/app/views/blog/list_ja.html.erb
/app/views/blog/list_ja_JP.html.erb

In this case, list_ja.html.erb is used when language is "ja" only. Otherwise list.rhml is used. You can use this way for render_partial. Use _foo.html.erb, _foo_ja.html.

Localized Routing

Using ":lang" in config/routes.rb, you can use localized URLs.

# config/routes.rb
ActionController::Routing::Routes.draw do |map|
  # Localized Routing.
  map.connect '/:lang/:controller/:action/:id'
  map.connect '/:lang/:controller/:action/:id.:format'
end

This :lang is used as param[:lang] and it is treated as the highest priority locale.

The URL of this routing is below:

http://www.foobar.com/ja_JP/foos/show
http://www.foobar.com/fr/foos/show

Then, url_for, link_to and foos_path are:

link_to "Click", :controller => :foos, :action => :show, :lang => lang
url_for :controller => :foos, :action => :show, :lang => lang
url = foos_path(:lang => lang)

Gets the locale

To get the locale information, use I18n.locale or I18n.candidates.

I18n.locale

I18n.locale is one of the method of Rails2.2 I18n API and it's extended by this library. This returns the highest priority locale from the user request.

# app/views/home/index.html.erb
<div><%= I18n.locale.inspect %></div>

The return value is not String but Locale::Tag::Rfc. It can behave like as String, so it can keep the compatibility with Rails I18n APIs. It means you can use the plugins/libraries depend on Rails I18n APIs.

Locale::Tag::Rfc is more flexible than String to treat the Language tags. You can convert RFC style to CLDR, POSIX or can just use region part only.

Locale.candidates

Locale.candidates(type) returns Locale::TagList which includes all locale candidates. The last candidate is the I18n.default_locale value.

Locale.candidates returns Common style(ja_Hira_JP_VARIANTS). It is the very common style, so Ruby-Locale recommand this. But you can also get other style with type argument such as :simple, :common, :rfc, :cldr, :posix.

# app/views/home/index.html.erb
<div><%= Locale.candidates.inspect %></div>

To set I18n.supported_locales, I18n.locale can return the correct locale which the application is supported.

For choosing other candidates, this method is very useful.

Locale.candidates.each do |lang|
  path = "/foo/bar/locale/#{lang}/foo.rb"
  if File.exist?(path)
    File.open(path)
       :
       :
    break
  end
end

I18n.locale is same with Locale.candidates(:type => :rfc)[0].

For Rails Plugins, Libraries

I18n.locale returns the value which defined in I18n.supported_locales.

Usually, I18n.supported_locales is defined by the application. And it returns the locale which is supported by the application.

Note that you need to consider what locale your plugin/library support. If your plugin/library will be used in many applications, they have each supported_locales and your plugin/library don't support any locales in the supported_locales. Thus, I18n.locale may returns the locale which your plugin/library doesn't support it.

So, it's better to use Locale.candidates and find a locale which your plugin/library supports.

How to get the locale information from WWW browser

The locale value is get from the order by "lang" value of QUERY_STRING > "lang" value of Cookie > HTTP_ACCEPT_LANGUAGE value > "en" (English). And the charset is set order by HTTP_ACCEPT_CHARSET > "UTF-8".

the application needs to set "lang" value of QUERY_STRING or Cookies properly by itself.

You can find the application is localized to access your application root such as http://foo/?lang=ja

If you want to set lang value to Cookie, then:

#blog_controller.rb
class BlogController < ApplicationController
      :
      :
  def cookie_locale
    cookies["lang"] = @params["id"]
    redirect_to :action => 'list'
  end
end

#blog.html.erb
<%= link_to "Set Locale to japanese", :action => "cookie_locale", :id => "ja" %>

Caching

Action/Fragment caches are avilable. The functions are extended by Ruby-Locale to manage data in each locales.

Page caching is not supported. I don't have any idea how do this now because both the http server and the rails app need to help each other to return the cache/non cache data. Tell me if you have good idea about Page caching.

ChangeLog

  • 2008-11-24: Created
Last modified:2009/09/23 11:47:20
Keyword(s):
References:[Ruby-Locale for Ruby on Rails]