I would like to know if there is a way to insert, alter and remove i18n locale keys programatically (I guess I could use the DB, but I like Rails i18n and want to stay as close to it as possible).
Basically I want to know if there's a way (native, gem, plugin, whatever) to do things like:
I18n.add_locale_key("en", "application.messages.submit_message", "Submit message!")
I18n.add_locale_key("es", "application.messages.submit_message", "Enviar mensaje!")
I18n.remove_locale_key("en", "application.messages.submit_message")
I18n.remove_locale_key("es", "application.messages.submit_message")
As packaged, the Rails I18n API only support defining locale terms via the local .yaml or .rb files. Short of dynamically editing those files at runtime, your best bet is to use the DB functionality of a gem gem like FastGetText.
You could also roll your own solution, of course, but the DB method will likely work for your use case and will result in a smaller time investment.
Here's one way to do it:
>> I18n.backend.store_translations :en, :hello_world => "Hello, world."
=> {:hello_world=>"Hello, world."}
>> I18n.t :hello_world
=> "Hello, world."
Related
After coding the app in English, I updated the language file (pt-BR.yml), the 'config/application.rb' (setting the default to pt-BR), and the 'inflections.rb'in order to have the error messages in my local language.
However, Rails now does not find my model because its logic does not pluralize in English anymore.
Is there a way to prevent Rails to use the local default language in models and controllers?
Or is there a better coding practice for it?
Thanks.
You can configure your inflections.rb rather than converting the default lang. You can do that like so:
ActiveSupport::Inflector.inflections(:es) do |inflect|
inflect.plural(/$/, 's')
inflect.plural(/([^aeéiou])$/i, '\1es')
inflect.plural(/([aeiou]s)$/i, '\1')
inflect.plural(/z$/i, 'ces')
inflect.plural(/á([sn])$/i, 'a\1es')
inflect.plural(/é([sn])$/i, 'e\1es')
inflect.plural(/í([sn])$/i, 'i\1es')
inflect.plural(/ó([sn])$/i, 'o\1es')
inflect.plural(/ú([sn])$/i, 'u\1es')
inflect.singular(/s$/, '')
inflect.singular(/es$/, '')
inflect.irregular('el', 'los')
end
Code taken from https://davidcel.is/posts/edge-rails-a-multilingual-inflector/
It looks like his gem also supports pt-BR https://github.com/davidcelis/inflections. I haven't personally tried it but it looks sane.
I have many ymls in my rails app, and i want to put some of them in other service, so that i can call this from multiple places.
the response of this call will be a hash.
{"en" :
{"test" :
{"text1" : "hi english"},
{"text2" : "mambo number %{num}"}
},
"es" :
{"test" :
{"text1" : "hi espaniol"},
{"text2" : "mamboes numeros %{num}"}
}
}
is there a way i can load that hash into I18n translations
like
I18n.add_translations(some_hash)
so i can access them with
I18n.t("test.text1")
I18n.t("test.text2", :num => 5)
how can i achieve it?
The dirty way
You could override the load_translation method in I18n::Backend::Base through a custom module or gem or -- cough -- monkey patching -- cough -- to fetch the translations from different sources, it feels dirty to me but I guess you could try experimenting with that before going further.
https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/base.rb#L13
Changing the I18n Backend
You can create a different I18n Backend that implements the expected behaviour and hook it up to I18n through an initializer. I'm assuming that's how tools like localeapp and phraseapp do it. There is a method just for that in I18n::Config
https://github.com/svenfuchs/i18n/blob/master/lib/i18n/config.rb#L23
So you can just do this in an initializer
I18n.backend = MyAwesomeI18nBackend.new
The good thing is that you can chain multiple backends together
I18n.backend = I18n::Backend::Chain.new(MyAwesomeI18nBackend.new)
It makes sure you still have access to the default translation backends or other custom backends.
References
Ryan made a great railscast back in the days explaining how to change backends. It's a bit outdated but it gives you a good idea of what needs to be done.
I18n Backends
If your translations are related to some data saved in a database, you could also use globalize to handle those.
https://github.com/globalize/globalize
EDIT: Simpler way by Dima
If you have a hash, you can use the default backend's store_translation method to load translations from that hash.
I18n.backend.store_translations(:en, {test: "YOOOOOHHHHHOOOO"})
I'm using the I18n Gem from Sven Fuchs in my Ruby on Rails 3.2 Application and while the gem works great I came across a situation, which I don't know the solution to:
I have a seed file, which contains the basic translation for my MVC's and is seeded, when I install my application on a new machine. The problem is that when one of these translations changes, I have to go to my seed file, edit it, delete in the database and reseed it. Which is problem not the best way to do this.
Furthermore, my application can create complete MVC's on the fly, which of course need translations as well. These translations get only stored in the database. But it would be nice to store them in a real file, keep them under version control and import or export them if I need to.
So, basically what I'm looking for, is an intelligent connection between the translations in my database and the ones in my files. So I can populate one from the other or vica verca and keep them in sync.
And also I looked at solutions like Globalize3 or localeapp, but they don't seem to fit.
Summarized, what I have is:
The I18n Gem from Sven Fuchs with a Backend I created myself
A Seed File which changes sometimes and has to be edited manually but seeds the basic translations
A database which contains translations that are created on the fly and are not under version control, nor stored in some file
What I want:
A sync between translations in my seed file and my database
A way to put my translations under version control
I'm sure I can't be the only one who needs this...
Thanks in regards!
Here is how I solved a problem closer to the question asked:
task :task_name => [:environment] do
file = "db/file_name.txt"
counter = 0
CSV.foreach(file, :headers => true, :col_sep => "^", :quote_char => "~") do |row|
identifier = row[0].to_i
model_name = ModelName.find_or_create_by_identifier(identifier)
I18n.locale = row[1]
model_name.name = row[3]
model_name.save!
end
end
Note that identifier needs to be a unique identifier that doesn't change and exists in the file and in the database. In this example, the columns are separated by "^" and quores are "~"
As #tigrish said in the comments, it is not a good idea to insert in the file and in the database, so it is important to restrict this.
These links may also help:
http://railscasts.com/episodes/396-importing-csv-and-excel
http://jasonseifer.com/2010/04/06/rake-tutorial
As the question is a little old, I hope it can help somebody else.
I am using devise_invitable gem in rails and I have configured a number of locales in my rails app. What I would like to do is to invite a user with a locale I would specify myself. I t could look something like this:
User.invite!(:email => "test#example.com", :locale => 'fr')
This would send an email with the 'fr' as locale , even when I18n.locale would be en.
Is this possible, even with a complete different syntax than the one I am using above ?
Digging, I found that devise_invitable uses the devise mailer, see source. I'm not 100% sure how I18n.t exactly works, but I suppose you know that. So use alias_method_chain to monkey-patch the translate method. To pass the other language, you can choose one:
modify the whole call stack to pass down the variable
use a pseudo-global variable via Thread.current[].
I propose to use 2., make your choice. Then use that variable to return the correct translation.
I use FastGettext in my Rails application.
I need a particular string translated into every single FastGettext.available_locales in my application.
How to do that?
PS: I couldn't find the solution with I18n either. (see answer below)
It seems to me that you can do something like that with I18n :
I18n.available_locales.each do |loc|
# do something with...
I18n.t(keypath, :locale => loc)
end