My presentation on I18n during Ruby India Conference 2010, Bangalore, India
Size: 2.75 MB
Language: en
Added: Jul 15, 2010
Slides: 58 pages
Slide Content
The Ruby on Rails I18n The Ruby on Rails I18n
Core APICore API
PRESENTED BYPRESENTED BY
-Neeraj Kumar-Neeraj Kumar
IntroductionIntroduction
•English – Default Language.English – Default Language.
•GettextGettext
•Tough Task – transform your ROR App into its Tough Task – transform your ROR App into its
regional language & providing a tool to solve all regional language & providing a tool to solve all
problems at once.problems at once.
•Provides easy-to-use and extensible framework.Provides easy-to-use and extensible framework.
• Translating Translating
- to a single custom language other than English.- to a single custom language other than English.
- for providing multi-language support.- for providing multi-language support.
• To abstract all strings and other locale specific bits To abstract all strings and other locale specific bits
(such as date or currency formats) out of your (such as date or currency formats) out of your
application. The process of “localization” means to application. The process of “localization” means to
provide translations and localized formats for these bits.provide translations and localized formats for these bits.
•Sven FuchsSven Fuchs
•Shipped with rails (started with rails-2.2)Shipped with rails (started with rails-2.2)
• In the process of internationalizing: In the process of internationalizing:
–Ensure you have support for i18nEnsure you have support for i18n
–Tell Rails where to find locale dictionariesTell Rails where to find locale dictionaries
–Tell Rails how to set, preserve and switch localeTell Rails how to set, preserve and switch locale
SetupSetup for RoR App for RoR App
•Configure the I18n ModuleConfigure the I18n Module
–.rb and .yml + .rb and .yml + translations load pathtranslations load path, automatically., automatically.
–translations load path (translations load path (I18n.load_pathI18n.load_path) - will be ) - will be
loaded automatically and available in your loaded automatically and available in your
application.application.
–environment.rbenvironment.rb - instructions to customize the - instructions to customize the
locale directory and default locale.e.g.locale directory and default locale.e.g.
# config.i18n.load_path << # config.i18n.load_path <<
Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.
{rb,yml}')]{rb,yml}')]
# config.i18n.default_locale = :de # config.i18n.default_locale = :de
en: en:
hello: "Hello world"hello: "Hello world"
•Setting and Passing the LocaleSetting and Passing the Locale
- For more locales - to set and pass the locale between - For more locales - to set and pass the locale between
requests.requests.
- Don't use session or cookies to store the chosen locale.- Don't use session or cookies to store the chosen locale.
before_filter :set_locale
def set_locale
# if params[:locale] is nil then
I18n.default_locale will be used
I18n.locale = params[:locale]
end
- URL : - URL : http://example.com/books?locale=pthttp://example.com/books?locale=pt - will load - will load
Portuguese localization.Portuguese localization.
•Locale setting from the URL ParamsLocale setting from the URL Params
- link_to( books_url(:locale => I18n.locale)) - tedious - link_to( books_url(:locale => I18n.locale)) - tedious
and probably impossible.and probably impossible.
- For 'centralizing dynamic decisions about the URLs' - For 'centralizing dynamic decisions about the URLs'
in its ApplicationController#default_url_options.in its ApplicationController#default_url_options.
# app/controllers/application_controller.rb
def default_url_options(options = {})
logger.debug “default_url_options is passed
options:
#{options.inspect}\n”
{:locale => I18n.locale}
end
- Every helper method dependent on url_for - Every helper method dependent on url_for
automatically include the locale in the query stringautomatically include the locale in the query string..
- Drawback of default_url_options - Drawback of default_url_options
implementation pass the :id option, e.g. link_to implementation pass the :id option, e.g. link_to
'show', book_url(:id => book) 'show', book_url(:id => book)
•Locale setting from the Domain NameLocale setting from the Domain Name
- advantages- advantages
–Locale, an obvious part of URLLocale, an obvious part of URL
–Trivial to implementTrivial to implement
–Intuitively grasp the language of content Intuitively grasp the language of content
before loadingbefore loading
–Search engines like content in different Search engines like content in different
languages at different domains.languages at different domains.
before_filter :set_locale
def set_locale
I18n.locale = extract_locale_from_uri
end
def extract_locale_from_tld
parsed_locale = request.host.split('.').last
I18n.available_locales.include?
(parsed_locale.to_sym) ? parsed_locale : nil
end
- parsed_locale = request.host.split('.').first to set the - parsed_locale = request.host.split('.').first to set the
locale from subdomain.locale from subdomain.
•Locale setting from the Client Supplied InformationLocale setting from the Client Supplied Information
- information can come from - information can come from
–Users preferred language (set in their Users preferred language (set in their
browser)browser)
–Users geographical location inferred from IPUsers geographical location inferred from IP
–By choosing locale in your application By choosing locale in your application
interface and saving to the profile.interface and saving to the profile.
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE' ].scan(/^[a-z]
{2}/).first
end
- Using GeoIP (or similar) Database – GeoIP Lite - Using GeoIP (or similar) Database – GeoIP Lite
CountryCountry
- User Profile- User Profile
en:
activerecord:
models:
user: foo
admin: bar
attributes:
user:
login: “Handle” # => will translate User
attribute “login” as “Handle”
Active Record Model TranslationsActive Record Model Translations
en:
activerecord:
errors:
messages:
blank: “can not has nothing”
# => #<User id:nil, etc>
# => u.valid?
# => false
# => u.errors.on(:name)
# => “can not has nothing”
–Error Messages ScopeError Messages Scope - Active Record - Active Record
Validation Error Messages TranslationValidation Error Messages Translation
–Active Record will look up this key in the Active Record will look up this key in the
namespacesnamespaces
–activerecord.errors.models.activerecord.errors.models.
[model_name].attributes.[attribute_name] [model_name].attributes.[attribute_name]
–activerecord.errors.models.[model_name] activerecord.errors.models.[model_name]
–activerecord.errors.messages activerecord.errors.messages
en:
activerecord:
errors:
messages:
already_registered: “u already is
{{model}}”
# => u.errors.on(:email)
# => “u already is foo”
–Error Message InterpolationError Message Interpolation
–Count can be used for PluralizationCount can be used for Pluralization
–Translation for the Active Record Translation for the Active Record
error_messages_for Helpererror_messages_for Helper
en:
activerecord:
errors:
template:
header:
one: “1 error prohibted this {{model}} from being
saved”
other: “{{count}} errors prohibted this {{model}} from
being saved”
body: “There were problems with the following fields:”
Anatomy of GemAnatomy of Gem
i18n
i18n
backend core_ext helpers locales
backend
exceptions
gettext
helpers
locale
i18n
version
locale
gettext
fallbackstag
i18n.rbi18n.rb
•get and set methods for default_locale.get and set methods for default_locale.
def default_locale(locale)
@@default_locale = locale.to_sym rescue
nil
end
•Get method for locale - either default_locale or locale Get method for locale - either default_locale or locale
in in Thread.currentThread.current hash. hash.
i18n.rbi18n.rb
•Set method for locale - set the locale in Set method for locale - set the locale in Thread.currentThread.current
•Returns the current backend.Returns the current backend.
def backend
@@backend ||= Backend::Simple.new
end
•Set method for current backend.Set method for current backend.
simple.rbsimple.rb
•Makes easier to extend the Simple backend's Makes easier to extend the Simple backend's
behaviour by including modules e.g. behaviour by including modules e.g.
I18n::Backend::Simple.send(:include, I18n::Backend::Simple.send(:include,
I18n::Backend::Pluralization).I18n::Backend::Pluralization).
module I18n
module Backend
class Simple
include Base
end
end
end
i18n.rbi18n.rb
def available_locales
@@available_locales ||=
backend.available_locales
end
I18n.rbI18n.rb
•Default scope separator method (i.e Default scope separator method (i.e
default_separator) default_separator)
–set your separator set your separator
–return the separator.return the separator.
•Default is '.'Default is '.'
I18n.rbI18n.rb
•Exception handler method (i.e. exception_handler)Exception handler method (i.e. exception_handler)
–set your exception handlerset your exception handler
–return the current exception handler.return the current exception handler.
•Default is :default_exception_handler private method.Default is :default_exception_handler private method.
I18n.rbI18n.rb
def default_exception_handler(exception, locale, key,
options)
return exception.message if MissingTranslationData
=== exception
raise exception
end
I18n.rbI18n.rb
•load_path=(load_path) method - set load path instance.load_path=(load_path) method - set load path instance.
•load_path methodload_path method
–*.rb*.rb and contain plain and contain plain RubyRuby Hashes.Hashes.
–*.yml*.yml and contain and contain YAMLYAML data. data.
I18n.rbI18n.rb
•Method to reload the translations.Method to reload the translations.
•Main method Main method translatetranslate and and localizelocalize
•I18n.t :message I18n.t :message I18n.t 'message' I18n.t 'message'
I18n.rbI18n.rb
•Translation method – scope options, interpolation, Translation method – scope options, interpolation,
pluralization, defaults pluralization, defaults
•:scope option – one or many keys - scope for a :scope option – one or many keys - scope for a
translation keytranslation key
I18n.t :invalid, :scope => [:active_record,
:error_messages] # => I18n.translation :invalid
:active_record.error_messages.invalid
I18n.rbI18n.rb
def localize(object, options = {})
locale = options.delete(:locale) || config.locale
format = options.delete(:format) || :default
config.backend.localize(locale, object, format,
options)
end
alias :l :localize
base.rbbase.rb
•load_translations method - accepts list of paths of load_translations method - accepts list of paths of
translation files.translation files.
def load_translations(*filenames)
filenames.each { |filename|
load_file(filename) }
end
base.rbbase.rb
def load_file(filename)
type = File.extname(filename).tr('.', '').downcase
raise UnknownFileType.new(type, filename)
unless respond_to?(:”load_#(type)”)
data = send(:”load_#(type)”, filename)
data.each { |locale, d| merge_translation(locale, d)
}
end
raise(I18n::MissingTranslationData.new(locale,
key, options)) if entry.nil?
entry = pluralize(locale, entry, count) if
count
entry = interpolate(locale, entry, values) if
values
end
entry
end
base.rbbase.rb
base.rbbase.rb
•look_up method look_up method
–looks up the translation from the translations hash. looks up the translation from the translations hash.
–Splits keys or scopes containing dots into multiple Splits keys or scopes containing dots into multiple
keys e.g. currency.format - %w(currency format).keys e.g. currency.format - %w(currency format).
base.rbbase.rb
•localize methodlocalize method
case match
when '%a' then I18n.t(:"date.abbr_day_names”, :locale =>
locale, :format => format)[object.wday]
when '%A' then I18n.t(:"date.day_names”, :locale =>
locale, :format => format)[object.wday]
when '%b' then I18n.t(:"date.abbr_month_names", :locale
=> locale, :format => format)[object.mon]
when '%B' then I18n.t(:"date.month_names", :locale =>
locale, :format => format)[object.mon]
when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am :
:pm}", :locale => locale, :format => format) if
object.respond_to? :hour
end
base.rbbase.rb
CustomizationCustomization
•Different BackendsDifferent Backends
–I18n::Backend::SimpleI18n::Backend::Simple
–shipped with Active Support of vendor shipped with Active Support of vendor
directory, work for english or similar directory, work for english or similar
languages.languages.
–capable of reading translations but cannot capable of reading translations but cannot
dynamically store them to any format.dynamically store them to any format.
MissingTranslationData # no translation was found for the
requested key
InvalidLocale # the locale set to I18n.locale is invalid (e.g. nil)
•Different Exception HandlersDifferent Exception Handlers
- customization – e.g. the default exception handling - customization – e.g. the default exception handling
does not allow to catch missing translation during does not allow to catch missing translation during
automated test easilyautomated test easily..
–I18nI18n
–own backendown backend
–makes easy to exchange the Simple backend makes easy to exchange the Simple backend
implementation with that to fits better with implementation with that to fits better with
your need.your need.
I18n.backend = Globalize::Backend::Static.new
module I18n
def just_raise_that_exception(*args)
raise args.first
end
end
I18n.exception_handler = :just_raise_that_exception