I'm having an existing website. Now I want to launch this same website with a new name, URL & logo in Canada. The difference would be only URL, name and logo. Rest everything (App, DB, layout, server etc.) will remain same.
I developed the website in ruby on rails 3.2. What is the BEST way to get this done ?
if a user comes at www.existing.come will be able to see the existing layout
if a user comes at www.forcanada.com. it will load the same website but different logo n name
You could use the I18n mechanic for it. Do something like the following code in the controller:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def set_locale
case request.host.split('.').last
when 'de'
I18n.locale = :de
when 'com'
I18n.locale = :en
else
I18n.locale = I18n.default_locale
end
end
end
Than use index.de.html.erb or index.en.html.erb for the different views. You can create your own "language" for each site. en and de are just examples.
Have a look at
http://xyzpub.com/en/ruby-on-rails/3.2/i18n_mehrsprachige_rails_applikation.html
Related
I'm developing a internationalized application, and sometimes I need to get some messages in a language that is not my default, like this:
I18n.t("my_message.some_attribute", :locale => :ptBR)
The problem is: I have an API method that creates and active record object, and I would like to render the error message from the method full_messages, like this:
my_object.errors.full_messages.uniq.to_sentence
The problem is, in that case, I get the message for my default language. How could I get that sentence in another language?
Thanks!
Got my answer... since the language come as a param to my api, in my app controller I set the locale before_action:
before_action :set_locale
def set_locale
I18n.locale = params[:lang] || "en"
end
This works for me
In development mode all work fine. But not in production mode on heroku.
When I select a locale and I refresh the page, it displays language by default half the time and the language I selected otherwise. I do not know what to do. I tried to clear the cache with Rails.cache.clear command, but it does not work. I guess the problem is with the cache system. I'm new to ruby on rails. Someone would have an idea how to fix this?
to understand my problem, you can go to my website, select the French language and refresh the page several times. Once the page is in French. Another time in English.
https://releaseit.herokuapp.com/
my application_controller:
before_action :set_locale
def set_locale
if params[:locale].in? %W(en fr)
I18n.locale = params[:locale]
end
end
The config files are same as here: https://github.com/starterkits/rails4-starterkit/tree/master/config
Sorry for my english (I am french and i use google translator)
I don't know (or see) where do you pass locale in URL. As far as I know in order to use params[:locale] your URL should look like:
https://releaseit.herokuapp.com/fr/something
https://releaseit.herokuapp.com/en/something
https://releaseit.herokuapp.com/en
https://releaseit.herokuapp.com?locale=fr
http://guides.rubyonrails.org/i18n.html#setting-the-locale-from-the-url-params
What is more try my set_locale method:
def set_locale
if params[:locale]
I18n.locale = params[:locale] || I18n.default_locale
else
I18n.locale = http_accept_language.compatible_language_from(
I18n.available_locales
)
end
end
set_locale method should be executed on every page reload to set proper locale each time.
It requires http_accept_language gem from: https://github.com/iain/http_accept_language
Check out also route_translator gem for creating routes with locale.
I'm trying to internationalize a Rails/Spree app using spree's own spree_i18n gem, but I can't get it to work.
I made a minimal app which recreates the problem here.
To cut a long story short, I have the following code in my ApplicationController:
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
puts I18n.locale
end
And code in my view which should be translated (<%= t("whatever") %>). But no matter what I do, the text is always output in English.
With some additional code for debugging, I can see that once set_locale is called but while execution is still within the controller, the locale is correct (e.g. if I visit the url /?locale=es, then the puts statement in the above controller code outputs es).
But by the time execution has reached the view, the locale has somehow been reset to en. (E.g. adding <% raise I18n.locale.to_s %> within the view raises "en" as an error message.)
I've opened an issue on Spree's Github because as far as I can tell I've followed their instructions exactly and it's still not working, but I may still be missing something. Why isn't the locale getting set properly?
(Note: I should add that the Spree.t doesn't work either, not just t.)
EDIT: If you look at the comment on my Github issue, you'll see that I got it working. However, I'm 99% sure that my solution is a hack and there's a better method I should be using. Bounty goes to whoever can tell me what I'm dong wrong.
Spree I18n gives a way to set default language: on config/application.rb with
config.i18n.default_locale = :es
And the possibility of setting the languages to be changed. Perhaps on config/initializers/spree_i18n.rb
SpreeI18n::Config.available_locales = [:en, :es, :de]
SpreeI18n::Config.supported_locales = [:en, :es, :de]
After that, you can remove set_locale on ApplicationController, because it has no effect.
With this at place, it works like a charm.
Edited:
I change the message of error because I want to be sure that it works:
<%= product_description(#product) rescue Spree.t(:product_has_no_description) +
' ' + Spree.t(:action) %>
And I add a new product without description. Running the server at localhost
In english I see: "This product has no description Action"
In spanish I see: "Este producto no tiene descripción Acción"
In deutsch I see: "Produkt hat keine Beschreibung Aktion"
Exactly the expected.
You can see the source with changes at github
It is unclear to me how Spree handles localization and in your routes.rb you only mounts engine.
Basically you should start localize your app within routes.rb by adding:
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
# routing and engines go here
end
Now, you need to keep your params[:locale] across requests, so add to app controller:
def default_url_options(options={})
logger.debug "default_url_options is passed options: #{options.inspect}\n"
{ locale: I18n.locale }
end
Last, detect and set locale for current request, depending on your input data:
before_filter :set_locale
def set_locale
if defined?(params) && params[:locale]
I18n.locale = params[:locale]
elsif current_user && current_user.language_id.present?
I18n.locale = current_user.language.code
elsif defined?(request)
I18n.locale = extract_locale_from_accept_language_header
end
I18n.locale ||= I18n.default_locale
I18n.locale = :en unless valid_languages.include?(I18n.locale.to_sym)
end
You may be using/setting the following in app/controllers/application_controller.rb, which doesn't work:
before_action :set_locale
def set_locale
I18n.locale =
Spree::Frontend::Config[:locale] =
Spree::Backend::Config[:locale] = :LOCALE
end
In core/lib/spree/core/controller_helpers/common.rb there is another before_filter called set_user_language. That filter gets called and re-sets the locale to the value of session[:locale], or if that's not defined it uses default locale.
To solve the issue, set session[:locale] = :LOCALE in your before_filter.
I just realized that the recommended Rails way to set locale in your controller
before_filter :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
sets the locale globally. The code above works, but I wonder is default_locale really default if you have to type it explicitly?
What I'd expect is to have a locale per request (like we have session per request) and doing something like:
def set_locale
locale = params[:locale] if params[:locale]
end
And having I18n.default_locale used by default otherwise. This would match ideally the optional locale in path:
# config/routes.rb
scope "(:locale)", :locale => /en|nl/ do
resources :books
end
For now if for some reason I skip locale setting in some action it uses the locale set in the previous request which could be from another user!
And isn't there a potential race condition as one request can change global I18n.locale while another request (having set another locale beforehande) is in the middle of rendering?
UPDATE: Some details I found for now, from the I18n documentstion:
Sets the current locale pseudo-globally, i.e. in the Thread.current hash
def locale=(locale)
Now I want to understand if every request is a separate thread.
UPDATE 2: See my answer for explanation.
So now the final answer. TL;DR Setting locale acts as global only when you use threaded web servers, like Thin and Puma.
As I mentioned, I18n.locale=
Sets the current locale pseudo-globally, i.e. in the Thread.current hash
So it is supposed to be per-request, and it works this way in Webrick and Unicorn.
But if you use threaded web server like Thin or Puma, seems that the thread lives longer, and the value is preserved for future requests, until it is changed explicitly. Where I learned it is from the new Steve Klabnik's gem request_store:
If you need global state, you've probably reached for Thread.current.
<...>
So people are using those fancy threaded web servers, like Thin or Puma. But if you use Thread.current, and you use one of those servers, watch out! Values can stick around longer than you'd expect, and this can cause bugs.
Recommended code from above does not set locale globally it sets it by request.
before_filter :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
Code is usually place in BaseController so before each page is render it is triggered and set. There is no race conditions since every page will trigger this code and I18n locale will be calculated there. You can expand this to let's say looks for users locale, than session locale, than request params, than uses English.
def set_locale
I18n.locale = #user.locale || session[:locale] || params[:locale] || :en
end
In other words if you set local on one page let's say in home controller to german and got to dashboard controller you will see default language (english). Since change is not global. That is why code is placed in base controller. Hope it makes sense.
when our app sends SMS messages, we'd like to give users the option to specify their preferred language.
Using Spanish as an example, I see how to add a new locale yml file to config/locales.
And I see how to replace any hardcoded strings such as "text STOP to opt-out" with :stop_opt_out in my app.
what I don't see is how to select the language used on a user-by-user basis.
specifically if my code is currently:
msg_out = "Thank you!"
and after internationalization I have :thank_you defined in multiple locale yml files
and if in my user record I have user.locale = "en" or "sp" (or should I enumerate locales 0,1,2?)
how would I do a user specific
msg_out = t :thank_you
that would apply to every message created for that user in the current session?
If all your messages are generated when the user is using your site (i.e. all messages are sent as responses to user actions), you can just read the preferred locale out of the User model in a before_filter on your Application Controller (more on this here):
class ApplicationController < ActionController::Base
before_filter :load_user
before_filter :load_locale
#...
def load_locale
I18n.locale = (#user && #user.locale)? #user.locale : I18n.default_locale
end
#...
end
If you're sending your messages asynchronously (e.g. nightly mass-mailings), you'll have to load it per user:
User.find_each do |user|
I18n.locale = user.locale || I18n.default_locale
# Send your message...
end
And if you're sending generic mass-emails (i.e. with no per-user customizations), you can probably speed the above code up drastically by loading lists of users grouped by locale, and then sending a single message to all of them at once.
Hope this helps!