i18n snippets

How to use the new internationalization (I18n) API available in Rails 2.2

Tagged ruby, rails, i18n  Languages ruby

Not yet released, but you can try it out by first installing the i18n gem:

sudo gem install i18n

And then testing the following code:

require 'rubygems'
require 'i18n'

I18n.store_translations 'en-US',
    :yes => "yes",
    :no => "no", 
    :inbox => {
      :one => '1 message', 
      :other => '{{count}} messages'
    }

I18n.store_translations 'sv',
    :yes => "ja",
    :no => "nej", 
    :inbox => {
      :one => '1 meddelande', 
      :other => '{{count}} meddelanden'
    }

I18n.locale = 'en-US'

puts I18n.translate(:yes)
puts I18n.translate(:inbox, :count => 1)
puts I18n.translate(:inbox, :count => 2)
puts I18n.localize Time.now


I18n.locale = 'sv'


puts I18n.translate(:yes)
puts I18n.translate(:inbox, :count => 1)
puts I18n.translate(:inbox, :count => 2)
puts I18n.localize Time.now

Troubleshooting

Note that the gem doesn't contain localization data, so you'll get the following error:

translation missing: en-US, time, formats (I18n::MissingTranslationData)

To fix this, simply tell the I18n gem where to find the locales you want to use:

I18n.load_translations "#{RAILS_ROOT}/locales/#{locale}.rb"

Creating a shortcut for i18n.translate

I recommend you create a shortcut for I18n.translate to the Symbol and String classes:

class Symbol
    def t(params = {})
        I18n.t(self, params)
    end
end

class String
    def t(params = {})
        I18n.t(self.to_s, params)
    end
end

Now instead of this:

puts I18n.translate(:yes)
puts I18n.translate(:inbox, :count => 1)
puts I18n.translate(:inbox, :count => 2)

You can type:

puts :yes.t
puts :inbox.t(:count => 1)
puts :inbox.t(:count => 2)

Handling missing translations

You can use this code to change the default behavior for missing translations, instead of showing "Missing translation" this code allows you to log the missing translation:

module I18n
  module DateTimeExtensions

    def l(params = {})
      params.update({:format => :short})

      I18n.l(self, params)
    end
  end

  module StringExtensions

    def t(params = {})
      params.update({:raise => true})

      key = self
      key = self.downcase.to_s if key.is_a?(String)

      begin
        I18n.t(key, params)
      rescue I18n::MissingTranslationData
        RAILS_DEFAULT_LOGGER.info("Translation for '#{self}' is missing")
        self
      end
    end
  end

end

class Symbol
  include I18n::StringExtensions
end

class String
  include I18n::StringExtensions
end

class Time
  include I18n::DateTimeExtensions
end

References

  1. http://github.com/svenfuchs/i18n/
  2. http://github.com/clemens/i18n_demo_app/
  3. http://www.artweb-design.de/2008/7/18/the-ruby-on-rails-i18n-core-api
  4. How to use the new I18n API with Rails

Fixing "DEPRECATION WARNING: ActiveRecord::Errors.default_error_messages has been deprecated."

Tagged i18n, translation, rails2.2, deprecation, default_error_messages  Languages ruby

With versions prior to Rails 2.2 you used to be able to translate ActiveRecord error messages through this method:

ActiveRecord::Errors.default_error_messages[:too_long] = " är för långt (max %d tecken)"

Now with Rails 2.2 you'll get this error message:

DEPRECATION WARNING: ActiveRecord::Errors.default_error_messages has been deprecated. Please use I18n.translate('activerecord.errors.messages').. (called from default_error_messages at /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/validations.rb:24)

In the view you'll see something like:

* Stad translation missing: sv, activerecord, errors, models, order, attributes, city, too_short

To fix this, first create lib/initializers/i18n.rb:

I18n.load_path += Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ]
I18n.default_locale = "en" # default language

This file initializes the i18n library, telling it where to find the translations and what the default locale is.

Next, create the file containing translations, for example lib/locale/en.yml:

"en":
  activerecord:
      errors:
        templates:
          header:
            one: "1 error prohibited this {{model}} from being saved"
            other: "{{count}} errors prohibited this {{model}} from being saved"
          body: "there were problems with the following fields:"
        messages:
          accepted: "must be accepted"
          blank: "can't be blank"
          confirmation: "doesn't match confirmation"
          empty: "can't be empty"
          equal_to: "must be equal to {{count}}"
          even: "must be even"
          exclusion: "is reserved"
          greater_than: "must be greater than {{count}}"
          greater_than_or_equal_to: "must be greater than or equal to {{count}}"
          inclusion: "is not included in the list"
          invalid: "is invalid"
          less_than: "must be less than {{count}}"
          less_than_or_equal_to: "must be less than or equal to {{count}}"
          not_a_number: "is not a number"
          odd: "must be odd"
          taken: "is already taken"
          too_long: "is too long (maximum is {{count}} characters)"
          too_short: "is too short (minimum is {{count}} characters)"
          wrong_length: "is the wrong length (should be {{count}} characters)"

Credits go to this thread which is where I found the code.

The I18n project has translations for most languages so it's best to copy them from there. For example, Swedish translation of text in Rails can be found here: http://github.com/svenfuchs/rails-i18n/raw/master/rails/locale/sv-SE.yml

Translating attribute names

Use this code to translate the attribute names:

class Order < ActiveRecord::Base

  def self.human_attribute_name(attr)
    I18n.t("#{class_name.downcase}.#{attr.to_sym}") || super
  end

Translating everything else

A full list of things you can translate can be found on the rails i18n wiki

How to get the localized name of a folder also called displayed name with AppleScript

Tagged displayed name, i18n, applescript, localized  Languages applescript

Not using the localized name of folders or items is a basic mistake made in almost all AppleScript examples I've seen.

For example, this code won't work on a Swedish OSX where the Applications folder's name is Program:

tell application "Finder"
    -- Mount a DMG
    .
    .
    .
    set position of item "Applications" to {175, 65}
end tell

The correct way of referencing folders is by using the localized name which you can get through the displayed name attribute like this:

tell application "Finder"
    -- Mount a DMG
    .
    .
    .
    set applications_folder to displayed name of (path to applications folder) -- i18n name
    set position of item applications_folder to to {175, 65}
end tell

This is the line which retrieves the localized name of the folder and stores it in a variable named applications_folder:

set applications_folder to displayed name of (path to applications folder) -- i18n name

Localizing URLs and Rails3 routes

Tagged i18n, routes, rails3, url, seo  Languages ruby

If you need to support localized URLs in a Rails application, you have at least two plugins to choose from: * i18n_routing NOTE: doesn't seem to work with Rails 3.2.8 * rails-translate-routes

I recommend the rails-translate-routes plugin because it allows me to create exactly the URLs I need.

For example, if these are the localized URLs I need:

http://xxx.com/news
http://yyy.com/uutiset
http://zzz.com/nyheter

How to Use Rails I18n With JavaScript/CoffeeScript

Tagged rails, i18n, javascript, coffeescript  Languages javascript

Option 1: Include all translations

Your app/assets/javascripts/i18n.js.coffee.erb file:

root = exports ? this
I18n = <%= I18n.backend.send(:translations).to_json.html_safe %>
$ ->
  root.I18n = I18n[$('body').data('lang')]

Option 2: Include a limited set of translations

Your app/assets/javascripts/i18n.js.coffee.erb file:

root = exports ? this

I18n =
<%
I18n.available_locales.each do |lang|
  I18n.with_locale lang do
%>
  <%= lang %>:
    text: "<%= I18n.t("js.text") %>"
<%
  end
end
%>

$ ->
  root.I18n = I18n[$('body').data('lang')]

Include the Selected Locale in the Rails Layout

The view defines the user's selected locale:

<body data-lang="<%= I18n.locale %>">
...
</body>

How to Translate JavaScript Strings

We can now translate strings in a JavaScript file:

# remember to use $(document).ready...
alert(I18n.text)

I18n for ActiveRecord Model Attributes

Tagged active_record, i18n  Languages ruby

This code will translate the AR model's title attribute using Rails' I18n library:

class Link < ActiveRecord::Base
  I18N_ATTRIBUTES = [ :title ]
  I18N_ATTRIBUTES.each do |attr|
    class_eval <<-EORUBY, __FILE__, __LINE__ + 1
      def #{attr}
        I18n.t(self[:#{attr}], default: self[:#{attr}])
      end
    EORUBY
  end
end

If a translation is not defined, the code will fall back to use the attribute's original value.

Example with translation defined:

Translation file (config/locales/en.yml):

en:
  views:
    index:
      title: Hello

Model code (app/models/link.rb):

link.title = 'views.index.title'
# Uses string from config/locales/en.yml
link.title => "Hello"

Example without translation defined

link = Link.new title: 'Hello'
# Fall back to specified value, because no translation is defined
link.title => "Hello"

How to find the I18n key and more for ActiveRecord models

Tagged activerecord, i18n, localization, key  Languages ruby

Use ActiveModel’s model_name method to find

User.model_name
User.i18n_scope # => :activerecord
User.model_name.i18n_key # => :user
User.model_name.route_key # => :user
User.model_name.partial_path # => users/user

# Find full name
klass = User
attribute_name = 'name'
puts "#{klass.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute_name}"
=> activemodel.attributes.user.name

# Find all translations
I18n.backend.send(:translations)[:en][:activemodel][:attributes]

See Rails’ source code (ActiveModel::Name, etc) for details on this complete mess:

If all else fails you can try to find the correct key by debugging the human_attribute_name method with, e.g, pry:

User.method(:human_attribute_name).source_location
[
    [0] ".../gems/activemodel-4.2.7.1/lib/active_model/translation.rb",
]