diff options
Diffstat (limited to 'guides/source/i18n.md')
-rw-r--r-- | guides/source/i18n.md | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/guides/source/i18n.md b/guides/source/i18n.md index ec7582fa62..d6fccadb28 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Rails Internationalization (I18n) API ===================================== @@ -77,8 +77,8 @@ There are also attribute readers and writers for the following attributes: load_path # Announce your custom translation files locale # Get and set the current locale default_locale # Get and set the default locale -available_locales # Whitelist locales available for the application -enforce_available_locales # Enforce locale whitelisting (true or false) +available_locales # Permitted locales available for the application +enforce_available_locales # Enforce locale permission (true or false) exception_handler # Use a different exception_handler backend # Use a different backend ``` @@ -116,7 +116,7 @@ NOTE: The backend lazy-loads these translations when a translation is looked up You can change the default locale as well as configure the translations load paths in `config/application.rb` as follows: ```ruby - config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] config.i18n.default_locale = :de ``` @@ -128,26 +128,31 @@ The load path must be specified before any translations are looked up. To change # Where the I18n library should search for translation files I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')] -# Whitelist locales available for the application +# Permitted locales available for the application I18n.available_locales = [:en, :pt] # Set default locale to something other than :en I18n.default_locale = :pt ``` -### Managing the Locale across Requests +Note that appending directly to `I18n.load_paths` instead of to the application's configured i18n will _not_ override translations from external gems. -The default locale is used for all translations unless `I18n.locale` is explicitly set. +### Managing the Locale across Requests A localized application will likely need to provide support for multiple locales. To accomplish this, the locale should be set at the beginning of each request so that all strings are translated using the desired locale during the lifetime of that request. -The locale can be set in a `before_action` in the `ApplicationController`: +The default locale is used for all translations unless `I18n.locale=` or `I18n.with_locale` is used. + +`I18n.locale` can leak into subsequent requests served by the same thread/process if it is not consistently set in every controller. For example executing `I18n.locale = :es` in one POST requests will have effects for all later requests to controllers that don't set the locale, but only in that particular thread/process. For that reason, instead of `I18n.locale =` you can use `I18n.with_locale` which does not have this leak issue. + +The locale can be set in an `around_action` in the `ApplicationController`: ```ruby -before_action :set_locale +around_action :switch_locale -def set_locale - I18n.locale = params[:locale] || I18n.default_locale +def switch_locale(&action) + locale = params[:locale] || I18n.default_locale + I18n.with_locale(locale, &action) end ``` @@ -167,10 +172,11 @@ One option you have is to set the locale from the domain name where your applica You can implement it like this in your `ApplicationController`: ```ruby -before_action :set_locale +around_action :switch_locale -def set_locale - I18n.locale = extract_locale_from_tld || I18n.default_locale +def switch_locale(&action) + locale = extract_locale_from_tld || I18n.default_locale + I18n.with_locale(locale, &action) end # Get locale from top-level domain or return +nil+ if such locale is not available @@ -210,13 +216,13 @@ This solution has aforementioned advantages, however, you may not be able or may #### Setting the Locale from URL Params -The most usual way of setting (and passing) the locale would be to include it in URL params, as we did in the `I18n.locale = params[:locale]` _before_action_ in the first example. We would like to have URLs like `www.example.com/books?locale=ja` or `www.example.com/ja/books` in this case. +The most usual way of setting (and passing) the locale would be to include it in URL params, as we did in the `I18n.with_locale(params[:locale], &action)` _around_action_ in the first example. We would like to have URLs like `www.example.com/books?locale=ja` or `www.example.com/ja/books` in this case. This approach has almost the same set of advantages as setting the locale from the domain name: namely that it's RESTful and in accord with the rest of the World Wide Web. It does require a little bit more work to implement, though. Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL, e.g. `link_to(books_url(locale: I18n.locale))`, would be tedious and probably impossible, of course. -Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-default_url_options), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for) and helper methods dependent on it (by implementing/overriding `default_url_options`). +Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-default_url_options), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](https://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for) and helper methods dependent on it (by implementing/overriding `default_url_options`). We can include something like this in our `ApplicationController` then: @@ -231,7 +237,7 @@ Every helper method dependent on `url_for` (e.g. helpers for named routes like ` You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of the application domain: and URLs should reflect this. -You probably want URLs to look like this: `http://www.example.com/en/books` (which loads the English locale) and `http://www.example.com/nl/books` (which loads the Dutch locale). This is achievable with the "over-riding `default_url_options`" strategy from above: you just have to set up your routes with [`scope`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html): +You probably want URLs to look like this: `http://www.example.com/en/books` (which loads the English locale) and `http://www.example.com/nl/books` (which loads the Dutch locale). This is achievable with the "over-riding `default_url_options`" strategy from above: you just have to set up your routes with [`scope`](https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html): ```ruby # config/routes.rb @@ -273,8 +279,11 @@ NOTE: Have a look at various gems which simplify working with routes: [routing_f An application with authenticated users may allow users to set a locale preference through the application's interface. With this approach, a user's selected locale preference is persisted in the database and used to set the locale for authenticated requests by that user. ```ruby -def set_locale - I18n.locale = current_user.try(:locale) || I18n.default_locale +around_action :switch_locale + +def switch_locale(&action) + locale = current_user.try(:locale) || I18n.default_locale + I18n.with_locale(locale, &action) end ``` @@ -289,10 +298,11 @@ The `Accept-Language` HTTP header indicates the preferred language for request's A trivial implementation of using an `Accept-Language` header would be: ```ruby -def set_locale +def switch_locale(&action) logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}" - I18n.locale = extract_locale_from_accept_language_header - logger.debug "* Locale set to '#{I18n.locale}'" + locale = extract_locale_from_accept_language_header + logger.debug "* Locale set to '#{locale}'" + I18n.with_locale(locale, &action) end private @@ -333,10 +343,12 @@ end ```ruby # app/controllers/application_controller.rb class ApplicationController < ActionController::Base - before_action :set_locale - def set_locale - I18n.locale = params[:locale] || I18n.default_locale + around_action :switch_locale + + def switch_locale(&action) + locale = params[:locale] || I18n.default_locale + I18n.with_locale(locale, &action) end end ``` @@ -584,7 +596,7 @@ You should have a good understanding of using the i18n library now and know how to internationalize a basic Rails application. In the following chapters, we'll cover its features in more depth. -These chapters will show examples using both the `I18n.translate` method as well as the [`translate` view helper method](http://api.rubyonrails.org/classes/ActionView/Helpers/TranslationHelper.html#method-i-translate) (noting the additional feature provide by the view helper method). +These chapters will show examples using both the `I18n.translate` method as well as the [`translate` view helper method](https://api.rubyonrails.org/classes/ActionView/Helpers/TranslationHelper.html#method-i-translate) (noting the additional feature provide by the view helper method). Covered are features like these: @@ -662,6 +674,26 @@ I18n.t 'activerecord.errors.messages' # => {:inclusion=>"is not included in the list", :exclusion=> ... } ``` +If you want to perform interpolation on a bulk hash of translations, you need to pass `deep_interpolation: true` as a parameter. When you have the following dictionary: + +```yaml +en: + welcome: + title: "Welcome!" + content: "Welcome to the %{app_name}" +``` + +then the nested interpolation will be ignored without the setting: + +```ruby +I18n.t 'welcome', app_name: 'book store' +# => {:title=>"Welcome!", :content=>"Welcome to the %{app_name}"} + +I18n.t 'welcome', deep_interpolation: true, app_name: 'book store' +# => {:title=>"Welcome!", :content=>"Welcome to the book store"} +``` + + #### "Lazy" Lookup Rails implements a convenient way to look up the locale inside _views_. When you have the following dictionary: @@ -1103,7 +1135,7 @@ For several reasons the Simple backend shipped with Active Support only does the That does not mean you're stuck with these limitations, though. The Ruby I18n gem makes it very easy to exchange the Simple backend implementation with something else that fits better for your needs, by passing a backend instance to the `I18n.backend=` setter. -For example, you can replace the Simple backend with the the Chain backend to chain multiple backends together. This is useful when you want to use standard translations with a Simple backend but store custom application translations in a database or other backends. +For example, you can replace the Simple backend with the Chain backend to chain multiple backends together. This is useful when you want to use standard translations with a Simple backend but store custom application translations in a database or other backends. With the Chain backend, you could use the Active Record backend and fall back to the (default) Simple backend: @@ -1174,7 +1206,7 @@ The I18n API described in this guide is primarily intended for translating inter Several gems can help with this: * [Globalize](https://github.com/globalize/globalize): Store translations on separate translation tables, one for each translated model -* [Mobility](https://github.com/shioyama/mobility): Provides support for storing translations in many formats, including translation tables, json columns (Postgres), etc. +* [Mobility](https://github.com/shioyama/mobility): Provides support for storing translations in many formats, including translation tables, json columns (PostgreSQL), etc. * [Traco](https://github.com/barsoom/traco): Translatable columns for Rails 3 and 4, stored in the model table itself Conclusion |