I18n to call different Model Attribute depending on Locale? - ruby-on-rails

So I am building an on-line shop and I want two language options, English and Spanish.
I am using I18n as you would normally do for all my static text and headings ect.
But, I have a products Model that can have new Products created for listing on the site. This has fields like :name_en and :name_es, :description_en and :description_es ect.
When the admin uploads a new product they obviously need to add the English and the Spanish text.
Because I have only 2 locales what I would like to do i think is call something like
<%= Product.name_"#{I18n.locale.downcase}" %>
But obviously this does not work. How can i, or just can I, interpolate a method or Attribute?
Have I missed something obvious here and just going about it the wrong way or is there a way to do this along the lines of my thinking?
Any Help massively appreciated.
Thanks

You can use send method. Try something like:
<%= Product.send("name_#{I18n.locale.downcase}") %>
Just a word of explanation, the following are equal:
string = "Hello"
string.upcase
# => "HELLO"
string.send("upcase")
# => "HELLO"
Hope that puts you in proper direction!
Good luck!

Related

what is the best way to get a portion of this url

I am creating like a link like so:
<%= link_to('', "#{issueable}/#{order.id}/issues" %>
which creates a link like this:
root/version2/parts/2418/issues
I want to be able to get the "parts" (/version2/parts/2418/issues) portion of that url when the user clicks the link to that controller method.
You can use split:
link = "root/version2/parts/2418/issues"
puts link.split('/')[2].strip
#outputs parts
link = "version2/parts/2418"
puts link.split('/')[1].strip
#outputs parts
Ruby fiddle
In other words, you've got a string "/version2/parts/2418/issues" and you want to extract the 'parts' position from it.
"/version2/parts/2418/issues".split('/')[-3]
You'll need to figure out yourself whether to get [2] from the split array or [-3]. As an added '/' in the beginning or in the end could mess it up.
You could use regex assuming you know that it starts with "version2" and also know the order_id when it gets to it.
"/version2/parts/2418/issues".match(/\/version2\/(\w+)\/2418/)
puts $1

Select tag & options for select 101

Can someone explain me how this exactly works ?
Problem:
I have a Scaffold and run the migration:
rails g migration AddRarityToTags rarity:string
For the rarity input i need a dropdown displaying a list of options to select from.
e.g. Rarity = Free
Common
Rare
Epic
If i'm right i need something like this:
select_tag :rarity, options_for_select(#rarity)
I searched a lot but it didn't helped much, i got more confused.
Can someone help me out ?
Imagine putting the raw options into the tag as a string:
select_tag :rarity, '<option>Free</option><option>Common</option>...'
That's what options_for_select returns, if you pass in an array:
select_tag :rarity, options_for_select(['Free', 'Common', ...])
See: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select
To enforce the "dumb views" rule, and to let others use that array, you can move it to the model:
class Tag < ActiveRecord::Base
RARITY_LEVELS = %w(Free Common Rare Epic)
end
...
select_tag :rarity, options_for_select(Tag::RARITY_LEVELS)
Both me and the OP would like to know if Rails, or any gems, let us get any DRYer than this; if, for example, Rails lets us attach the RARITY_LEVELS directly to the rarity field...

rails i18n adjectives

I'm currently stuck with a small but not so uncommon problem in rails i18n ( hopefully I just haven't used the wrong search terms...)
In a standard rails crud app, you often have models like "contract", "group" etc..
So far, if you want a button for "new group" oder "new contract", this is simple in the english language, since it's basically always something like "new" + model_name.
Unfortunately, languages like german are not so computer-friendly :)
"new contract" translates to "neuer vertrag" while "new group" translates to "neue gruppe" (note the adjective change).
So, no problem with pluralisation this time but with adjective changes.
Is there any rails i18n support for such cases?
Don't want to use ugly i18n concatenation :)
thanks a lot!
just to understand your question correctly, you don't want to translate 'new' to german?
What is wrong with:
en:
new_contract: New contract
new_group: New group
de:
new_contract: Neuer Vertrag
new_group: Neue Gruppe
This is the standard way to do it and I don't see any advantage of DRYing up the 'new'. You remove something from the context there. Btw. you have this problem in a lot of languages. It is not possible to translate an adjective just once and then reuse, since it belongs to another word (cannot stand in its own context).
I would definitely go with the approach above.

Localizing a text field containing a number in Ruby on Rails

I am currently working on a project to internationalize one of our ruby-on-rails web applications so that it can be used in other countries (France will be the first one in this case).
A particular issue I haven't worked out yet is with the displaying of numeric fields. When displaying numbers for display purposes only, I do the following:
<%= number_to_percentage(tax.rate, :precision => 2)%>
In English, this shows 17.50, but in French it shows 17,50 (with a comma in place of the decimal point) which is as expected. The problem comes in the Edit form, when I show a text field
<%= f.text_field :rate, :size => 15 %>
When this renders a text box on the screen, the text box always shows 17.50 with a full stop rather than a comma for French. I am not sure that is correct.
When I tried doing the following:
<%= f.text_field :rate, :size => 15, :value => number_with_precision(f.object.rate, :precision => 2) %>
This did indeed show 17,50 in the text box for French, but when I click on the Update button to save the form, the Ruby validation kicks in and tells me that 17,50 is not a number (or rather it says "n'est pas un nombre"). I have to enter 17.50 to get it to save.
To be honest, I am not entirely sure on the correct thing to do here. Should all countries enter numbers with full stops in text boxes, or is there a way to get Ruby-on-Rails to display commas, and validate them appropriately?
TL;DR
This is the kind of things I hate to do over and over again (I'm serving french users, they're easily confused with dots as the decimal separator).
I exclusively use the delocalize gem now, which does the format translation automatically for you. You just have to install the gem and leave your forms as-is, everything should be taken care of for you.
I like to read, give me the long explanation
The basic conversion is quite simple, you have to convert back and forth between the following formats:
The backend one, which is usually English, used by your persistent storage (SQL database, NoSQL store, YAML, flat text file, whatever struck your fancy, ...).
The frontend one, which is whatever format your user prefers. I'm going to use French here to stick to the question*.
* also because I'm quite partial towards it ;-)
This means that you have two points where you need to do a conversion:
Outbound: when outputting your HTML, you will need to convert from English to French.
Inbound: When processing the result of the form POST, you will need to convert back from French to English.
The manual way
Let's say I have the following model, with the rate field as a decimal number with a precision of 2 (eg. 19.60):
class Tax < ActiveRecord::Base
# the attr_accessor isn't really necessary here, I just want to show that there's a database field
attr_accessor :rate
end
The outbound conversion step (English => French) can be done by overriding text_field_tag:
ActionView::Helpers::FormTagHelper.class_eval do
include ActionView::Helpers::NumberHelper
alias original_text_field_tag text_field_tag
def text_field_tag(name, value = nil, options = {})
value = options.delete(:value) if options.key?(:value)
if value.is_a?(Numeric)
value = number_with_delimiter(value) # this method uses the current locale to format our value
end
original_text_field_tag(name, value, options)
end
end
The inbound conversion step (French => English) will be handled in the model. We will override the rate attribute writer to replace every French separator with the English one:
class Tax < ActiveRecord::Base
def rate=(rate)
write_attribute(:rate, rate.gsub(I18n.t('number.format.separator'), '.')
end
end
This look nice because there's only one attribute in the example and one type of data to parse, but imagine having to do this for every number, date or time field in your model. That's not my idea of fun.
This also is a naïve* way of doing the conversions, it does not handle:
Dates
Times
Delimiters (eg. 100,000.84)
* did I already tell you I like French?
Enter delocalize
Delocalize is working on the same principle I outlined above, but does the job much more comprehensively:
It handles Date, Time, DateTime and numbers.
You don't have to do anything, just install the gem. It checks your ActiveRecord columns to determine if it's a type that needs conversion and does it automatically.
The number conversions are pretty straightforward, but the date ones are really interesting. When parsing the result of a form, it will try the date formats defined in your locale file in descending order and should be able to understand a date formatted like this: 15 janvier 2012.
Every outbound conversion will be done automatically.
It's tested.
It's active.
One caveat though: it doesn't handle client-side validations. If you're using them, you will have to figure out how to use i18n in your favourite JavaScript framework.
This is the gsub technique :
In your model :
before_validation :prepare_number
def prepare_number
self.rate.gsub(/,/, '.') if self.rate.match /,\S/
end

translate database fields with rails

I know about the built-in I18n in Rails, but how can I select a database field per locale?
My model structure is something like this:
title #default (englisch)
title_de #(german)
title_it #(italian)
In my template I want to be able to write only
<%= #model.title %>
and should get the value in the right language.
Is there a plugin or a solution to use different fields per different locale settings with a structure like mine?
Although your db architecture (different locales hardcoded as table columns) seems wrong to me, I think you can achieve what you want by adding a pseudo-field to your model, something along:
# example not tested
class MyModel < ActiveRecord::Base
def localized_title(locale)
locale = locale == 'en' ? '' : '_' + locale
read_attribute("title#{locale}".to_sym")
end
end
Or, provided that you somehow make your current locale visible to your models, you can similarly overwrite the default title accessor method.
Edit: You can take a look at http://github.com/iain/translatable_columns, it seems pretty much compatible with your architecture....
Try using:
http://github.com/joshmh/globalize2
It may require renaming your columns (to a different standard).
Nowadays the best way to translate active record models fields is using https://github.com/shioyama/mobility

Resources