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"})
Related
I am introducing a new locale to my application, and copy all existing files in config/locales/.locale1.yml to config/locales/.locale2.yml.
At first I expect that I18n.backend.send(:translations)['locale1'] would equal I18n.backend.send(:translations)['locale2'], but when I diff both hashes I realise that my new new 'locale2' is missing a bunch of translations.
I figure that for locale1 additional translations have been loaded from gems like for instance the popular rails-i18n gem.
As there is no (easy) way to find out in which .yml file a translation was defined, I want to get a list of all locale-files loaded from any gems.
Any suggestions how to get that information?
Even more interesting would be if I could actually implement a way to figure out from which file a translation was loaded, but I guess that would require writing a custom i18n backend that somehow stores where each key was loaded from.
After phrasing the question, it became quite clear what I need to search for: 'rails i18n load paths'.
By using:
Rails.configuration.i18n.load_path.select { |path| path.match('bundle/gems') }
I get close to what I need. Still not a list of what files are actually loaded or containing translations for the locale of interest, but at least a list of all gems that are considered by i18n.
I want to match the locale code to the specific language name. Is there any build in function in I18n/rails which would return the language name to the corresponding locales. Is installing a gem is the only way?
It seems there is no method for this in I18n.
If you just need current language name, you can easily include it in corresponding locale file:
# config/locales/en.yml
en:
language_name: "English"
And get it as usual: I18n.t('language_name') or I18n.t('language_name', locale: :en).
For general purposes you could use: https://github.com/hexorx/countries or initialize your own mapping as a ruby hash: { en: 'English', ... }.
Without installing an additional gem, you could make your own key/value pairs (either store it in a json file or store it to DB) and then lookup key eg "de" and read the value (in this case, "German"). It requires a bit of manual work (or setup a rake task or something to build it for you in appropriate format from some info source) but you aren't dependent on an additional gem in that case (which, without going thoroughly through the code, might have a far greater impact on your app performance/memory wise than your custom implementation for your specific need for all you know).
I am not aware of any rails built in functions that would return the entire language name, though. You can return the language abbreviation (eg for use in html lang attribute), but I think it stops there as far as the built in functions are concerned).
Have a look the following post in google groups (Gist). I hope there is no default support for the required conversion in rails.
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."
Hoping some learned Rails developers here can recommend an existing Ruby on Rails plugin or gem that allows you to continue using the Simple I18n backend whilst allowing you to optionally specify translations in the database.
Here's why:
I have one Rails app used for many websites. For the example I'll just use 2 websites:
Website 1: Leprechauns R Us
Website 2: Unicorns R Us
Most translations are the same for both websites, but occassionally I want to override a translation. For example, in my en-US.yml file I have the following translation:
view_all: View all
And for most websites this translation is fine, including for website 1 (Leprechauns) where I'm happy to use "View all".
However, for website 2, I'd like to use "View all Unicorns" as the view_all translation and I'd like to specify this in the database. For maintenance reasons I don't want to specify this override in a YAML file.
Many thanks,
Eliot
In the end I opted to take advantage of Rails' I18n::Backend::Simple's ability to process both .yml files and .rb files as locale dictionaries.
Artifacts created:
DB migration to create a translations table with columns: locale, key, text
Translation model to map to the translations table
Class method to_locale_hash on Translation model that returns a locale keyed hash as required by I18n::Backend::Simple.load_rb
A single-line file located at config/translations.rb with the line 'Translation.to_locale_hash'
For the source code see the Spree extension (sorry not in a Rails plugin structure, it will be easy to move over to a plugin should you require it) here:
http://github.com/eliotsykes/spree-i18n-db/tree/master
I have never worked with web services and rails, and obviously this is something I need to learn.
I have chosen to use hpricot because it looks great.
Anyway, _why's been nice enough to provide the following example on the hpricot website:
#!ruby
require 'hpricot'
require 'open-uri'
# load the RedHanded home page
doc = Hpricot(open("http://redhanded.hobix.com/index.html"))
# change the CSS class on links
(doc/"span.entryPermalink").set("class", "newLinks")
# remove the sidebar
(doc/"#sidebar").remove
# print the altered HTML
puts doc
Which looks simple, elegant, and easy peasey.
Works great in Ruby, but my question is: How do I break this up in rails?
I experimented with adding this all to a single controller, but couldn't think of the best way to call it in a view.
So if you were parsing an XML file from a web API and printing it in nice clean HTML with Hpricot, how would you break up the activity over the models, views, and controllers, and what would you put where?
Model, model, model, model, model. Skinny controllers, simple views.
The RedHandedHomePage model does the parsing on initialization, then call 'def render' in the controller, set output to an instance variable, and print that in a view.
I'd probably go for a REST approach and have resources that represent the different entities within the XML file being consumed. Do you have a specific example of the XML that you can give?