Changing locale but staying on the current page - ruby-on-rails

I did an internationalization of my website.
I used https://github.com/enriclluelles/route_translator
Every link are working depending on the current locale
I have 2 buttons like this : EN | FR
You can click on it to change the locale. It's working like this :
if I18n.locale == :fr
link_to('en', root_en_path)
else
link_to('fr', root_fr_path)
end
The only problem is that if I'm on a certain page in my website and I change the locale, it will comeback to the root_path
What I want is to stay on the same page.
For example: I have a how_it_works page
If I'm in /fr/how_it_works I want the EN button to link to /en/how_it_works
I've been told to pass the locale as a param but I don't want that because I don't want to have a big link like /fr/how_it_works?locale=en and I'm sure that's a bad design

The advice you were given would be the best approach and no, you wouldn't be using a query parameter as you thought.
Rails.application.routes.draw do
scope ':locale', constraints: { locale: /(en|fr)/ } do
#define all your scopeable routes within here
end
end
This way, you can visit /en/how-it-works or /fr/how-it-works. In your ApplicationController, you can do a before action :set_locale where you'd be setting the locale as params[:locale].
Hope that makes it clearer and resolves your issue.
UPDATE
Can't really figure out a better way of achieving this, but here's a way I could immediately work out:
url_params = params.to_h
if I18n.locale == :fr
link_to('en', url_params.merge(locale: :en))
else
link_to('fr', url_params.merge(locale: :fr)
end

Thank good lord for bringing the solution to me! I've just encountered you guys having the same issue so here it is what I have used.
<%= link_to(options = {controller: controller_name, action: action_name, locale: :en} , class: "navbar-item") do %>
<%= image_tag "gb.svg", size: "24x24" %>
<% end %>
For displaying a link to the same page, however changing locales and using an image as link.

After some research, I found a basic way to do it. I first thought this thing was already implemented in route_translator, but apparently no.
The solution :
if I18n.locale == :fr
en_uri = request.fullpath.gsub('/fr', '/en')
good_link = en_uri[0, 3] == '/en' ? en_uri : root_en_path
link_to('en', good_link)
else
fr_uri = request.fullpath.gsub('/en', '/fr')
good_link = fr_uri[0, 3] == '/fr' ? fr_uri : root_fr_path
link_to('fr', good_link)
end

I use a similar setup, and came across this (old) question. Matheus answer helped me to order my thoughts, and for me the solution was as simple as
<%= link_to "fr", controller: controller_name, action: action_name, locale: "fr" %>
Note that this works because I use "scope" in routes.rb:
scope "(:locale)", locale: /en|fr/ do
...
end
This way, the locale gets passed on every request, and fetching it is easy
I18n.locale = params[:locale]
I wanted to share this for others who might come by. Once again, built in rails comes with the power to do amazing things with a few lines.
Happy codin .

What about ? :
<%= link_to "English", current_page_params.merge(locale: :en) %>
See more about it : https://gorails.com/episodes/rails-link-to-current-page-with-params

Related

Link to corresponding path in other locale (rails)

I have a multi-lingual application in Ruby on Rails 4. For that I use the following domains:
Swedish: exempel.se
English: example.com
French: fr.example.com
Spanish: es.example.com
I want to be able to link to the corresponding path in another corresponding locale. For example if I am at www.exempel.se/denna-bloggpost I want to be able to easily link to (English/Spanish/French) to e.g. www.example.com/this-here-blog-post and es.example.com/este-posto-de-bloggo (sorry, can't speak Spanish :)).
I understand this is done with link_to 'Spanish', locale => :es but this gives me the url www.exempel.se/denna-bloggpost?locale=es which is not what I want. I expect to access es.example.com/esto-posto-de-bloggo
It seems like default_url_options has something to do with this but I can't make it work.
How do I solve this?
Edit (2017-03-30): I will also need this solution for hreflang in the section.
I am using the route_translator gem.
I have seen several solutions for this but they all include solutions with ?locale=en or are just to simplified (like, only working for one single controller). What I am hoping for is a solution that would do something like this:
<% I18n.available_locales.each |locale| do %>
<% I18n.t(this route e.g. /denna-bloggpost) #=> /este-posto-de-bloggo, /this-blog-post, /le-post-du-blog %>
<% end %>
You can use the locale-specific routes that route_translator generates for you. Run rake routes to see what these are. And then:
# Create links for every other locale
<% (I18n.available_locales - I18n.locale).each |locale| do %>
# Example URL helper here - replace with your own!
<%= Rails.application.routes.url_helpers.send("posts_#{locale}_url",
'denna-bloggpost') %>
<% end %>
In order to create such a dynamic mapping, you must presumably have something like this defined in your application config:
APP_CONFIG = {
# ...
base_urls: {
se: 'exempel.se',
en: 'example.com',
fr: 'fr.example.com',
es: 'es.example.com'
}
# ...
}
(It wouldn't necessarily need to be in this format, of course; this is just an example.)
In the locale switching menu, you can then define your links like this:
link_to("French", "#{APP_CONFIG[:base_urls][:fr]}#{request.env['PATH_INFO']}")
In order to actually set the locale in your application, you could then place something like this in your ApplicationController:
class ApplicationController
before_action :set_locale
def set_locale
I18n.locale = APP_CONFIG[:base_urls].key(request.host) || I18n.default_locale
end
end
For more information, see here: http://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests
This question is addressed a number of times and many ways. Yet the simplest approach in my opinion is
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>

Rails current url helper

Apologies for such a simple question, but I couldn't been able to solve it myself after hours since my RoR knowledge is basically nonexistent. In the Rails application I'm working with, has been used a navigation helper to highlight active menu:
def nav_link(link_text, link_path, ico_path)
class_name = current_page?(link_path) ? 'active' : nil
content_tag :li do
link_to(link_path, class: class_name) do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
The circumstances have changed and current_page? is no longer a viable option, since routing now handled on the front-end. Is there a way to achieve the same functionality by retrieving, for instance, current url and check it against link_path?. I've tried a lot of things with different helpers like request.original_url, but to no avail.
request.original_url should work according to the documentation.
Returns the original request URL as a string
http://apidock.com/rails/ActionDispatch/Request/original_url
You could also try string concatenation with different variables.
request.host + request.full_path
If that doesn't work either, you could try
url_for(:only_path => false);
Use
request.url
http://api.rubyonrails.org/classes/ActionDispatch/Http/URL.html#method-i-url
or
request.path
http://www.rubydoc.info/gems/rack/Rack/Request#path-instance_method
You'll want to look at the active_link_to gem:
def nav_link(link_text, link_path, ico_path)
content_tag :li do
active_link_to link_path do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
Unlike the current_page? helper, active_link_to uses controller actions and model objects to determine whether you're on a specific page.
current_page? only tests against the current path, leaving you exposed if you're dealing with obscure or ajaxified routes.
--
I was going to write about how current_page? works etc, but since you mentioned that it's nonviable, I won't. I would have to question why it's nonviable though...
routing now handled on the front-end.
Surely even if you're using something like Angular with Rails, you'd have to set the routes for your app?

Can I Set Up Routes That Include The Locale & Default the Locale In The Route When It Is Not Provided?

I currently have routing that requires the locale (i.e. /en, /fr, etc.). At some point I have used all of the statements below in routes.rb:
scope "/:locale", locale: /#{I18n.available_locales.join("|")}/ do
scope "/:locale", defaults: { :locale => "en" } do
scope "/:locale" do
I know that if I do the following if the route does not include the locale that it will point to the English version of the website. However it does not set the locale like I want once the page is displayed. If I go to the French version by clicking my locale logic the first link will display the French version of the page with /fr in the link. However if I click another link on the French page the locale goes back to English with the locale excluded from the link.
scope "(/:locale)", defaults: { :locale => "en" } do
Here is the code for my locale links in my application where a user can click on a flag image or text to change the locale:
<%= link_to_unless_current image_tag("english.jpg", alt: "#{t :english}"), locale: "en" %> <%= link_to_unless_current "#{t :english}", locale: "en" %>
<%= link_to_unless_current image_tag("french.jpg", alt: "#{t :french}"), locale: "fr" %> <%= link_to_unless_current "#{t :french}", locale: "fr" %>
What I would like to do is to prevent a 500 system error if by chance someone has an link saved before the website was localized. For example if they have http://mywebsite.com/video it would display the English version of the website and set the locale to "en".
Here is the code I have in application_controller.rb.
before_filter :set_locale
def default_url_options(options={})
{ :locale => I18n.locale }
end
private
def set_locale
I18n.locale = (params[:locale] if params[:locale].present?) || cookies[:locale] || 'en'
cookies[:locale] = I18n.locale if cookies[:locale] != I18n.locale.to_s
end
I'm not finding anything on this particular issue other than to use the routing-filter gem. I was using the gem but until there is a production version of the gem for Rails 4 I have no option but to figure this routing issue out.
Any help would be appreciated.
i find your question rather confusing... so my answer will refer to some parts of you code. maybe that gives you enough context to fix your problems.
do not use 3 routes for locale
one route is enough, please read the guides for internationlization.
i think that you will have to go with the optional approach as you want to support legacy urls:
scope "(/:locale)" {}
use the config.default_locale option
in the configuration you can configure fallbacks for localization.
don't mix default_url_options and cookies
if you are using cookies to keep track of your locale, you can can skip the default_url_options, you will have to keep the unlocalized versions anyways for backward compatibility.
if you MUST have urls like domain.com/en/something do it the other way around. avoid using cookies, use the URL everywhere and redirect people coming in from a legacy url.

Passing path to current_page method

I have a helper method to help to determine whether or not a navigation menu item should be active/inactive.
def events_nav_link
nav_item = 'Events'
if current_page?(events_path) # additional conditions here
# do nothing
else
nav_item = link_to nav_item, events_path
end
content_tag(:li, nav_item + vertical_divider, :class => 'first')
end
I want this link to be inactive not only for the events_path page, but for other pages as well. Problem is that I don't know what param to pass the current_page?(path) method based on this route:
map.list_events '/events/:league/:year/:month/:day', :controller => 'events', :action => 'list'
This route generates a path such as /pow or /chow/2011/09/25. Leagues can be pow, chow or wow.
I like unobtrusive JS approach with add/remove classes and unwrap() deactivated links, but it requries specific rules.
The Rails way is to use link_to_unless_current built-in helper to highlight and unlink on current page href.
You're looking for named routes. In your routes.rb file, add
:as => :foo
after the route. Then use
if current_page(events_path) || current_page(foo_path)
in your condition.
This is what I do:
application_helper.rb:
def already_here?(this_controller,this_action)
controller_name == this_controller && action_name == this_action ? true : false
end
in a view:
<%= already_here?("users","index") ? "Manage Users" : link_to("Manage Users", users_path, :title => "Manage Users.") %>
Of course, you can abstract it further by passing the title of the link and path to the helper if you want, but that's a bit of a hassle (to me).
UPDATE: never mind, see mikhailov's answer- much cleaner (why reinvent the wheel?) :)

creating dynamic helper methods in rails

I am trying to create a bunch of dynamic helper methods like these:
show_admin_sidebar
show_posts_sidebar
show_users_sidebar
So far I have this in my helper.rb file:
#spits out a partial
def show_sidebar(name, show_sidebar = true)
#content_for_sidebar = render :partial => "partials/#{name}"
#show_sidebar = show_sidebar
end
def show_sidebar?
#show_sidebar
end
In my application layout file I have this: (NB - I'm using HAML):
- if show_sidebar?
= yield(:sidebar)
This allows me to say the following in my views:
- show_sidebar(:foo)
- show_sidebar(:bar)
And this renders the desired partial.
The problem with this is that I can only add one sidebar per page. So, I figure I need to have dynamic methods like: show_admin_sidebar, show_foo_sidebar.
So I have tried to do this:
def show_#{name}_sidebar(show_sidebar = true)
#name = name
#content_for_#{#name}_sidebar = render :partial => "partials/#{#name}"
#show_sidebar = show_sidebar
end
and then in my layout:
- if show_sidebar?
= yield("{#name}_sidebar")
But rails does not like this at all.
I have tried almost everything I can think of in my helper file and nothing works.
The reason I am using helper methods for this is because I want my content div to be 100% page width unless there is a sidebar present in which case the main content goes into a smaller div and the sidebar content goes into it's own..
If I can't get this working, then I can easily fix the problem by just adding the partials manually but I'd like to get my head round this....
Anyone got any experience with this kind of thing?
The entire approach to this was bizarrely overcomplicated, didn't follow Rails conventions at all, nor make the slightest bit of sense, and shame on prior respondents for enabling this approach instead of helping him to simplify. My apologies for being 13 months late with the answer.
Your controller should be deciding if a sidebar is to be shown or not, and setting an instance variable #side_bar_name to either nil or a sidebar name string. Then somewhere in shared view code, probably views/layouts/application.html.erb, you would have something as simple as this:
<% if #side_bar_name %>
<%= render :partial => "partials/#{#side_bar_name}" %>
<% end %>
Or better yet:
<%= render(:partial => "partials/#{#side_bar_name}") if #side_bar_name %>
If you want to use a helper (which is not a bad idea for keeping your code DRY and readable) it would basically be the same code, just moved into the helper.
<%= side_bar_helper %>
def side_bar_helper
render(:partial => "partials/#{#side_bar_name}") if #side_bar_name
end
What the controller does is up to you. It would probably do something like this:
if session[:show_side_bar]
# maybe use cookies instead of session, or store user preference in a database
#side_bar_name = session[:side_bar_name]
end
Here is a solution for you, however I wouldn't suggest too much metaprogramming:
#Add the following snippet to the proper helper module:
['admin','user','whatever'].each do |name|
class_eval{
"def show_#{name}_sidebar(show_sidebar = true)
#name = #{name}
#content_for_#{#name}_sidebar = render :partial => 'partials/#{#name}'
#show_sidebar = show_sidebar
end"
}
end
def show_#{name}_sidebar(show_sidebar = true)
That doesn't look like valid Ruby to me. Are you parsing and evaling this yourself or just throwing that right in the file and expecting it to work?

Resources