Successfully reported this slideshow.
Your SlideShare is downloading. ×

The Ruby On Rails I18n Core Api

Upcoming SlideShare
Loading in …3

Check these out next

1 of 58 Ad
1 of 58 Ad

More Related Content


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 : - 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' # => 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 = '.' ).last I18n .available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil end - parsed_locale ='.').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 { |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> </li></ul><ul><li> </li></ul><ul><li> </li></ul><ul><li> </li></ul><ul><li> </li></ul><ul><li> </li></ul>
  57. 57. <ul><li>Questions? </li></ul>
  58. 58. <ul><li>Thank You! </li></ul>

Editor's Notes

  • Need to understand.