J'ajoute I18N à mon Rails application en passant les paramètres régionaux à l'aide des paramètres d'URL. Mes URL ressemblent à http://example.com/en/users et - http://example.com/ar/users (pour les paramètres régionaux anglais et arabe respectivement).
Dans mon fichier de routes, j'ai défini mes routes avec une option: path_prefix:
map.resources :users, :path_prefix => '/:locale'
Et les paramètres régionaux sont définis à l'aide d'un before_filter défini dans ApplicationController
def set_locale
I18n.locale = params[:locale]
end
J'ai également défini ApplicationController # default_url_options, pour ajouter des paramètres régionaux à toutes les URL générées par l'application:
def default_url_options(options={})
{:locale => I18n.locale}
end
Ce que je veux, c'est ajouter un lien dans l'en-tête de mise en page (affiché dans toutes les pages) qui serait lié à la même page mais avec les autres paramètres régionaux.
Par exemple, si je parcours les paramètres régionaux arabes, je veux un lien "anglais" dans l'en-tête, qui me redirigera vers ma page actuelle et définira les paramètres régionaux sur anglais. Y a-t-il un moyen de le faire dans les rails?
Cela m'a pris un certain temps pour trouver cela, mais voici ma solution:
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
De la documentation ici: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649
Lors de la génération d'une nouvelle URL, les valeurs manquantes peuvent être remplies à partir des paramètres de la demande actuelle. Par exemple, url_for: action => ‘some_action’ conservera le contrôleur actuel, comme prévu. Ce comportement s’étend à d’autres paramètres, notamment: contrôleur,: id et tout autre paramètre placé dans le chemin d’une route.
Donc, en utilisant url_for par défaut, les paramètres de la requête en cours, il suffit de changer celui que vous voulez dans votre code. Dans ce cas, tout ce que j'ai changé était: locale, donc tout le reste reste le même.
Notez que cela fonctionne également pour les paramètres "cachés": Donc si vous avez:
map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map'
utiliser l'url_for ci-dessus dans la page/en/my_map n'aura pas 'home' dans l'url (ie/en/home/my_map). Prime.
J'ai donc trouvé un moyen de le faire de manière plus explicite sans compter sur (autant) Rails magic.
url_for(params.merge({:your_new_parameter => value}))
Cela devrait fonctionner dans n'importe quel link_to
.
Tout ce qu'il fait, c'est prendre les paramètres de la requête actuelle et y fusionner le nouveau hachage souhaité, puis créer une nouvelle URL pour cela.
Lien vers la page actuelle avec différents paramètres régionaux
Testé sur Rails 4
Bonjour à tous. Après un certain temps de recherche, je décide d'écrire ma propre solution pour cela.
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
Cela fonctionne parfaitement, mais il permet Vulnérabilité XSS juste en passant des paramètres dans votre URL comme ci-dessous:
http://localhost:3000/en/about?host=www.fishingsiteorbadurl.com/%23&port=80
Ou pire cas:
http://localhost:3000/en/about?host=%D0%BE%D1%87%D0%B5%D0%BD%D1%8C%D0%BF%D0%BB%D0%BE%D1%85%D0%BE%D0%B9%D1%81%D0%B0%D0%B9%D1%82.%D1%80%D1%84
Découvrez les URL que vous obtiendrez après avoir parcouru ce lien dans votre application.
Ma solution de production. La méthode "changer de langue" redirige vers n'importe quelle page avec les paramètres régionaux appropriés en utilisant simplement HTTP_REFERER dans l'objet de demande. Remarque: méthode URI.path pour obtenir uniquement le chemin, pas l'URL entière
Créez une méthode de "changement de langue" dans n'importe quel contrôleur:
def change_lang
if request.referer.nil?
refer = root_url
else
uri = URI(request.referer)
refer = uri.path
end
lang = params[:lang]
cookies[:locale] = lang
redirect_to refer
end
application_controller.rb
before_action :set_locale
def set_locale
# -- Get lang from cookies or url parameter locale
user_locale = cookies[:locale] || params[:locale]
# -- If present
if user_locale.present?
# -- If it is has 2 symbols
user_locale = user_locale.scan(/[a-zA-Z]{2}/)
else
# -- If no - use default en locale
user_locale = 'en'
end
# -- Check, is this locale available for using.
# Please note: this needed for disable invalid locale warning.
if I18n.available_locales.include?(user_locale[0].to_sym)
I18n.locale = user_locale[0]
else
I18n.locale = "en"
end
end
ajoutez ceci à votre mise en page
<%= link_to 'English', change_lang_path('en') %> <%= link_to 'Russian', change_lang_path('ru') %>
config/routes.rb
scope "(:locale)", locale: /[a-zA-Z]{2}/ do
get "change_lang/:lang" => "users#change_lang", :as => "change_lang"
end
Il n'est pas nécessaire d'utiliser params.merge ou une solution de patch de singe.
J'espère que cela aide, car j'ai personnellement passé beaucoup de temps à le résoudre.
Vous pouvez analyser request_uri et remplacer vos paramètres régionaux dans le chemin par une expression régulière
Ok, voici un exemple d'aide. Si je comprends bien l'objectif
def locale_url(url, locale)
url.gsub(/\/\w*$/, "/#{locale}")
end
url = "http://www.domain.com/products/1/ru" # or request.request_uri
locale = "en"
locale_url(url, locale) #=> "http://www.domain.com/products/1/en"
Ceci est un point de départ, vous pouvez donc faire des choses différentes dont vous avez besoin
Jetez un oeil à cela, bien qu'il ne soit pas DRY et un bon, mais fonctionne parfaitement pour moi. Il lit tous les paramètres que vous avez fournis en remplaçant uniquement les URL EX locales: http : //example.com: 3000/us/users? t = 123 & m = 34 etc
def us_link
link_to "US", form_locale_url("/us")
end
def jp_link
link_to "Japan",form_locale_url("/jp")
end
def form_locale_url(locale)
new_url = request.request_uri
new_locale_url = new_us_url = new_jp_url = new_url
if new_url == "/"
new_locale_url.sub!(/\//,locale)
elsif (new_url =~/\/us/) == 0
new_us_url.sub!(/\/us/,locale)
elsif (new_url =~/\/jp/) == 0
new_jp_url.sub!(/\/jp/,locale)
end
end
Une avenue beaucoup plus rapide - et pratique si vous avez de nombreux paramètres qui changent à différents endroits ... évitez l'encombrement avec une balise d'ancrage qui fusionne simplement le nouveau paramètre de paramètres régionaux aux paramètres existants (et en fait, tue l'ancien paramètre de paramètres régionaux).
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>
Mais oui, il faut ajouter des paramètres à la liste blanche à ce stade, selon le contexte de l'application.
Vous pouvez en toute sécurité utiliser url_for
pour changer de locale avec l'url params
si vous définissez only_path: true
:
<%= link_to I18n.t('language_name', locale: I18n.locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>
Nous .clone
le params
avant de les autoriser tous (.permit!
), pour conserver des paramètres forts ailleurs. La seule solution plus sûre que je pourrais trouver serait de chronométrer la liste blanche de tous les paramètres à la place ...
Implémentation I18n robuste:
Ajouter un locales.rb
initialiseur pour définir ce que I18n.available_locales
vous soutenez:
# config/initializers/locales.rb
# Permitted locales available for the application
I18n.available_locales = [:en, :fr]
Définissez un language_name
valeur dans le fichier de paramètres régionaux de chaque langue (par exemple, fr.yml
):
fr:
language_name: "Français"
Au fur et à mesure que vous ajoutez des langues, cet ERB vous permet de basculer entre elles de manière générique:
// app/views/layouts/_languages.html.erb
<span class="languages">
<% I18n.available_locales.each do |locale| %>
<% if I18n.locale == locale %>
<%= link_to I18n.t('language_name', locale: locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ), {style: "display:none" } %>
<% else %>
<%= link_to I18n.t('language_name', locale: locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>
<% end %>
<% end %>
</span>
Pour le contrôleur, nous trouvons automatiquement la langue correcte pour l'utilisateur en détectant le navigateur de son Accept-Language
En-tête HTTP (en utilisant la gemme http_accept_language ).
Définissez un cookie session
pour conserver les paramètres régionaux entre les demandes.
Ou, facultativement, utilisez default_url_options
pour insérer le ?locale=
param dans l'URL de votre application. Je fais les deux.
Manette:
class ApplicationController < ActionController::Base
before_action :set_locale
private
def set_locale
I18n.locale = begin
extract_locale ||
session[:locale] ||
http_accept_language.compatible_language_from(I18n.available_locales) ||
I18n.default_locale
end
session[:locale] = I18n.locale
end
def extract_locale
parsed_locale = params[:locale].dup
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end
def default_url_options
{ locale: I18n.locale }
end
end