I18n with friendly-id and globalize3 - avoid duplicate content (seo) - ruby-on-rails

In a classic multilingual rails 4 website I want to avoid the duplicate content problem.
I used friendly-id and globalize3 to make the website multilingual.
Here is my configuration:
classic page model:
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
translates :title, :content, :slug
first routes configuration:
scope ":locale", /#{I18n.available_locales.join("|")}/ do
my_routes
end
#rails cast solution
match '*path', to: redirect("/#{I18n.default_locale}/%{path}"), constraints: lambda { |req| !req.path.starts_with? "/#{I18n.default_locale}/" }, via: :all
match '', to: redirect("/#{I18n.default_locale}"), via: :all
first application application-controller configuration:
before_action :set_locale
def default_url_options(options = {})
{locale: I18n.locale}
end
private
def set_locale
I18n.locale = params[:locale] if params[:locale].present?
end
As I want users to access the site without /the-default-locale at the end of the URL I change configuration as follow:
Routes configuration:
#Here I'm trying to avoid /en/content and /content to avoid duplication
match "/#{I18n.default_locale}/*path", to: redirect("/%{path}"), via: :all
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
my_routes
end
#removed the rails cast fallback to default locale
Application controller configuration:
before_action :set_locale
def default_url_options(options = {})
{ :locale => ((I18n.locale == I18n.default_locale) ? nil : I18n.locale) }
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
the links to switch between languages:
#here the French language is the default locale
<%= link_to_unless_current t("English"), locale: "en" %>
<%= link_to_unless_current t("French"), locale: nil %>
Questions:
1- With the friendly ids and the translated slug you can go to mywebsite.com/mon_contenu and mywebsite/en/my_content. But if you already are on mywebsite.com/mon_contenu and you click on the english switch you will be on mywebsite.com/en/mon_contenu with the english content but the url doesn't switch to the english slug.
Is this considerated as duplicate content? And if yes how can I avoid it?
2- With globalize if a content isn't translated it will display the default locale content. So mywebsite.com/mon_contenu and mywebsite.com/en/my_content can display the same content in the same language if the translation is not done.
Again is this considerated as duplication?
Options considered
Using robot.txt to disable some routes for instance to allow just the default locale to be indexed?
Using the canonical tag but I don't know how to easily setup it in the layout
How do you manage this kind of situations?
Any help/idea/comment/advice is always welcome!
As always thanks for your help.

Few months later, I'm still trying to figure out the best options.
Here is the solution I use for the question 1:
I set this in the controllers (solution from railscasts about friendly_id)
def show
if request.path != page_path(#page)
redirect_to #page, status: :moved_permanently
end
end
With this in place there are no reasons for multiple urls pointing to the same content. Instead the user will be redirected properly to the right URL. And the slug history is still useful.
I'll update this post if I figured out something for the second point! Actually I'm thinking of something to check if translation exist and if not redirect to default locale with a flash notice.

Related

Rails I18n - How can I change other locale with the same page [duplicate]

I am adding I18N to my rails application by passing the locale using url params. My urls are looking like http://example.com/en/users and http://example.com/ar/users (for the english and arabic locales respectively).
In my routes file, I have defined my routes with a :path_prefix option:
map.resources :users, :path_prefix => '/:locale'
And locale is being set using a before_filter defined in ApplicationController
def set_locale
I18n.locale = params[:locale]
end
I also defined ApplicationController#default_url_options, to add locale to all urls generated by the application:
def default_url_options(options={})
{:locale => I18n.locale}
end
What I want is to add a link in the layout header (displayed in all pages) that would link to the same page but with the other locale.
For instance, if I am browsing the arabic locale, I want a "English" link in the header, that will redirect me back to my current page, and set the locale to english. Is there a way to do this in rails?
Took me a while to find this but here is my solution:
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
From the docs here: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649
When generating a new URL, missing
values may be filled in from the
current request‘s parameters. For
example, url_for :action =>
‘some_action‘ will retain the current
controller, as expected. This behavior
extends to other parameters, including
:controller, :id, and any other
parameters that are placed into a
Route‘s path.
So using url_for will default to the current request's parameters, just change the one's you want in your code. In this case all I changed was :locale, so everything else stays the same.
Note this also works for "hidden" :parameters. So if you have:
map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map'
using the above url_for in the page /en/my_map will not have 'home' in the url (ie /en/home/my_map). Bonus.
So I found a way to more explicitly do this with out relying on (as much) rails magic.
url_for(params.merge({:your_new_parameter => value}))
This should work in any link_to.
All its doing is taking the current request's parameters and merging your new desired hash into them and then creating a new url for that.
Link to current page with different locales
Tested on Rails 4
Hello all.
After some time of research I decide to write my own solution for this.
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
This works perfect, but it allows XSS Vulnerability just passing parameters in your URL like below:
http://localhost:3000/en/about?host=www.fishingsiteorbadurl.com/%23&port=80
Or worst case:
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
Check out what URLs you will get after going through this link in your application.
My production solution.
Method "change language" redirects to any page with proper locale just using HTTP_REFERER in request object.
Please note: URI.path method for get only path, not whole url
Make "change language" method in any controller:
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
add this to your layout
<%= 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
There is no need to use params.merge or any monkey-patch solution.
I hope this helps, because I personally spent a lot of time to solve it.
A much quicker avenue - and convenient if you have many parameters that change in different places... avoid the clutter with an anchor tag that just merges the new locale param to the existing ones (and actually killing the old locale param).
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>
But yes, one needs to whitelist parameters at that point, according to application's context.
You can parse request_uri, and replace your locale in the path with regular expression
Ok, here is helper example. If I correctly understand the goal
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"
This is a start point, so you can make some different stuff that you need
You can safely use url_for to switch locales with url params if you set only_path: true:
<%= link_to I18n.t('language_name', locale: I18n.locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>
We .clone the params before permitting them all (.permit!), to preserve strong parameters elsewhere. The only more secure solution I could find would be to time consumingly whitelist all params instead...
Robust I18n implementation:
Add a locales.rb initializer to define what I18n.available_locales you support:
# config/initializers/locales.rb
# Permitted locales available for the application
I18n.available_locales = [:en, :fr]
Set a language_name value in each language's locale file (e.g. fr.yml):
fr:
language_name: "Français"
As you add more languages, this ERB will let you generically switch between them:
// 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>
For the controller, we automatically find the correct language for the user by detecting their browser's Accept-Language HTTP header (using the http_accept_language gem).
Set a session cookie to preserve locale across requests.
Or optionally, use default_url_options to insert the ?locale= param into your app's url. I do both.
Controller:
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
This is what worked for me, which preserves params and protects against xss:
= link_to_unless_current "English", url_for( request.params.merge(locale: 'en'))
You could use link_to instead of link_to_unless_current
Have a look at this, though it may not be DRY and proper one, but works perfectly for me. It reads all the parameters you supplied replacing only the locale
EX urls : http://example.com:3000/us/users?t=123&m=343 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

nil class when changing the language from :de to :en but not the other way round

I use the globalize gem to translate content in my Rails App. Everything works fine when I change the language from the default language :en to :de but when I want to change the language from :de to :en I get a NoMethodError (undefined method 'color' for nil:NilClass)
I did some research and tried a few approches but have to admit I don't completely understand this bit which is probably the reason for the error:
application_controller.rb
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
request.subdomain
request.env["HTTP_ACCEPT_LANGUAGE"]
request.remote_ip
end
def default_url_options(options = {})
(I18n.locale.to_sym.eql?(I18n.default_locale.to_sym) ? {} : {locale: I18n.locale})
end
I would highly appreciate a hint how to solve the problem or some explanation how this code works would be very welcome.
Here's the model:
page.rb
class Page < ActiveRecord::Base
translates :name, :permalink
validates_uniqueness_of :permalink, :message => "This url is already taken"
validates_presence_of :permalink
validates_presence_of :name
validates_format_of :permalink, :with => /\A[a-zA-Z0-9-_]*\z/i, :message => 'Url can only contain downcase letters from a-z and numbers from 0-9 and a dash and underscore'
before_save :only_allow_one_home_page
belongs_to :label
has_many :chapters
accepts_nested_attributes_for :chapters, :allow_destroy => true
mount_uploader :backgroundimage, BackgroundimageUploader
def chapters_for_form
collection = chapters.where(page_id: id)
collection.any? ? collection : chapters.build
end
def to_param
permalink
end
end
And the Controller:
pages_controller.rb
def set_page
#page = Page.find_by_permalink(params[:id])
end
And the routes:
resources :labels, do
resources :pages
end
Try changing your link_to the following:
<%= link_to 'E', params.merge(locale: "en") %>
A bit of explanation:
# You must have `before_action :set_locale` somewhere in your controllers
# So, this method is called before your controller code does its job
def set_locale
# This just sets current locale to params[:locale]
# So when you request URL like http://example.org/controller/action?locale=de,
# params[:locale] contains 'de'
I18n.locale = params[:locale] || I18n.default_locale
end
# default_url_options is function which, well, adds default options
# to every call of url_for helper method
# It is also called internally when you build paths and urls for
# resources, like 'labels_path' or 'pages_url'
def default_url_options(options = {})
# This line just says to add 'locale=...' parameter (locale: I18n.locale) to the request,
# unless default locale is selected
# This will preserve your locale between requests
(I18n.locale.to_sym.eql?(I18n.default_locale.to_sym) ? {} : {locale: I18n.locale})
end
Now, returning to the error. You must provide URL params to your link_to helper. You provide only 'locale', but it should somehow determine which page you want the link to be pointing to. By adding params.merge(locale: en) we instruct it to use current parameters (so it will link to current page), only additionally add locale parameter to it.

Rails 3.1 Routes: How to add a locale to beginning of URI when missing?

I'm trying to insert a locale at the beginning of a request URI in a Rails 3.1 app if it is missing. I created a Ruby script that does what I want:
uri = "/products"
re = /\A\/((?:[a-z]{2,2})(?:[-|_](?:[A-Z]{2,2}))?)(\/.*)\Z/
unless uri =~ re
uri = "/en#{uri}"
end
puts uri
So, if the request URI is /en-GB/products (the locale is already present), it doesn't do anything. If it is /products (like the example above), it spits out /en/products.
Now I'm trying to get it to work in my routes file. Here's what I've attempted:
match "(*all)", :to => redirect do |params, request|
uri = request.path_info
re = /\A\/((?:[a-z]{2,2})(?:[-|_](?:[A-Z]{2,2}))?)(\/.*)\Z/
unless uri =~ re
uri = "/en#{uri}"
end
"#{request.scheme}://#{request.host_with_port}#{uri}"
end
My problem is that I can't even get inside the match block. I keep getting an ArgumentError: redirection argument not supported.
I've tried changing it to match "(*all)" => redirect do |params, request| to no avail.
I'm looking at the Rails 3.1 API documentation for these examples.
Is the routes file the place to try and do this? It makes the most sense to me.
Introducing logic in routes smells for me. Controllers are meant for that, and I would use optional scope in routes and before_filter in controller with redirect_to
routes.rb - keep it simple:
scope '(:locale)', :constraints => {:locale=> /[a-z]{2}(-[A-Z]{2})?/ } do
match 'url1' ...
match 'other' ...
end
controller:
before_filter :check_locale
protected
def check_locale
redirect_to "/en#{request.path_info}" if params[:locale].blank?
end
(the above is written from memory)
I find these lines in a before_filter in the ActionController quite usefull.
These lines extracts a locale an redirects e.g. foo.com/fie to foo.com/en/fie (or wahtever locale the current locale is). If the user has a not supported locale, he gets a hint, that he can gon on with english...
def set_locale
params_locale = params[:locale]
if params_locale
if (!Supportedlocale::SUPPORTED.include?(params_locale))
redirect_to "/en/localenotsupported/"
end
end
language_locale = locale_from_accept_language
default_locale = I18n.default_locale
I18n.locale = params_locale || language_locale || default_locale
if params_locale.blank?
redirect_to "/#{I18n.locale}#{request.path_info}"
end
end
def locale_from_accept_language
accepted_lang = request.env['HTTP_ACCEPT_LANGUAGE']
if (!accepted_lang.nil?)
accepted_lang.scan(/^[a-z]{2}/).first
else
"en" #en is default!
end
end
In order to keep parameter like pagination do something like :
def check_locale
if params[:locale].blank?
I18n.locale = :en
redirect_to params.merge!(:locale => I18n.locale)
end
end
So
/controler/action?page=10&search=dada => /en/controler/action?page=10&search=dada

path not working properly when using capybara

I'm using rails 3.0.5, rspec2 with latest capybara.
Routes setup like:
scope "(:locale)", :locale => /de|fr|it|en/ do
resources :dossiers
end
In application_controller I have this:
def default_url_options(options={})
options[:locale] = "es"
options
end
So in my views I can use
link_to 'test', dossier_path(1)
without any problems.
But when I do the same in capybara's visit it tries to use the 1 for the locale and not for the id. It only works when I use
visit dossier_path(nil, 1)
or
visit dossier_path(:id => 1)
But both are ugly and looks like a dirty hack. So why do I need to use this dirty hack and what do I jave to do, so that I can use the path methods just like in the views (so without the dirty hack of having to add nil or explicitly pass :id => ...)? :)
I ran into a similar issue. You can set the default_url_options in a before block like this in request specs:
before :each do
app.default_url_options = { :locale => :es }
end
Unfortunately the route generation happens outside of Application Controller. And Capybara doesn't do any magic to provide default url options from it to route helpers.
But you can specify default locale inside your routes.rb
scope "(:locale)", :locale => /de|fr|it|en/, :defaults => { :locale => "es" } do
resources :dossiers
end
And now if you don't pass :locale option to a route helper it will default to "es". Actually, it isn't necessary to keep def default_url_options anymore in your controller.
I'm running rails 3.2.6 and I use a technique that I found here https://github.com/rspec/rspec-rails/issues/255 under Phoet's comment. Just put this somewhere in /spec/support and it should cover all your specs
class ActionView::TestCase::TestController
def default_url_options(options={})
{ :locale => I18n.default_locale }
end
end
class ActionDispatch::Routing::RouteSet
def default_url_options(options={})
{ :locale => I18n.default_locale }
end
end
Opposite as shown here under Using Capybara with RSpec the only way I've been able to get it working is writing
visit user_path(:id => myuser.id.to_s)
so for you it should be
visit dossier_path(:id => "1")
Does it work?

Rails link to current page and passing parameters to it

I am adding I18N to my rails application by passing the locale using url params. My urls are looking like http://example.com/en/users and http://example.com/ar/users (for the english and arabic locales respectively).
In my routes file, I have defined my routes with a :path_prefix option:
map.resources :users, :path_prefix => '/:locale'
And locale is being set using a before_filter defined in ApplicationController
def set_locale
I18n.locale = params[:locale]
end
I also defined ApplicationController#default_url_options, to add locale to all urls generated by the application:
def default_url_options(options={})
{:locale => I18n.locale}
end
What I want is to add a link in the layout header (displayed in all pages) that would link to the same page but with the other locale.
For instance, if I am browsing the arabic locale, I want a "English" link in the header, that will redirect me back to my current page, and set the locale to english. Is there a way to do this in rails?
Took me a while to find this but here is my solution:
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
From the docs here: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649
When generating a new URL, missing
values may be filled in from the
current request‘s parameters. For
example, url_for :action =>
‘some_action‘ will retain the current
controller, as expected. This behavior
extends to other parameters, including
:controller, :id, and any other
parameters that are placed into a
Route‘s path.
So using url_for will default to the current request's parameters, just change the one's you want in your code. In this case all I changed was :locale, so everything else stays the same.
Note this also works for "hidden" :parameters. So if you have:
map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map'
using the above url_for in the page /en/my_map will not have 'home' in the url (ie /en/home/my_map). Bonus.
So I found a way to more explicitly do this with out relying on (as much) rails magic.
url_for(params.merge({:your_new_parameter => value}))
This should work in any link_to.
All its doing is taking the current request's parameters and merging your new desired hash into them and then creating a new url for that.
Link to current page with different locales
Tested on Rails 4
Hello all.
After some time of research I decide to write my own solution for this.
link_to 'English', url_for( :locale => 'en' )
link_to 'Deutch', url_for( :locale => 'de' )
This works perfect, but it allows XSS Vulnerability just passing parameters in your URL like below:
http://localhost:3000/en/about?host=www.fishingsiteorbadurl.com/%23&port=80
Or worst case:
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
Check out what URLs you will get after going through this link in your application.
My production solution.
Method "change language" redirects to any page with proper locale just using HTTP_REFERER in request object.
Please note: URI.path method for get only path, not whole url
Make "change language" method in any controller:
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
add this to your layout
<%= 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
There is no need to use params.merge or any monkey-patch solution.
I hope this helps, because I personally spent a lot of time to solve it.
A much quicker avenue - and convenient if you have many parameters that change in different places... avoid the clutter with an anchor tag that just merges the new locale param to the existing ones (and actually killing the old locale param).
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>
But yes, one needs to whitelist parameters at that point, according to application's context.
You can parse request_uri, and replace your locale in the path with regular expression
Ok, here is helper example. If I correctly understand the goal
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"
This is a start point, so you can make some different stuff that you need
You can safely use url_for to switch locales with url params if you set only_path: true:
<%= link_to I18n.t('language_name', locale: I18n.locale), url_for( params.clone.permit!.merge(locale: locale, only_path: true ) %>
We .clone the params before permitting them all (.permit!), to preserve strong parameters elsewhere. The only more secure solution I could find would be to time consumingly whitelist all params instead...
Robust I18n implementation:
Add a locales.rb initializer to define what I18n.available_locales you support:
# config/initializers/locales.rb
# Permitted locales available for the application
I18n.available_locales = [:en, :fr]
Set a language_name value in each language's locale file (e.g. fr.yml):
fr:
language_name: "Français"
As you add more languages, this ERB will let you generically switch between them:
// 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>
For the controller, we automatically find the correct language for the user by detecting their browser's Accept-Language HTTP header (using the http_accept_language gem).
Set a session cookie to preserve locale across requests.
Or optionally, use default_url_options to insert the ?locale= param into your app's url. I do both.
Controller:
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
This is what worked for me, which preserves params and protects against xss:
= link_to_unless_current "English", url_for( request.params.merge(locale: 'en'))
You could use link_to instead of link_to_unless_current
Have a look at this, though it may not be DRY and proper one, but works perfectly for me. It reads all the parameters you supplied replacing only the locale
EX urls : http://example.com:3000/us/users?t=123&m=343 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

Resources