R18n for Rails

R18n-rails is a gem to add out-of-box R18n support to Rails I18n.

It is a wrapper for R18n Rails API and R18n core libraries. See R18n core documentation for more information.

Features

R18n for Rails is fully compatibile with Rails I18n, and add extra features:

R18n Syntax

You can use more compact, explicit and ruby-style syntax.

Translations in R18n format will be loaded from app/i18n/locale.yml:

user:
  name: User name is %1
  count: !!pl
    0: No users
    1: 1 user
    n: %1 users

R18n extends t helper to add optional R18n syntax:

t.user.name('John')      #=> "User name is John"
t.user.count(5)          #=> "5 users"
t.not.exists | 'default' #=> "default"

Filters

R18n has flexible architecture based on filters. Variables, pluralization, untranslated are common filters, and you can change them all. For example, write untranslated keys to file:

R18n::Filters.add(::R18n::Untranslated, :write_untranslated) do
|v, c, translated, untranslated, path|
  File.open('untranslated.list', 'w') do |io|
    io.puts(path)
  end
end

R18n already has filters for HTML escaping, lambdas, Textile and Markdown:

hi: !!markdown
  **Hi**, people!
greater: !!escape
  1 < 2 is true

i18n.hi      #=> "<p><strong>Hi</strong>, people!</p>"
i18n.greater #=> "1 &lt; 2 is true"

Model Translation

R18n can add i18n support for your ActiveRecord model and any other class (include DataMapper, MongoMapper, Mongoid):

  1. Add separate columns for all supported translations:

    def self.up
      create_table :posts do |t|
        t.string :title_en
        t.string :title_ru
      end
    end
    
  2. Add virtual method title, which will use title_locale methods to find actual translation:

    class Post < ActiveRecord::Base
      include R18n::Translated
      translations :title
    end
    
    # For Russian user
    post = Post.new
    post.title_en = 'Post'
    post.title_ru = 'Запись'
    post.title = 'Запись'
    
    post.title = 'Другая' # will use title_ru, by first user's locale
    

Time Fomatters

R18n add full time formatter based on locale info:

# English
l Time.now, :full #=> "1st of December, 2009 12:00"

# French
l Time.now, :full #=> "1er décembre 2009 12:00"

Locales

R18n contains locales info, so it supports locale pluralization and fallback rules for non-English locales out-of-box:

# Russian have different plural rules:
user:
  count: !!pl
    0: Нет пользователей
    1: %1 пользователь
    2: %1 пользователя
    n: %1 пользователей

t.user.count(2)  #=> "2 пользователя"
t.user.count(21) #=> "21 пользователь"

Autodetect User Locales

R18n automatically generate fallbacks for current user, based on user locales list from HTTP_ACCEPT_LANGUAGE, locale info (in some countries people know several languages), and default locale.

For example, if user know Kazakh and German, R18n will try find translations in: Kazakh → German → Russian (second language in Kazakhstan) → English (default locale).

Separated I18n

You can create another R18n I18n instance with another languages. For example, to send e-mail for English admin on error with French user:

puts I18n.t :error # Show error in French

admin_i18n = R18n::I18n.new(@admin_locales, Rails.root + 'app/i18n')
send_email(admin_i18n.error_messages)

How To

  1. Add r18n-rails gem to your config/environment.rb:

    config.gem 'r18n-rails'
    

    Now R18n will autodetect user locales.

  2. Define your way to set locale manually. R18n will find it in params[:locale] or session[:locale]. Best way is a put optional locale prefix to URLs:

    map.connect ':controller/:action'
    map.connect ':locale/:controller/:action'
    
  3. Print available translations, to choose from them manually (and to helpsearch engines):

    <ul>
    <% r18n.available_locales.each do |locale| %>
        <li>
          <a href="/<%= locale.code %>/"><%= locale.title %></a>
        </li>
    <% end %>
    </ul>
    
  4. Translations in I18n format are stored in config/locales/locale.yml:

    en:
      user:
        name: "User name is %{name}"
        count:
          zero: "No users"
          one:  "One user"
          many: "%{count} users"
    

    Translations in R18n format go to app/i18n/locale.yml:

    user:
      name: User name is %1
      count: !!pl
        0: No users
        1: 1 user
        n: %1 users
    
  5. Use translated messages in views. You can use Rails I18n syntax:

    t 'user.name', :name => 'John'
    t 'user.count', :count => 5
    

    or R18n syntax:

    t.user.name(:name => 'John') # for Rails I18n named variables
    t.user.name('John')          # for R18n variables
    t.user.count(5)
    
  6. Print dates and numbers in user’s tradition:

    l Date.today, :standard #=> "20/12/2009"
    l Time.now,   :full     #=> "20th of December, 2009 12:00"
    l 1234.5                #=> "1,234.5"
    
  7. Translate models:

    1. Add to migration columns for each of the supported locales, named as name_locale:

      t.string :title_en
      t.string :title_ru
      
      t.string :text_en
      t.string :text_ru
      
    2. Add R18n::Translated mixin to model:

      class Post < ActiveRecord::Base
        include R18n::Translated
      
    3. Call translations method in model with all columns to be translated:

      translations :title, :text
      

      Now model will have virtual methods title, text, title= and text=, which will call title_ru or title_en and etc based on current user locales.

    You can use R18n::Translated mixin for any Ruby class, not only for ActiveRecord models.

  8. Download translations for Rails system messages (validation, etc) from github.com/svenfuchs/rails-i18n/tree/master/rails/locale and put them to config/locales/ (because them use Rails I18n format).

License

R18n is licensed under the GNU Lesser General Public License version 3. You can read it in LICENSE file or in www.gnu.org/licenses/lgpl.html.

Author

Andrey “A.I.” Sitnik <[email protected]>