I am using Ruby on Rails 4 and, given a number, I would like to display the internationalization "second"/"seconds" string for that number. That is, I have a number (for example, 1 or 20) and I would like to display 1 second or 20 seconds (in english).
I know the date helpers but no method seems to fit for my case. How can I make that?
The usual t function eventually ends up inside the i18n gem's translate method. translate, like any sensible i18n/l10n tool, already knows about the current locale's pluralization rules. That means that you should just tell the translation system which message/string you want to how many of them you have, something like:
t('message-identifier', :count => n)
Then t will use the appropriate pluralization rules for n things in the current locale.
I use gettext for all my translation needs and it behaves this way. But there's no possible way that t wouldn't work this way too; it must work this way or it is utterly useless.
Related
I wonder something. We have an rails app that had been translated in 30/40 languages including exotic languages. We wonder what's the best way to handle numbers and number translation.
For example, we have in english, a string 3 items, but in persian or arabic, it will become something like ٣ سلع. Unfortunately, I am getting 3 سلع using I18n gem.
I am using this file as locale:
https://raw.github.com/svenfuchs/rails-i18n/master/rails/locale/ar.yml
The locale is correclty set to ar it just output 3 in place of ٣ (the arabic/persian character)
Any ideas?
As far as I know there are many ways:
Directly in the code: this could work only if the application doesn't need to be internationalized, but it's not the best, I think.
In the localization files: I've run into the problem that when I internationalize a model, and I have buttons like Create %{model}, if the model has more than one word, it may look awkward if only the first letter is capitalized.
In the code using humanize or titleize: It may lead to capitalization of sentences like Create And Continue, capitalizing the And when you could want to say something like Create and Continue or Create and continue.
Trough CSS: I thought this was the best place because capitalization is part of the style of the page (or not?) and it's similar to use humanize or titleize but you still have the same problems than these.
I've tried them and I've had difficulties with all of them. Especially because there exists acronyms that shouldn't be transformed to lowercase and articles that looks a little ugly when capitalized.
Also, sometimes you want to use the same words but capitalized them different. In this case should be better to use two different entries in the locale files or use 3 or 4 to change them?
When using the 4th option I found difficult to write tests because the html has everything lowercased but it's not really like that. Cucumber doesn't parse CSS to check the style of words.
What is wrong with putting it in the localization? Put each text as you want it to appear on the site, and you're set. If you write the text yourself, there should be no need to programmatically mangle it afterwards.
As for the models: Put human readable names into the translations for each of them. Also, if you think they need to be capitalized differently in some place - capitalize just the model name, not the entire button text.
I've been happily using the built-in rails i18n support for translating strings to different languages, which works great. Recently though I've had a need for something that goes a bit beyond the default behaviour of this gem.
I'll call this "inverse translation" for lack of a better word. Basically the idea is that I have some string in some language, and I want to be able to call a method with another locale, and get back the string translated to that locale if a mapping exists in the locale strings.
For example, assume I have in config/locales/en.yml
en:
hello: Hello World!
and in config/locales/ja.yml:
ja:
hello: Konnichi wa!
then when I call this method l2l_translate ("locale to locale translate") while in the English locale, with the string and the locale as arguments, I get back the Japanese translation:
I18n.locale = :en
l2l_translate("Hello World!", :ja) #=> "Konnichi wa!"
Also, and this is more tricky, I want to be able to inverse match interpolated strings. So say I have:
config/locales/en.yml
en:
minutes: "%d minutes"
config/locales/ja.yml
ja:
minutes: "%d分"
Then I should be able to translate from English to Japanese like so:
l2l_translate("5 minutes", :ja) #=> "5分"
So basically the string should be matched with a regex to the English translation string, and the "5" pulled out and sent as an argument "%d" to the Japanese translation.
Obviously there are potential problems here, if: 1) there is no match, or 2) there are multiple matches. Those could be handled by raising an exception, for example, or by returning nil in the former case and an array of translations in the latter. In any case those are minor points.
My basic question is: does anything like this exist? And if not, does anyone have any suggestions on how to go about developing it (say as a gem)?
The application I'm specifically thinking of is an API wrapper for a service in Japanese. I want to be able to specify patterns in Japanese which can be matched and translated into other languages. The default i18n support won't do this, and I don't know of any other gems that will.
Any advice or suggestions would be much appreciated! For reference see also this discussion in 2010 on the topic of inverse translation with i18n-rails.
We use gettext, which is a standard unix i18n solution. For Rails, you can use gettext_i18n_rails. One caveat is that FastGettext, which gettext_i18n_rails is backed by, doesn't seem to have complete gettext support, and some advanced features such as pluralization didn't work as expected.
I need to be able add days or hours to a previously created Item.
The system can add or subtract a set number of hours or days based on attributes stored in the db, :operator (add/subtract), :unit_of_time(hours/days), and :number.
I'd like to be able to do something like:
Date.today+2.days
where "+" is the :operator, "2" is the :number, and "days" is the :unit_of_time but I'm unsure of how to get the interpolated string of attributes to become the actual operator "+2.days". Any ideas?
(I've poured through the ruby documentation, but to no avail. Currently, I'm just manually creating of the possible options (4) in nested if/else blocks... yeah it's gross.)
You could use eval, e.g.:
eval("Date.today+2.days")
...and then simply use string interpolation to put in the variables. Note, however, that you should only do this if you can be very certain that the values in your database are always what you want them to be; under no circumstances should users be able to change them, otherwise you'll have a major security issue which compromises your entire system.
Using more lengthy methods like the if statement you suggested (or a case statement) require you to write more code, but they are much more secure.
All ruby objects have a send method which can be used to run a method by name with parameters. Using send as well as converting strings to ints (.to_i) should suffice.
Date.today.send '+', '1'.to_i.send('months') # This works
Date.today.send operator, number.to_i.send(unit) # Generalized form
Ruby is beautiful!
I have a requirement to handle custom date formats in an existing app. The idea is that the users have to do with multiple formats from outside sources they have very little control over. We will need to be able to take the format and both validate Dates against it, as well as parse strings specifically in that format. The other thing is that these can be completely arbitrary, like JA == January, FE == February, etc...
to my understanding, chronic only handles parsing (and does it in a more magical way then I can use), and enter code here DateTime#strptime comes close, but doesn't really handle the whole two character month scenario, even with custom formatters. The 'nuclear' option is to write in custom support for edge cases like this, but I would prefer to use a library if something like this exists.
I don't think something that handles all these problems exists if the format is really very arbitrary. It would probably be easiest to "mold" your input into a form that can be handled by Date.parse, Date.strptime, or another existing tool, even though that could mean quite a bit of work.
How many different formats are we talking about? Do any of them conflict? It seems like you could just gsub like so: input_string.gsub(/\bJA\b/i, 'January'). Is this part of an import routine, or are the users going to be typing in dates in different formats?
There's a related question here: Parse Italian Date with Ruby