Définition et gestion des paramètres régionaux dans Rails i18n


L’un des articles précédents couvrait I18n dans Rails. Nous avons parlé de stocker et de récupérer des traductions, de localiser l’application et d’autres choses utiles. Cependant, nous n’avons pas discuté des différentes façons de gérer les paramètres régionaux entre les demandes.

Par défaut, Rails va utiliser les paramètres régionaux définis dans le I18n.default_locale (lequel est :en ou toute autre valeur que vous définissez dans la configuration) ou la valeur de I18n.locale si elle a été explicitement définie. Bien sûr, si une application prend en charge plusieurs langues, ses utilisateurs ont besoin d’un moyen de modifier les paramètres régionaux et leur choix doit être conservé. Par conséquent, dans cet article, nous explorerons les solutions suivantes:

  • Fournissez le nom des paramètres régionaux en tant que paramètre GET (example.com?locale=en)
  • Fournissez-le en tant que partie d’un nom de domaine (en.example.com)
  • Définir les paramètres régionaux en fonction de l’agent utilisateur envoyé par le navigateur
  • Définir les paramètres régionaux en fonction de l’emplacement de l’utilisateur

Le code source de l’application de démonstration est disponible sur GitHub.

Soit dit en passant, si vous commencez seulement à apprendre Rails, ici est la grande liste de ressources utiles.

Préparation de l’application

Dans cette démo, je vais utiliser Rails 5.0.0.1 mais les concepts décrits s’appliquent également aux anciennes versions. Pour commencer, créez une nouvelle application sans la suite de tests par défaut:

    $ rails new Localizer -T

Afin de prendre en charge des langues supplémentaires, incluez le rails-i18n bijou dans votre Gemfile:

Gemfile

    [...]
    gem 'rails-i18n'
    [...]

Installez-le

    $ bundle install

Je vais fournir un support pour les langues anglaise et polonaise dans cette démo, mais vous pouvez choisir autre chose. Définissons explicitement les paramètres régionaux pris en charge:

config / application.rb

    config.i18n.available_locales = [:en, :pl]

Créez également rapidement deux petites pages gérées par le PagesController:

pages_controller.rb

    class PagesController < ApplicationController
    end

vues / pages / index.html.erb

    

<%= t('.title') %>

<%= link_to t('pages.about.title'), about_path %>

* vues / pages / about.html.erb

    

<%= t('.title') %>

<%= link_to t('pages.index.title'), root_path %>

N'oubliez pas que le t est un alias pour I18n.translate et il recherche la traduction en fonction
sur la clé fournie. Voici nos traductions:

config / locales / en.yml

    en:
      pages:
        index:
          title: 'Welcome!'
        about:
          title: 'About us'

config / locales / pl.yml

    pl:
      pages:
        index:
          title: 'Powitanie!'
        about:
          title: 'O nas'

Tant que nous nommons ces clés en fonction des noms du contrôleur et de la vue, à l'intérieur du .html.erb fichier, nous pouvons simplement dire t('.title') en omettant le pages.index ou pages.about les pièces.

Définissez les itinéraires:

config / routes.rb

  get "https://dzone.com/about", to: 'pages#about', as: :about
  root 'pages#index'

Enfin, fournissez les liens pour changer les paramètres régionaux du site (les URL seront vides pour l'instant):

shared / _change_locale.html.erb

    
  • <%= link_to 'English', "https://dzone.com/#" %>
  • .
  • <%= link_to 'Polska', "https://dzone.com/#" %>

Rendez ce partiel à l'intérieur de la mise en page:

layouts / application.html.erb

    <%= render 'shared/change_locale' %>

Agréable! Les préparatifs sont terminés et nous pouvons passer à la partie principale.

Définition des paramètres régionaux en fonction du nom de domaine

La première solution dont nous discuterons consiste à définir les paramètres régionaux en fonction du nom du domaine de premier niveau, par exemple example.com affichera la version anglaise du site, alors que example.pl - Version polonaise. Cette solution présente un certain nombre d'avantages et probablement le plus important est que les utilisateurs peuvent facilement comprendre quelle langue ils vont utiliser. Néanmoins, si votre site Web prend en charge de nombreux paramètres régionaux, l'achat de plusieurs domaines peut être coûteux.

Afin de tester cette solution localement, vous devrez configurer un peu votre poste de travail en modifiant le hôtes fichier. Ce fichier se trouve à l'intérieur du etc répertoire (pour Windows, ce sera % WINDIR% system32 drivers etc). Modifiez-le en ajoutant

    127.0.0.1   localizer.com
    127.0.0.1   localizer.pl

En visite localizer.com:3000 et localizer.pl:3000 devrait vous diriger vers notre application Rails.

Un endroit très courant pour définir les paramètres régionaux est le before_action à l'intérieur de ApplicationController:

application_controller.rb

    [...]
    before_action :set_locale

    private
    def set_locale
      I18n.locale = extract_locale || I18n.default_locale
    end
    [...]

Pour récupérer le nom d'hôte demandé, utilisez request.host:

application_controller.rb

    [...]
    def extract_locale
    parsed_locale = request.host.split('.').last
    I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
    end
    [...]

Dans cette méthode, nous supprimons la dernière partie du nom de domaine (com, pl etc) et vérifiez si les paramètres régionaux demandés sont pris en charge. Si oui - retournez-le, sinon dites nil.

Maintenant, ajustez les liens pour changer les paramètres régionaux:

shared / _change_locale.html.erb

    [...]
  
  • <%= link_to 'English', "http://localizer.com:3000" %>
  • <%= link_to 'Polska', "http://localizer.pl:3000" %>
  • [...]

    Pour le rendre un peu plus convivial, ajoutons le chemin actuel à l'URL:

    shared / _change_locale.html.erb

        [...]
      
  • <%= link_to 'English', "http://localizer.com:3000#{request.env['PATH_INFO']}" %>
  • <%= link_to 'Polska', "http://localizer.pl:3000#{request.env['PATH_INFO']}" %>
  • [...]

    Vous pouvez maintenant tester le résultat!

    Utiliser un sous-domaine

    Bien sûr, au lieu d'acheter plusieurs domaines de premier niveau, vous pouvez vous inscrire sous-domaines dans votre zone de domaine, par exemple en.localizer.com et pl.localizer.com.

    le extract_locale la méthode doit être modifiée comme ceci:

    application_controller.rb

        [...]
        def extract_locale
        parsed_locale = request.subdomains.first
        I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
        end
        [...]
    

    Bien sûr, les liens seront également un peu différents:

    shared / _change_locale.html.erb

      
  • <%= link_to 'English', "http://en.localizer.com:3000#{request.env['PATH_INFO']}" %>
  • <%= link_to 'Polska', "http://pl.localizer.com:3000#{request.env['PATH_INFO']}" %>
  • Définition des paramètres régionaux en fonction des paramètres HTTP GET

    Une autre approche très courante utilise les paramètres HTTP GET, par exemple localhost:3000?locale=en. Cela nous obligera à changer la extract_locale encore une fois:

    application_controller.rb

        [...]
      def extract_locale
        parsed_locale = params[:locale]
        I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
      end
        [...]
    

    Le problème, cependant, est la nécessité de conserver les paramètres régionaux choisis entre les demandes. Bien sûr, vous pouvez dire link_to root_url(locale: I18n.locale) à chaque fois, mais ce n'est pas la meilleure idée. Au lieu,
    vous pouvez compter sur default_url_options méthode qui définit les paramètres par défaut pour le url_for et d'autres méthodes qui en dépendent:

    application_controller.rb

        [...]
        def default_url_options
          { locale: I18n.locale }
        end
        [...]
    

    Ainsi, vos assistants d'itinéraire incluront automatiquement le ?locale partie. Cependant, je n’ai pas vraiment
    comme cette approche, principalement à cause de ce paramètre GET ennuyeux. Par conséquent, discutons encore une autre solution.

    Utilisation des étendues des itinéraires

    Comme vous vous en souvenez probablement, les itinéraires peuvent être portée et cette fonctionnalité peut être utilisée pour conserver facilement le nom des paramètres régionaux:

    config / routes.rb

        [...]
      scope "(:locale)", locale: /en|pl/ do
        get "https://dzone.com/about", to: 'pages#about', as: :about
        root 'pages#index'
      end
        [...]
    

    En enveloppant :locale avec des parenthèses rondes, nous rendons ce paramètre GET facultatif. locale: /en|pl/ définit l'expression régulière en vérifiant que ce paramètre ne peut contenir que en ou pl, par conséquent, l'un de ces liens est correct:

    • http://localhost:3000/about
    • http://localhost:3000/en/about
    • http://localhost:3000/pl/about

    Modifiez les liens pour changer les paramètres régionaux:

    shared / _change_locale.html.erb

      
  • <%= link_to 'English', root_path(locale: :en) %>
  • <%= link_to 'Polska', root_path(locale: :pl) %>
  • À mon avis, cette solution est beaucoup plus ordonnée que de passer des paramètres régionaux via le ?locale GET param.

    Déduire des paramètres régionaux en fonction des paramètres de l'utilisateur

    Lorsque les paramètres régionaux n'ont pas été définis explicitement, vous revenez à la valeur par défaut définie dans I18n.default_locale mais nous pouvons changer ce comportement. Pour obtenir des paramètres régionaux implicites, vous pouvez utiliser des en-têtes HTTP ou des informations sur l'emplacement d'un visiteur, voyons donc ces deux approches en action maintenant.

    Utilisation d'en-têtes HTTP

    Il existe un en-tête HTTP spécial appelé Accept-Language que les navigateurs définissent en fonction des préférences linguistiques sur l'appareil d'un utilisateur. Son contenu ressemble généralement à en-US,en;q=0.5, mais nous ne nous intéressons qu'aux deux premiers caractères, donc le extract_locale La méthode peut être modifiée comme ceci:

    application_controller.rb

        [...]
        def extract_locale
            parsed_locale = params[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/)[0]
          I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
        end
        [...]
    

    Il y a un grand bijou http_accept_language qui agit comme un middleware Rack et vous aide à résoudre ce problème de manière plus robuste.

    Employer l'emplacement de l'utilisateur

    Une autre approche consisterait à définir les paramètres régionaux par défaut en fonction de l'emplacement de l'utilisateur. Cette solution est généralement considérée comme peu fiable et généralement déconseillée, mais par souci d'exhaustivité, discutons-en également.

    Afin de récupérer l'emplacement de l'utilisateur, utilisons un joyau appelé géocodeur qui peut être utilisé pour de nombreuses tâches différentes et fournit même des crochets pour ActiveRecord et Mongoid. Dans cette démo, cependant, les choses seront beaucoup plus simples. Tout d'abord, ajoutez ce nouveau bijou

    Gemfile

        [...]
        gem 'geocoder'
        [...]
    

    et courir

        $ bundle install
    

    Nous pouvons maintenant profiter de request.location.country_code pour voir le pays de l'utilisateur. Cependant, la chaîne résultante est en majuscule, nous allons donc la décliner. Voici le code correspondant:

    application_controller.rb

        [...]
        def extract_locale
          parsed_locale = if params[:locale]
                            params[:locale]
                          else
                            request.location.country_code ? request.location.country_code.downcase : nil
                          end
            I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
        end
        [...]
    

    Le seul problème ici est que vous ne pourrez pas le tester localement, car request.location.country_code renverra toujours "RD". Néanmoins, vous pouvez déployer votre application sur Heroku (cela prendra littéralement quelques minutes) et testez tout ce qui s'y trouve en utilisant des serveurs proxy ouverts.

    Encore une fois, je tiens à vous rappeler que la définition des paramètres régionaux de l'utilisateur en fonction de son emplacement n'est pas considérée comme une pratique recommandée, car quelqu'un peut, par exemple, visiter un autre pays lors d'un voyage d'affaires.

    PhraseApp et gestion des traductions

    Bien sûr, l'introduction du mécanisme de commutation et de persistance des paramètres régionaux est très importante pour toute application multilingue, mais cela n'a pas de sens si vous n'avez pas de traductions. Et PhraseApp est là pour faciliter le processus de gestion des traductions!

    Tu peux essayez PhraseApp gratuitement pendant 14 jours en ce moment. Il prend en charge une énorme liste de différents langages et cadres de Rails à JavaScript et permet d'importer et d'exporter facilement des données de traductions. Ce qui est cool, vous pouvez rapidement comprendre quelles clés de traduction manquent car il est facile de perdre la trace lorsque vous travaillez avec de nombreuses langues dans de grandes applications. Par conséquent, je vous encourage vraiment à l'essayer!

    Conclusion

    Dans cette application, nous avons couvert différentes façons de basculer et de conserver les données locales entre les demandes. Nous avons vu comment les paramètres régionaux peuvent être transmis comme partie du nom de domaine et comme partie de l'URL. En outre, nous avons parlé de déduire les paramètres régionaux en fonction de l'en-tête HTTP et de l'emplacement de l'utilisateur.

    J'espère que cet article vous a été utile et intéressant. Je vous remercie d'être resté avec moi et d'avoir codé avec plaisir!

    Close Menu