2010-03-30 8 views
45

Estoy agregando I18N a mi aplicación de rieles al pasar la configuración regional usando parámetros de URL. Mis direcciones URL se parecen a http://example.com/en/users y http://example.com/ar/users (para las configuraciones regionales en inglés y árabe, respectivamente).Los rieles enlazan a la página actual y le pasan los parámetros

En mi archivo de rutas, he definido mis rutas con la opción: path_prefix:

map.resources :users, :path_prefix => '/:locale' 

y la configuración regional se está estableciendo el uso de un before_filter definido en ApplicationController

def set_locale 
    I18n.locale = params[:locale] 
end 

que también definió ApplicationController # default_url_options, para agregar la configuración regional a todas las direcciones URL generadas por la aplicación:

def default_url_options(options={}) 
    {:locale => I18n.locale} 
end 

Lo que quiero es agregar un enlace en el encabezado de diseño (que se muestra en todas las páginas) que se vincularía a la misma página pero con la otra configuración regional.

Por ejemplo, si estoy navegando por la configuración regional árabe, quiero un enlace "Inglés" en el encabezado, que me redireccionará a mi página actual, y estableceré la configuración regional en inglés. ¿Hay alguna manera de hacer esto en los rieles?

Respuesta

106

Me tomó un tiempo para encontrar esto, pero aquí está mi solución:

link_to 'English', url_for(:locale => 'en') 
link_to 'Deutch', url_for(:locale => 'de') 

a partir de los documentos aquí: http://api.rubyonrails.org/classes/ActionController/Base.html#M000649

Cuando se genera una nueva dirección URL, faltaLos valoresse pueden completar a partir de los parámetros de la solicitud actual . Para el ejemplo , url_for: action => 'some_action' retendrá el controlador actual, como se esperaba. Este comportamiento se extiende a otros parámetros, incluido : controlador,: id y cualquier otro parámetro que se coloca en la ruta de una ruta .

Por lo tanto, si usa url_for tendrá los parámetros de la solicitud actual de forma predeterminada, simplemente cambie la que quiere en su código. En este caso, todo lo que cambié fue: locale, por lo que todo lo demás permanece igual.

Tenga en cuenta que esto también funciona para los parámetros "ocultos". Así que si usted tiene:

map.my_map ':locale/my_map', :controller => 'home', :action => 'my_map' 

utilizando el url_for más arriba en la página/es/my_map no tendrán 'casa' en la URL (es decir,/es/home/my_map). Prima.

+0

Gracias, esta sería una solución elegante. Sin embargo, no funciona con URLs tranquilas: s – Faisal

+0

Esto es genial y elegante, he estado buscando una solución como esta por horas ... No entiendo por qué no cumple con las URL RESTful? Puede dar un ejemplo ? – Alex

+2

Si quiere suprimir la configuración regional: url_for (: locale => nil) –

2

puede analizar request_uri, y reemplazar la configuración regional en el camino con expresión regular

autorización, aquí es ejemplo ayudante. Si he entendido bien el objetivo

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" 

Este es un punto de inicio, para que pueda hacer algunas cosas diferentes que usted necesita

+0

Esperaba un ayudante que hiciera eso por mí. Pero hasta ahora, esta es la única solución que he encontrado. Supongo que haré algo como request.request_uri.gsub (/ \/en \ //, '/ ar /') ... Eso debería hacer el truco Gracias por la entrada – Faisal

+0

Ok, he añadido la muestra ayudante – fl00r

1

Eche un vistazo a esto, aunque puede no ser SECO y adecuado, pero funciona perfectamente para mí.Se lee todos los parámetros que proporcionó reemplazar sólo las direcciones URL local EX: 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 
14

así que encontré una manera de hacer más explícita con este cabo apoyándose en (como mucho) carriles de magia.

url_for(params.merge({:your_new_parameter => value})) 

Esto debería funcionar en cualquier link_to.

Todo lo que hace es tomar los parámetros de la solicitud actual y fusionar su nuevo hash deseado en ellos y luego crear una nueva url para eso.

+1

Esta es la mejor solución, la más genérica. Gracias. –

+3

Esta solución expone todos los parámetros, incluso aquellos que se enviaron con POST, p. contraseñas Por favor no lo uses – Franz

+0

No si usa parámetros potentes como se supone que debe estar haciendo. el ejemplo es psuedocode ... – Will

5

Enlace a la página actual con diferentes lugares

Probado en los carriles 4

Hola a todos. Después de un tiempo de investigación, decido escribir mi propia solución para esto.

link_to 'English', url_for(:locale => 'en') 
link_to 'Deutch', url_for(:locale => 'de') 

Esto funciona perfecto, pero permite XSS vulnerabilidad parámetros simplemente pasan en su URL, como a continuación:

http://localhost:3000/en/about?host=www.fishingsiteorbadurl.com/%23&port=80 

O peor de los casos:

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 

Checa lo que URLs obtendrá después de ir a través de este enlace en su aplicación.

Mi solución de producción. El método "cambiar el idioma" redirige a cualquier página con la configuración regional adecuada simplemente utilizando HTTP_REFERER en el objeto de solicitud. Tenga en cuenta: método para obtener URI.path único camino, no toda url método

Marca "cambio de idioma" en cualquier controlador:

 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 

Agregar a su disposición

<%= 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 

No hay necesidad de utilizar params.merge o cualquier solución de mono-parche.

Espero que esto ayude, porque personalmente gasté mucho tiempo para resolverlo.

+0

Quizás sea demasiado tarde, pero aquí tengo un problema: rails dice que falta un parámetro: lang. ¿Alguna idea? –

Cuestiones relacionadas