The Ruby on Rails I18n Core API PRESENTED BY -Neeraj Kumar
Introduction <ul><li>English – Default Language. </li></ul><ul><li>Gettext </li></ul><ul><li>Tough Task – transform your R...
<ul><li>Provides easy-to-use and extensible framework. </li></ul><ul><li>Translating  </li></ul><ul><li>- to a single cust...
<ul><li>To abstract all strings and other locale specific bits (such as date or currency formats) out of your application....
<ul><li>In the process of internationalizing:  </li></ul><ul><ul><li>Ensure you have support for i18n </li></ul></ul><ul><...
Setup  for RoR App <ul><li>Configure the I18n Module </li></ul><ul><ul><li>.rb and .yml +  translations load path , automa...
<ul><ul><li>environment.rb  - instructions to customize the locale directory and default locale.e.g. </li></ul></ul><ul><l...
<ul><li>Setting and Passing the Locale </li></ul><ul><li>- For more locales - to set and pass the locale between requests....
before_filter  :set_locale def   set_locale # if params[:locale] is nil then I18n.default_locale will be used I18n .locale...
<ul><li>Locale setting from the URL Params </li></ul><ul><li>- link_to( books_url(:locale => I18n.locale)) - tedious and p...
# app/controllers/application_controller.rb def  default_url_options (options = {}) logger.debug  “default_url_options is ...
# config/routes.rb map.resources   :books ,   :path_prefix   =>   '/:locale' # =>  www.example.com/nl/books map.root   '/:...
- Drawback of default_url_options    implementation pass the :id option, e.g. link_to    'show', book_url(:id => book)
<ul><li>Locale setting from the Domain Name </li></ul><ul><li>- advantages </li></ul><ul><ul><ul><ul><li>Locale, an obviou...
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_loca...
<ul><li>Locale setting from the Client Supplied Information </li></ul><ul><li>- information can come from  </li></ul><ul><...
def   set_locale logger.debug =  “* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}” I18n .locale = extract_locale...
def   extract_locale_from_accept_language_header request.env[ 'HTTP_ACCEPT_LANGUAGE' ].scan( /^[a-z]{2}/ ).first end - Usi...
en: activerecord: models: user: foo admin: bar attributes: user:  login: “Handle” # => will translate User attribute “logi...
en: activerecord: errors: messages: blank: “can not has nothing” # => #<User id:nil, etc> # => u.valid? # => false # => u....
<ul><li>Active Record will look up this key in the namespaces </li></ul><ul><ul><li>activerecord.errors.models.[model_name...
en: activerecord: errors: messages: already_registered: “u already is {{model}}” # => u.errors.on(:email) # => “u already ...
<ul><li>Translation for the Active Record error_messages_for Helper </li></ul>en: activerecord: errors: template: header: ...
Anatomy of Gem i18n i18n backend core_ext helpers locales backend exceptions gettext helpers locale i18n version locale ge...
active_record Interpolation compiler Interpolation compiler Interpolation compiler Interpolation compiler Interpolation co...
i18n.rb   <ul><li>get and set methods for default_locale. </li></ul>def   default_locale(locale) @@default_locale  = local...
i18n.rb   <ul><li>Set method for locale - set the locale in  Thread.current </li></ul><ul><li>Returns the current backend....
simple.rb   <ul><li>Makes easier to extend the Simple backend's behaviour by including modules e.g. I18n::Backend::Simple....
i18n.rb   def   available_locales @@available_locales  ||= backend.available_locales end
I18n.rb   <ul><li>Default scope separator method (i.e default_separator)  </li></ul><ul><ul><li>set your separator  </li><...
I18n.rb   <ul><li>Exception handler method (i.e. exception_handler) </li></ul><ul><ul><li>set your exception handler </li>...
I18n.rb   def   default_exception_handler (exception, locale, key, options) return  exception.message if  MissingTranslati...
I18n.rb   <ul><li>load_path=(load_path) method - set load path instance. </li></ul><ul><li>load_path method </li></ul><ul>...
I18n.rb   <ul><li>Class method config returns I18n configuration object </li></ul>def   config Thread .current[ :i18n_conf...
I18n.rb   <ul><li>Method to reload the translations. </li></ul><ul><li>Main method  translate  and  localize </li></ul><ul...
I18n.rb   <ul><li>Translation method – scope options, interpolation, pluralization, defaults  </li></ul><ul><li>:scope opt...
I18n.rb   <ul><li>Interpolation </li></ul>I18n. t  :foo ,  :bar  =>   'baz' #=> 'foo baz' I18n. t  :foo ,  :count  =>   1 ...
I18n.rb   <ul><li>def   translate (&args) </li></ul><ul><ul><li>options = args.pop  if  args.last.is_a?( Hash ) </li></ul>...
I18n.rb   <ul><li>def   localize (object, options = {}) </li></ul><ul><ul><li>locale = options.delete( :locale ) || config...
base.rb   <ul><li>load_translations method - accepts list of paths of translation files. </li></ul>def   load_translations...
base.rb   <ul><li>def   load_file (filename) </li></ul><ul><ul><li>type =  File .extname(filename).tr('.', '').downcase </...
base.rb   def   store_translations (locale, data, options = {}) merge_translations(locale, data, options) end
<ul><li>def   merge_translations (locale, data, options = {}) </li></ul><ul><ul><li>locale = locale.to_sym </li></ul></ul>...
base.rb   def   translate (locale, key, options = {}) raise   InvalidLocale .new(locale)  unless  locale return  key.map {...
else count, scope, default = options.values_at( :count ,  :scope ,  :default ) values = options.reject { |name, value|  RE...
raise ( I18n::MissingTranslationData .new(locale, key, options))  if  entry.nil? e ntry = pluralize(locale, entry, count) ...
base.rb   <ul><li>look_up method  </li></ul><ul><ul><li>looks up the translation from the translations hash.  </li></ul></...
base.rb   <ul><li>localize method </li></ul>case  match when   '%a'  then   I18n . t(: &quot;date.abbr_day_names” ,   :loc...
    when   '%B'   then  I18n.t(: &quot;date.month_names&quot; ,  :locale  => locale,  :format  => format)[object.mon] when...
Customization <ul><li>Different Backends </li></ul><ul><ul><li>I18n::Backend::Simple </li></ul></ul><ul><ul><ul><ul><li>sh...
MissingTranslationData  # no translation was found for the requested key InvalidLocale  # the locale set to I18n.locale is...
- customization – e.g. the default exception handling does not allow to catch missing translation during automated test ea...
<ul><ul><li>I18n </li></ul></ul><ul><ul><ul><ul><li>own backend </li></ul></ul></ul></ul><ul><ul><ul><ul><li>makes easy to...
module  I18n def  just_raise_that_exception (*args) raise  args.first end end I18n .exception_handler   =   :just_raise_th...
References <ul><li>http://guides.rails.info/i18n.html </li></ul><ul><li>http://rails-i18n.org/wiki </li></ul><ul><li>http:...
<ul><li>Questions? </li></ul>
<ul><li>Thank You! </li></ul>
Upcoming SlideShare
Loading in …5
×

The Ruby On Rails I18n Core Api

4,096 views

Published on

My presentation on I18n during Ruby India Conference 2010, Bangalore, India

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,096
On SlideShare
0
From Embeds
0
Number of Embeds
115
Actions
Shares
0
Downloads
16
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • Need to understand.
  • The Ruby On Rails I18n Core Api

    1. 1. The Ruby on Rails I18n Core API PRESENTED BY -Neeraj Kumar
    2. 2. Introduction <ul><li>English – Default Language. </li></ul><ul><li>Gettext </li></ul><ul><li>Tough Task – transform your ROR App into its regional language & providing a tool to solve all problems at once. </li></ul>
    3. 3. <ul><li>Provides easy-to-use and extensible framework. </li></ul><ul><li>Translating </li></ul><ul><li>- to a single custom language other than English. </li></ul><ul><li>- for providing multi-language support. </li></ul>
    4. 4. <ul><li>To abstract all strings and other locale specific bits (such as date or currency formats) out of your application. The process of “localization” means to provide translations and localized formats for these bits. </li></ul><ul><li>Sven Fuchs </li></ul><ul><li>Shipped with rails (started with rails-2.2) </li></ul>
    5. 5. <ul><li>In the process of internationalizing: </li></ul><ul><ul><li>Ensure you have support for i18n </li></ul></ul><ul><ul><li>Tell Rails where to find locale dictionaries </li></ul></ul><ul><ul><li>Tell Rails how to set, preserve and switch locale </li></ul></ul>
    6. 6. Setup for RoR App <ul><li>Configure the I18n Module </li></ul><ul><ul><li>.rb and .yml + translations load path , automatically. </li></ul></ul><ul><ul><li>translations load path ( I18n.load_path ) - will be loaded automatically and available in your application. </li></ul></ul>
    7. 7. <ul><ul><li>environment.rb - instructions to customize the locale directory and default locale.e.g. </li></ul></ul><ul><li># config.i18n.load_path << Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.{rb,yml}')] </li></ul><ul><li># config.i18n.default_locale = :de </li></ul>en: hello: &quot;Hello world&quot;
    8. 8. <ul><li>Setting and Passing the Locale </li></ul><ul><li>- For more locales - to set and pass the locale between requests. </li></ul><ul><li>- Don't use session or cookies to store the chosen locale. </li></ul>
    9. 9. 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 : http://example.com/books?locale=pt - will load Portuguese localization.
    10. 10. <ul><li>Locale setting from the URL Params </li></ul><ul><li>- link_to( books_url(:locale => I18n.locale)) - tedious and probably impossible. </li></ul><ul><li>- For 'centralizing dynamic decisions about the URLs' in its ApplicationController#default_url_options. </li></ul>
    11. 11. # app/controllers/application_controller.rb def default_url_options (options = {}) logger.debug “default_url_options is passed options: #{options.inspect} ” { :locale => I18n .locale} end - Every helper method dependent on url_for automatically include the locale in the query string .
    12. 12. # config/routes.rb map.resources :books , :path_prefix => '/:locale' # => www.example.com/nl/books map.root '/:locale' , :controller => “dashboard”
    13. 13. - Drawback of default_url_options implementation pass the :id option, e.g. link_to 'show', book_url(:id => book)
    14. 14. <ul><li>Locale setting from the Domain Name </li></ul><ul><li>- advantages </li></ul><ul><ul><ul><ul><li>Locale, an obvious part of URL </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Trivial to implement </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Intuitively grasp the language of content before loading </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Search engines like content in different languages at different domains. </li></ul></ul></ul></ul>
    15. 15. before_filter :set_locale def set_locale I18n .locale = extract_locale_from_uri end
    16. 16. 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 locale from subdomain.
    17. 17. <ul><li>Locale setting from the Client Supplied Information </li></ul><ul><li>- information can come from </li></ul><ul><ul><li>Users preferred language (set in their browser) </li></ul></ul><ul><ul><li>Users geographical location inferred from IP </li></ul></ul><ul><ul><li>By choosing locale in your application interface and saving to the profile. </li></ul></ul>
    18. 18. def set_locale logger.debug = “* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}” I18n .locale = extract_locale_from_accept_language_header end
    19. 19. 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 Country - User Profile
    20. 20. en: activerecord: models: user: foo admin: bar attributes: user: login: “Handle” # => will translate User attribute “login” as “Handle” <ul><li>Active Record Model Translations </li></ul>
    21. 21. en: activerecord: errors: messages: blank: “can not has nothing” # => #<User id:nil, etc> # => u.valid? # => false # => u.errors.on(:name) # => “can not has nothing” <ul><ul><li>Error Messages Scope - Active Record Validation Error Messages Translation </li></ul></ul>
    22. 22. <ul><li>Active Record will look up this key in the namespaces </li></ul><ul><ul><li>activerecord.errors.models.[model_name].attributes.[attribute_name] </li></ul></ul><ul><ul><li>activerecord.errors.models.[model_name] </li></ul></ul><ul><ul><li>activerecord.errors.messages </li></ul></ul>
    23. 23. en: activerecord: errors: messages: already_registered: “u already is {{model}}” # => u.errors.on(:email) # => “u already is foo” <ul><li>Error Message Interpolation </li></ul><ul><ul><li>Count can be used for Pluralization </li></ul></ul>
    24. 24. <ul><li>Translation for the Active Record error_messages_for Helper </li></ul>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:”
    25. 25. Anatomy of Gem i18n i18n backend core_ext helpers locales backend exceptions gettext helpers locale i18n version locale gettext fallbacks tag
    26. 26. active_record Interpolation compiler Interpolation compiler Interpolation compiler Interpolation compiler Interpolation compiler Interpolation compiler Interpolation compiler fast gettext helpers Interpolation compiler links metadata simple active_record base cache cascader chain cldr fallbacks pluralization missing translation store_procs backend
    27. 27. i18n.rb <ul><li>get and set methods for default_locale. </li></ul>def default_locale(locale) @@default_locale = locale.to_sym rescue nil end <ul><li>Get method for locale - either default_locale or locale in Thread.current hash. </li></ul>
    28. 28. i18n.rb <ul><li>Set method for locale - set the locale in Thread.current </li></ul><ul><li>Returns the current backend. </li></ul>def backend @@backend ||= Backend::Simple .new end <ul><li>Set method for current backend. </li></ul>
    29. 29. simple.rb <ul><li>Makes easier to extend the Simple backend's behaviour by including modules e.g. I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization). </li></ul>module I18n module Backend class Simple include Base end end end
    30. 30. i18n.rb def available_locales @@available_locales ||= backend.available_locales end
    31. 31. I18n.rb <ul><li>Default scope separator method (i.e default_separator) </li></ul><ul><ul><li>set your separator </li></ul></ul><ul><ul><li>return the separator. </li></ul></ul><ul><li>Default is '.' </li></ul>
    32. 32. I18n.rb <ul><li>Exception handler method (i.e. exception_handler) </li></ul><ul><ul><li>set your exception handler </li></ul></ul><ul><ul><li>return the current exception handler. </li></ul></ul><ul><li>Default is :default_exception_handler private method. </li></ul>
    33. 33. I18n.rb def default_exception_handler (exception, locale, key, options) return exception.message if MissingTranslationData === exception raise exception end
    34. 34. I18n.rb <ul><li>load_path=(load_path) method - set load path instance. </li></ul><ul><li>load_path method </li></ul><ul><ul><li>*.rb and contain plain Ruby Hashes. </li></ul></ul><ul><ul><li>*.yml and contain YAML data. </li></ul></ul>
    35. 35. I18n.rb <ul><li>Class method config returns I18n configuration object </li></ul>def config Thread .current[ :i18n_config ] ||= I18n::Config .new end <ul><li>method config=(value) sets I18n configuration object. </li></ul>
    36. 36. I18n.rb <ul><li>Method to reload the translations. </li></ul><ul><li>Main method translate and localize </li></ul><ul><li>I18n.t :message I18n.t 'message' </li></ul>
    37. 37. I18n.rb <ul><li>Translation method – scope options, interpolation, pluralization, defaults </li></ul><ul><li>:scope option – one or many keys - scope for a translation key </li></ul>I18n .t :invalid , :scope => [ :active_record , :error_messages ] # => I18n.translation :invalid :active_record.error_messages.invalid
    38. 38. I18n.rb <ul><li>Interpolation </li></ul>I18n. t :foo , :bar => 'baz' #=> 'foo baz' I18n. t :foo , :count => 1 #=> 'foo' I18n. t :foo , :count => 0 #=> 'foos' I18n. t :foo , :count => 2 #=> 'foos' <ul><li>Pluralization </li></ul><ul><li>Defaults </li></ul>I18n. t :foo , :default => 'bar'
    39. 39. I18n.rb <ul><li>def translate (&args) </li></ul><ul><ul><li>options = args.pop if args.last.is_a?( Hash ) </li></ul></ul><ul><ul><li>key = args.shift </li></ul></ul><ul><ul><li>locale = options && options.delete( :locale ) || config.locale </li></ul></ul><ul><ul><li>raises = options && options.delete( :raise ) </li></ul></ul><ul><ul><li>config.backend.translate(locale, key, options || {}) </li></ul></ul><ul><ul><li>rescue I18n::ArgumentError => exception </li></ul></ul><ul><ul><li>raise exception if raises </li></ul></ul><ul><ul><li>handle_exception(exception, locale, key, options) </li></ul></ul><ul><li>end </li></ul><ul><li>alias :t :translate </li></ul>
    40. 40. I18n.rb <ul><li>def localize (object, options = {}) </li></ul><ul><ul><li>locale = options.delete( :locale ) || config.locale </li></ul></ul><ul><ul><li>format = options.delete( :format ) || :default </li></ul></ul><ul><ul><li>config.backend.localize(locale, object, format, options) </li></ul></ul><ul><li>end </li></ul><ul><li>alias :l :localize </li></ul>
    41. 41. base.rb <ul><li>load_translations method - accepts list of paths of translation files. </li></ul>def load_translations (*filenames) filenames.each { |filename| load_file(filename) } end
    42. 42. base.rb <ul><li>def load_file (filename) </li></ul><ul><ul><li>type = File .extname(filename).tr('.', '').downcase </li></ul></ul><ul><ul><li>raise UnknownFileType .new(type, filename) unless respond_to?(: ”load_#(type)” ) </li></ul></ul><ul><ul><li>data = send(: ”load_#(type)” , filename) </li></ul></ul><ul><ul><li>data.each { |locale, d| merge_translation(locale, d) } </li></ul></ul><ul><li>end </li></ul>
    43. 43. base.rb def store_translations (locale, data, options = {}) merge_translations(locale, data, options) end
    44. 44. <ul><li>def merge_translations (locale, data, options = {}) </li></ul><ul><ul><li>locale = locale.to_sym </li></ul></ul><ul><ul><li>translations[locale] ||= {} </li></ul></ul><ul><ul><li>separator = options[ :separator ] || I18n .default_separator </li></ul></ul><ul><ul><li>data = unwind_keys(data, separator) </li></ul></ul><ul><ul><li>data = deep_symbolized_keys(data) </li></ul></ul><ul><ul><li>merger = proc do |key, v1, v2| </li></ul></ul><ul><ul><li>Hash === v1 && Hash === v2 ? </li></ul></ul><ul><ul><li>v1.merge(v2, &merger) : (v2 || v1) </li></ul></ul><ul><ul><li>end </li></ul></ul><ul><ul><li>translations[locale].merge!(data, &merger) </li></ul></ul><ul><li>end </li></ul>base.rb
    45. 45. base.rb def translate (locale, key, options = {}) raise InvalidLocale .new(locale) unless locale return key.map { |k| translate(locale, k, options) } if key.is_a?( Array ) if options.empty? entry = resolve(locale, key, lookup(locale, key), options) raise ( I18n::MissingTranslationData .new(locale, key, options)) if entry.nil?
    46. 46. else count, scope, default = options.values_at( :count , :scope , :default ) values = options.reject { |name, value| RESERVED_KEYS .include?(name) } entry = lookup(locale, key, scope, options) entry = entry.nil? && default ? default(locale, key, default, options) : resolve(locale, key, entry, options) base.rb
    47. 47. raise ( I18n::MissingTranslationData .new(locale, key, options)) if entry.nil? e ntry = pluralize(locale, entry, count) if count entry = interpolate(locale, entry, values) if values end entry end base.rb
    48. 48. base.rb <ul><li>look_up method </li></ul><ul><ul><li>looks up the translation from the translations hash. </li></ul></ul><ul><ul><li>Splits keys or scopes containing dots into multiple keys e.g. currency.format - %w(currency format). </li></ul></ul>
    49. 49. base.rb <ul><li>localize method </li></ul>case match when '%a' then I18n . t(: &quot;date.abbr_day_names” , :locale => locale, :format => format)[object.wday] when '%A' then I18n .t(: &quot;date.day_names” , :locale => locale, :format => format)[object.wday] when '%b' then I18n .t(: &quot;date.abbr_month_names&quot; , :locale => locale, :format => format)[object.mon]
    50. 50. when '%B' then I18n.t(: &quot;date.month_names&quot; , :locale => locale, :format => format)[object.mon] when '%p' then I18n.t(: &quot;time.#{object.hour < 12 ? :am : :pm}&quot; , :locale => locale, :format => format) if object.respond_to? :hour end base.rb
    51. 51. Customization <ul><li>Different Backends </li></ul><ul><ul><li>I18n::Backend::Simple </li></ul></ul><ul><ul><ul><ul><li>shipped with Active Support of vendor directory, work for english or similar languages. </li></ul></ul></ul></ul><ul><ul><ul><ul><li>capable of reading translations but cannot dynamically store them to any format. </li></ul></ul></ul></ul>
    52. 52. MissingTranslationData # no translation was found for the requested key InvalidLocale # the locale set to I18n.locale is invalid (e.g. nil) <ul><li>Different Exception Handlers </li></ul>
    53. 53. - customization – e.g. the default exception handling does not allow to catch missing translation during automated test easily .
    54. 54. <ul><ul><li>I18n </li></ul></ul><ul><ul><ul><ul><li>own backend </li></ul></ul></ul></ul><ul><ul><ul><ul><li>makes easy to exchange the Simple backend implementation with that to fits better with your need. </li></ul></ul></ul></ul>I18n .backend = Globalize :: Backend :: Static .new
    55. 55. module I18n def just_raise_that_exception (*args) raise args.first end end I18n .exception_handler = :just_raise_that_exception
    56. 56. References <ul><li>http://guides.rails.info/i18n.html </li></ul><ul><li>http://rails-i18n.org/wiki </li></ul><ul><li>http://iain.nl/2008/09/translating-activerecord/ </li></ul><ul><li>http://github.com/svenfuchs/rails-i18n </li></ul><ul><li>http://rails-i18n.org/wiki/wikipages/i18n-rails-guide </li></ul><ul><li>http://www.artweb-design.de/2008/7/18/the-ruby-on-rails-i18n-core-api </li></ul>
    57. 57. <ul><li>Questions? </li></ul>
    58. 58. <ul><li>Thank You! </li></ul>

    ×