Reputation: 1276
Is there a way to nest translation lookups? Something like this:
en:
uh_oh: 'Uh Oh!'
error1: :'uh_oh' + ' There was a big error!'
error2: :'uh_oh' + ' There was another big error!'
I18n.t('error1') #=> 'Uh Oh! There was a big error!'
I18n.t('error2') #=> 'Uh Oh! There was another big error!'
I've tried a bunch of variations of this, and also tried it using a Ruby translation file instead of YAML. Note that this does work:
en:
uh_oh: 'Uh Oh!'
error1: :'uh_oh'
I18n.t('error1') #=> 'Uh Oh!'
But if I add additional text to error1
, uh_oh
doesn't get translated.
Basically I want to avoid having to always pass in common terms, like this:
en:
uh_oh: 'Uh Oh!'
error1: '%{uh_oh} There was a big error!'
I18n.t('error1', {uh_oh: I18n.t('uh_oh')})
For common terms like uh_oh
, the interpolation is the same for every call to error1
(and any other key that uses uh_oh
), so it doesn't really make sense to have to pass in a string to be interpolated. It'd be easier to do the following instead and have the error1
translation take care of the common key translation:
I18n.t('error1')
Upvotes: 6
Views: 4273
Reputation: 1286
I'm not going to answer your question (I don't think it's possible with the i18n gem but could be wrong). I am going to say that you shouldn't take this approach and give you link [1] as background. As developers it's natural to see patterns and extract common code to keep things DRY. This is a step too far when dealing with multiple languages as it prevents proper translations. Not all languages follow the same sentence structure as english and what you're substituting in may have to change to agree with the rest of the sentence.
On a site I work on we have this problem with French. We have sentences that include a location name and this is straightforward in English. "%{location_name} property" works whatever the location name is. In French however, you need different structures depending on whether the location is a town, a province, a region, and whether the name starts with a vowel or not.
[1] http://www.multilingual.com/articleDetail.php?id=594
Upvotes: 6
Reputation: 3205
The reason you can do the "I18n.t('error1')" substitution by itself because that's a special case that the I18n calls a "symlink".
It won't do anything further than a single, full substitution, unfortunately.
I see two solutions to solving this problem. The first was to post-process the output of I18n, which might be difficult when you don't have full control over when I18n is called and the consumption of the translated messages might be spread out (such as in Rails). The best bet would be probably to override the I18n.t function.
Another option is to take advantage of the ability to store a lambda in the I18n backend. Unfortunately this means that you can't store the combined translation in the YAML file, since it only supports basic strings.
As an example, in the translation YAML we could have any of the error messages:
en:
error: "There was a big error [%{arg}]!"
And now we want to call it with the translation of uh_oh before it. We need to store the combination translation with uh_oh into the I18n backend:
translam = lambda { |key,opts| "Uh Oh! #{I18n.t(opts[:for],opts)}" }
I18n.backend.store_translations(:en,:uh_oh => translam)
Now we can translate "uh_oh" and give it the error we want to translate plus any arguments it may need:
I18n.t(:uh_oh, for: :error, arg: 42)) #=> 'Uh Oh! There was a big error [42]!'
Upvotes: 0