Fork me on GitHub

R18n is an tool to internationalize and localize your Rails, Sinatra or desktop Ruby application.

Why R18n?

Ruby-style Syntax

R18n uses hierarchical, not English-centric, YAML format for translations by default:

user:
  edit: Edit user
  name: User name is %1
  count: !!pl
    1: There is 1 user
    n: There are %1 users

To access translation you can call methods with the same names:

t.user.edit         #=> "Edit user"
t.user.name('John') #=> "User name is John"
t.user.count(5)     #=> "There are 5 users"

t.not.exists | 'default' #=> "default"
t.not.exists.translated? #=> false

If the translation key is the name of an Object method you can access it via hash index:

t[:methods] #=> "Methods"

Filters

You can add custom filters for YAML types or any translated string. Filters are cascading and can communicate with each other.

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

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

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

Flexibility

Translation variables and pluralization (“1 comment”, “5 comments”) are filters too, so you can extend or replace them. For example, you can use the ‘named variables filter’ from the r18n-rails-api gem:

greeting: "Hi, %{name}"

R18n::Filters.on(:named_variables)
t.greeting(name: 'John') #=> "Hi, John"

Flexible Locales

Locales extend the Locale class. For example, English locale extends the time formatters:

l Date.now, :full #=> "30th of November, 2009"

Russian has built-in pluralization without any lambdas in YAML:

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

Loaders

R18n can load translations from anywhere, not just from YAML files. You just need to create loader object with 2 methods: available and load:

class DBLoader
  def available
    Translation.find(:all).map(&:locale)
  end
  def load(locale)
    Translation.find(locale).to_hash
  end
end

R18n.set(user_locales, DBLoader.new)

You can also set a list of different translation locations or set extension locations which will be only used with application translation (useful for plugins).

Object Translation

You can translate any class, including ORM models (ActiveRecord, DataMapper, MongoMapper, Mongoid or others):

require 'r18n-core/translated'

class Product < ActiveRecord::Base
  include R18n::Translated
  # Model has two normal properties: title_en and title_ru
  translations :title
end

# For English users
product.title #=> "Anthrax"

# For Russian users
product.title #=> "Сибирская язва"

Localization

R18n can localize numbers and time:

l -5000                 #=> "−5,000"
l Time.now              #=> "30/11/2009 14:36"
l Time.now, :full       #=> "30th of November, 2009 14:37"
l Time.now - 60, :human #=> "1 minute ago"

Several User Languages

If a particular locale is requested but missing, R18n will automatically take the next available language (according to the browser’s list of locales) and for cultures with two official languages (e.g., exUSSR) it takes the second language (e.g., if a translation isn’t available in Kazakh R18n will look for Russian):

i18n = R18n::I18n.new(['kk', 'de'], 'dir/with/translations')

i18n.locales    #=> [Locale kk (Қазақша), Locale de (Deutsch),
                #    Locale ru (Русский), Locale en (English)]

i18n.kazakh  #=> "Қазақша", main user language
i18n.deutsch #=> "Deutsch", not in Kazakh, use next user locale
i18n.russian #=> "Русский", not in kk and de, use Kazakh sublocale
i18n.english #=> "English", not in any user locales, use default

Agnostic

R18n has an agnostic core package and plugins with out-of-box support for Sinatra, Merb and desktop applications.

Locales

R18n support Czech, Deutsch, English, Esperanto, Spanish, French, Italian, Kazakh, Polish, Brazilian Portuguese, Russian, Slovak, Thai and Chinese languages. And you can easy add you own locale.