A photo of me on a horse looking quite dapper

David Celis

A cowboy coder.

Follow me

Internationalization and the Rails Inflector

Here’s a peek at an enhancement for ActiveSupport::Inflector that was introduced in Rails 4.0 and which I’m proud to have contributed. The Inflector is the part of Rails responsible for a good amount of the cool stuff you can do with Strings: pluralization, singularization, titleization, humanization, tableization... The list goes on. Rails uses these methods extensively to map between, say, Model names, Controller names, database table names, and more. Let’s dive into the new stuff!

Previously, the Inflector could handle only one set of rules at a time. Rails provides a lengthy list of singularization and pluralization rules for English, but what if somebody wants to specify how certain words in a different language should be pluralized? In Rails 3, they had two options: they could define the words as irregularities in config/initializers/inflections.rb or add them one by one into locale files. The former is bad because it involves mixing two languages into one set of rules, and the latter can lead to large, cluttered locale files when internationalizing a website.

As of Rails 4, however, I’m happy to offer a better solution for Rails developers in the process of internationalization: a multilingual Inflector. It can manage a complete set of inflection rules for each locale! Rails will still only provide a list of inflections in English, but it’s now much easier to specify your own sets of rules for additional locales, or even to have them provided to you via a gem. You can, as previously, specify these rules in config/initializers/inflections.rb:

# You can pass any locale code as a parameter. This defaults to `:en`,
# but here we’re adding rules for Spanish (`:es`)!
ActiveSupport::Inflector.inflections(:es) do |inflect|
  inflect.plural(/$/, 's')
  inflect.plural(/([^aeéiou])$/i, '\1es')
  inflect.plural(/([aeiou]s)$/i, '\1')
  inflect.plural(/z$/i, 'ces')
  inflect.plural(/á([sn])$/i, 'a\1es')
  inflect.plural(/é([sn])$/i, 'e\1es')
  inflect.plural(/í([sn])$/i, 'i\1es')
  inflect.plural(/ó([sn])$/i, 'o\1es')
  inflect.plural(/ú([sn])$/i, 'u\1es')

  inflect.singular(/s$/, '')
  inflect.singular(/es$/, '')

  inflect.irregular('el', 'los')
end

After specifying our ruleset for Spanish, we can see it in action by passing the same locale code to methods defined by the inflector:

'avión'.pluralize      # => 'avións'
'avión'.pluralize(:es) # => 'aviones'
'luz'.pluralize        # => 'luzs'
'luz'.pluralize(:es)   # => 'luces'

Note that the Inflector will still default to English and use :en as the locale unless specified, despite the existence of the I18n.default_locale configuration. This is to avoid breaking applications that have been wired internally to use English pluralization rules for mapping between Model, Controller, and table names.

Where can I get rules for other locales?

I’m happy to offer a solution for this too! I’ve created a gem called Inflections that I’m hoping can serve as a central repository for inflection rules of all locales. Unfortunately, I’m not a master of linguistics. Aside from English, I am only comfortable with Spanish, and so that’s the only additional set of inflection rules I myself have provided (aside from a shorter list of English inflections that I believe to be stripped to the essentials). If you or anybody you know are a Rails developer and fluent in another language, please consider forking Inflections, making a list of inflections (lib/inflections/<locale>.rb) with tests (test/<locale>_test.rb) and opening a pull request.