I have PO files (en.po & fr.po) that I want to use to localize my Rails application into French. I submitted the question https://stackoverflow.com/questions/17203622/translating-a-rails-application-3-2-13-using-po-gettext-files recently to see if I could get any help. I mentioned that I had read some information about Fast-Gettext and another gem. I decided to look at the Fast-Gettext gem since it allows the use of PO files without using a database.
I added the latest versions of fast_gettext and gettext_i18n_rails in my Gemfile. I installed the latter gem to get rid of an undefined method "_" error message even though I have no plans at this point to use the database feature.
I added the following code in config/application.rb.
# add FastGettext configuration
FastGettext.add_text_domain 'my_app', :path => 'config/locales', :type => :po, :ignore_fuzzy => true, :report_warning => false
FastGettext.default_text_domain = 'my_app' # set the default textdomain
FastGettext.default_available_locales = ["en","fr"] # set available locales # (note: the first one is used as a fallback if you try to set an unavailable locale)
FastGettext.default_locale = 'en'
Here is my setup in application_controller.rb to allow the locale to be set and saved using a cookie.
include FastGettext::Translation
before_filter :set_users_locale
def set_users_locale
I18n.locale = FastGettext.set_locale(params[:locale] || cookies[:locale] ||
request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
cookies[:locale] = I18n.locale if cookies[:locale] != I18n.locale.to_s
end
I added logic where the user can click a flag and set the value of :locale.
<%= link_to_unless_current image_tag("flag_us_30px.jpg", :alt => "Set Language to English"), locale: "en" %>
<%= link_to_unless_current image_tag("flag_fr_30px.jpg", :alt => "Set Language to French"), locale: "fr" %>
When a person clicks the flag it sets the value of :locale correctly. I have my routes formatted as domain.com/:locale/link. Right now the root will include the locale until I add logic to override it.
Here are two statements in my views that I am testing with:
<%= _("Language") %>
<%= _("Note: If you do not understand the text on the icons, use the text links at the bottom of the page.") %>
When I click the French flag to change the value of :locale to "fr" the link changes properly but the code for both strings remains in English. The PO file has the French translation for both of these terms. I would think that if it had not found the PO files that I should be seeing error messages stating it did not find them.
I first attempted to use the configuration code in config/initializers/fast_gettext.rb but did not get any results so I decided to put it in config/application.rb to see if I could get it to work. I also removed ':ignore_fuzzy => true, :report_warning => false' to see if that may change things. However I get the same results.
I am using fast_gettext because back in 2011 #svenfuchs recommended it for using Gettext. I may try and contact him on Twitter since it looks like that is the only place I can find where he is active these days.
Any help would be appreciated.
Why are you using PO files instead of common Rails translations?
Or the globalize3 if you prefer to save the translations on database and add model translations.
There's also a gem to help you converting your existing translations: i18n-translators-tools.
Related
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.
I have removed gem routing-filter from my Rails 3.2.13 application in preparation to upgrade it to Rails 4. The author(s) have a beta version for Rails 4 but I could never get it to work. I have implemented the normal Rails process for localization/internationalization. The last issue I need to resolve is a link_to statement that displays a thread in a mailer view.
When I was using routing-filter I had the link_to statement as below where I set #host in my mailer depending on the environment.
<%= link_to "#{t :view_thread}", micropost_url(#item), host: "#{#host}" %>
When I uninstalled routing-filter I started getting errors because of a missing locale when the attempt is made to send the email. It crashes and sends the application back to the landing page. The gem took care of this.
I have been searching for about an hour trying to find the correct syntax for this but I'm not finding any examples that include both the host and locale parameters. I have tried several guesses but I get syntax errors.
Any help would be appreciated. I will keep searching and trying.
Here is the solution I came up with. I was not sure where the locale clause should go related to the host clause. I decided to try the statement below and it worked.
<%= link_to "#{t :view_thread}", micropost_url(#item, locale: I18n.locale.to_s), host: "#{#host}" %>
Updated solution for Rails 6 (and probably 5).
First, make sure you followed Rails guides on localization, so it's all set up
Then, add this to your ApplicationMailer:
def default_url_options(options = {})
ActionMailer::Base.default_url_options
.merge(locale: I18n.locale)
.merge(options)
end
This will use your selected locale for links generation, so you don't have to pass locale: #locale every time.
And then, set current locale in your mailers with the following block.
I18n.with_locale(#locale) do
mail(to: #email,
subject: I18n.t("mailers.my_mailer.subject"))
end
The last piece of advice - don't forget to fallback with your #locale var, so it's smth along these lines: #locale = #user.locale || I18n.default_locale
Update:
Or you can simply monkeypatch mail method, but make sure you know what you're doing.
def mail(**)
I18n.with_locale(#locale || I18n.default_locale) { super }
end
I have 8 controllers using will_paginate to paginate their index pages. I'd like to override the defaults for "Previous" and "Next" on each without having to specify the same options 8 times. Is there a way to override the defaults only once (perhaps by subclassing will_paginate).
will_paginate uses I18n so you can just use that.
Given you use English as the default locale the following line should be present in application.rb:
config.i18n.default_locale = :en
you can then change the text of the pagination links by adding the following to config/locales/will_paginate.en.yml:
en:
will_paginate:
previous_label: "← go back"
next_label: "go forward →"
Alternatively you can add them to your default translations file: config/locales/en.yml
but I have found that it quickly becomes to large to handle.
Note: If you use another locale, for instance es, for this to work you need to at least replace the en: keys within the YAML files to es: and to be concise about naming your files,
use either config/locales/will_paginate.es.yml or config/locales/es.yml.
I'm assuming you're doing something like this in your controllers:
will_paginate #collection, :previous_label => '< go back', :next_label => 'go forward >'
Your problem is that you want to use these labels everywhere in your application, so it's pointless to repeat them. In that case, you could define a helper like this:
def paginate(collection, options = {})
defaults = {
:previous_label => '< go back',
:next_label => 'go forward >',
}
options = defaults.merge(options)
will_paginate collection, options
end
After that, calling paginate #collection in your views will use your defaults and still let you override them if necessary.
EDIT: suweller's response is definitely the better way to go in this case, especially considering it's approved by mislav, the plugin creator :). I'd completely forgotten about the translation file option. My solution could probably be useful in the general case, when the helper is not configurable in a similar way.
I'm using the default I18n module for Rails to translate my strings in views.
<%= t("registration.heading") %>
Now, when I'm in the registration-view, all my strings start with registration. I always have to write
<%= t("registration.heading.notice") %>
// or
<%= t(:heading, :scope => :registration) %>
It would be nice to define a default scope for that file (maybe even in the controller), so a call to t automatically adds the defined scope
// controller
set_i18n_default_scope :registration
// view
<%= t(:heading) %>
// --> looks in "registration.heading"
Is this possible?
If you organize your translations adding a view name, as in:
en:
registration:
index:
heading: "Registration heading"
then you may use this:
<%= t(".heading") %>
Notice that the first character is a dot.
You may read about it in Rails Internationalization (I18n) API Guide
If you have texts which are shared amongst numerous views, and you don't want to copy the same translation in each section for each view, you may use YAML references. They are nicely described on wikipedia: http://en.wikipedia.org/wiki/YAML#Repeated_nodes
It is possible. Check section 4.1.4 of the Rails i18n API
4.1.4 “Lazy” Lookup
Rails 2.3 implements a convenient way
to look up the locale inside views.
When you have the following
dictionary:
es: books:
index:
title: "Título"
you can look up the books.index.title value inside
app/views/books/index.html.erb
template like this (note the dot):
<%= t '.title' %>
Regarding Lazy Lookups:
Here's the general solution for this kind of problem
Common Problem: Where is Rails trying to look-up L10N / I18N Strings? - e.g. when doing Lazy Lookups
It's not easy to guess, because it's different for Views, Controllers, Models, Labels, Helpers, or Validations... etc... but...
It's easy to find out directly, using this:
http://www.unixgods.org/Rails/where_is_Rails_trying_to_lookup_L10N_strings.html
this helps figuring out what Rails thinks the current scope is (e.g. when using ".heading")
3 Simple Steps:
create a file ./config/initializers/i18n.rb , as described in the article above
put t('.heading') in your view
start "rails server" and look in the console output where Rails thinks the default location is for '.heading' for this view... e.g. what's the I18N-key
(4. then add the I18N string into the location identified by the key)
Works like a charm :-)
If you want to print out keys that I18n gem's lazy mode is looking for, you can add that in a i18n.rb file in your initializers folder:
module I18n
module Backend
class Simple
module Implementation
alias_method :lookup_orig, :lookup
# Give ability to check I18n looked up keys in lazy mode by setting env var I18N_DEBUG to true
#
def lookup(locale, key, scope = [], options = {})
puts "I18N keys: #{I18n.normalize_keys(locale, key, scope, options[:separator])}" if ENV['I18N_DEBUG']
lookup_orig(locale, key, scope, options)
end
end
end
end
end
(Gist: https://gist.github.com/capripot/6e6cf778ad2db0443280)
And then start your server like for instance:
I18N_DEBUG=true bundle exec rails server
Other than copying Facebook's SELECT and OPTION elements, is there a Rails-native way of generating a Facebook-esque, localized-language select list?
If by "Rails-native" you mean "provided by Rails core," then no. However, you can access a list of locales your app provides translations for via I18n.available_locales. If one of the values of your locale is a localized version of the name of the language, you can use it to build a select:
# as a helper
def available_locales
I18n.available_locales.map{ |l| [t('name', :locale => l), l] }
end
# in a view
= select_tag :language, options_for_select(available_locales, I18n.locale.to_sym)
If you want something that will build the list for you, you might check out a Gem or plugin, such as localized_language_select.