public
Description: Rails: FastGettext, I18n integration -- simple, threadsafe and fast!
Homepage:
Clone URL: git://github.com/grosser/gettext_i18n_rails.git
grosser (author)
Thu Aug 13 23:15:49 -0700 2009
commit  92bc3e5fdac3de5ade1a125895de65c3dc352ed9
tree    1dffc75047635ce2ad7578c5673d651d775c84e7
parent  d0cd4a76f4e95e580110c847d55f0b74e00ef5a7
name age message
file README.markdown Tue Aug 11 11:15:11 -0700 2009 hacky haml parser replaced through superior get... [grosser]
file Rakefile Tue Feb 24 09:51:05 -0800 2009 empty tests running... [grosser]
file init.rb Sat May 16 22:22:58 -0700 2009 refixed rake gems:install bug, thanks @ matthuh... [grosser]
directory lib/ Thu Aug 13 23:15:49 -0700 2009 fixing bug introduced through last merge [grosser]
directory spec/ Thu Aug 13 23:15:49 -0700 2009 fixing bug introduced through last merge [grosser]
directory tasks/ Tue Mar 31 01:01:43 -0700 2009 updated to use gettext 1.93/2.0 for po/mo gener... [grosser]
README.markdown

Simple FastGettext / Rails integration.

Do all translations you want with FastGettext, use any other I18n backend as extension/fallback.

Rails does: I18n.t('weir.rails.syntax.i.hate')
We do: _('Just translate my damn text!')
To use I18n calls define a weir.rails.syntax.i.hate translation.

See it working in the example application.

Setup

Installation

This plugin: script/plugin install git://github.com/grosser/gettext_i18n_rails.git

FastGettext: sudo gem install grosser-fast_gettext -s http://gems.github.com/

GetText 1.93 or GetText 2.0: sudo gem install gettext
GetText 2.0 will render 1.93 unusable, so only install if you do not have apps that use 1.93!

RubyParser if you want to parse ruby files for gettext calls. sudo gem install ruby_parser

Locales & initialisation

Copy default locales you want from e.g. rails i18n: rails/locale/de.yml into 'config/locales'

#environment.rb
Rails::Initializer.run do |config|
  ...
  config.gem "grosser-fast_gettext", :lib => 'fast_gettext', :version => '~>0.4.9', :source=>"http://gems.github.com/"
  #only used for mo/po file generation in development, !do not load(:lib=>false)! since it will only eat 7mb ram
  config.gem "gettext", :lib => false, :version => '>=1.9.3'
end

#config/initialisers/fast_gettext.rb
FastGettext.add_text_domain 'app', :path => 'locale'

#application_controller
class ApplicationController < ...
  before_filter :set_gettext_locale
  def set_gettext_locale
    FastGettext.text_domain = 'app'
    FastGettext.available_locales = ['en','de'] #all you want to allow
    super
  end

Translating

Getting started

Option A: Traditional mo/po files

  • use some _('translations')
  • run rake gettext:find, to let GetText find all translations used
  • (optional) run rake gettext:store_model_attributes, to parse the database for columns that can be translated
  • if this is your first translation: cp locale/app.pot locale/de/app.po for every locale you want to use
  • translate messages in 'locale/de/app.po' (leave msgstr blank and msgstr == msgid)
    new translations will be marked "fuzzy", search for this and remove it, so that they will be used. Obsolete translations are marked with ~#, they usually can be removed since they are no longer needed
  • run rake gettext:pack to write GetText format translation files

Option B: Database

This is the most scalable method, since all translators can work simultanousely and online, it is new, so please give me feedback!

Most easy to use with the translation database Rails engine. FastGettext setup would look like:

include FastGettext::TranslationRepository::Db.require_models #load and include default models
FastGettext.add_text_domain 'app', :type=>:db, :model=>TranslationKey

Translations can be edited under /translation_keys

I18n

Through Ruby magic:

I18n.locale is the same as FastGettext.locale.to_sym
I18n.locale = :de  is the same as FastGettext.locale = 'de'

Any call to I18n that matches a gettext key will be translated through gettext.

Namespaces

Car|Model means Model in namespace Car.
You do not have to translate this into english "Model", if you use the namespace-aware translation

s_('Car|Model') == 'Model' #when no translation was found

ActiveRecord - error messages

ActiveRecord error messages are translated through Rails::I18n, but model names and model attributes are translated through FastGettext. Therefore a validation error on a BigCar's wheels_size needs _('big car') and _('BigCar|Wheels size') to display localized.

The model/attribute translations can be found through rake gettext:store_model_attributes, (which ignores some commonly untranslated columnslike id,type,xxx_count,...).

Error messages can be translated through FastGrttext, if the ':message' has a translation or the Rails I18n key is translated. In any other case they go through the SimpleBackend.

Option A:

Define a translation for "I need my rating!" and use it as message.

validates_inclusion_of :rating, :in=>1..5, :message=>N_('I need my rating!')

Option B:

Do not use :message

validates_inclusion_of :rating, :in=>1..5

and make a translation for the I18n key: activerecord.errors.models.rating.attributes.rating.inclusion

Option C:

Add a translation to each config/locales/*.yml files

en:
  activerecord:
    errors:
      models:
        rating:
          attributes:
            rating:
              inclusion: " -- please choose!"

The rails I18n guide can help with Option B and C.

Plurals

GetText supports pluralization

n_('Apple','Apples',3) == 'Apples'

Unfound translations

Sometimes translations like _("x"+"u") cannot be fond. You have 4 options:

  • add N_('xu') somewhere else in the code, so the parser sees it
  • add N_('xu') in a totally seperate file like locale/unfound_translations.rb, so the parser sees it
  • use the gettext_test_log rails plugin to find all translations that where used while testing
  • add a Logger to a translation Chain, so every unfound translations is logged (example))

Author

Michael Grosser
grosser.michael@gmail.com
Hereby placed under public domain, do what you want, just do not hold me accountable...