Reputation: 9702
My app's pricing plan has some features that are unlimited. For example in the "Pro" version you get 10 forms, and in the "Unlimited" version you get unlimited forms.
This is represented in the Plan model by an integer or Float::Infinity.
pro = Plan.find_by name: 'Pro'
pro.forms_limit
#=> 10
unl = Plan.find_by name: 'Unlimited'
unl.forms_limit
#=> Float::INFINITY
In the view:
= t('.forms', count: plan.forms_limit)
I am trying to find an efficient way to interpolate this with I18n. What I'd like to do is:
plans:
index:
forms:
zero: No Forms
one: 1 Form
other: "%{count} Forms"
infinity: Unlimited Forms
This will work, but it results in undesired output like:
"Infinity Forms"
Is there a way to structure this so that Infinity will interpolate "Unlimited" instead of "Infinity"?
Upvotes: 1
Views: 811
Reputation: 2154
Define a custom I18n Backend in config/locales/locale.rb
module I18n
module Backend
module PluralizeInfinite
def pluralize(local, entry, count)
return super unless entry.is_a?(Hash) && entry.has_key?(:infinity)
return super unless count&.infinite?
entry[:infinity]
end
end
end
end
I18n::Backend::Simple.send(:include, I18n::Backend::PluralizeInfinite)
This takes the same approach as I18n::Backend::Pluralization
which is a Unicode CLDR backend.
Be sure to have tests that cover this behaviour if using this approach, as the I18n::Backend::Base#pluralize
interface could change in future versions of Rails.
Upvotes: 0
Reputation: 11090
Create a file config/locales/plurals.rb
with the following
{
en: {
i18n: {
plural: {
keys: [:one, :other, :infinity],
rule: lambda do |n|
if n == 1
:one
elsif n == Float::INFINITY
:infinity
else
:other
end
end
}
}
}
}
and then in my config/locales/en.yml
, I have
en:
forms:
zero: 'No Forms'
one: '1 Form'
other: '%{count} Forms'
infinity: 'Unlimited Forms'
added in config/initializers/locale.rb
I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
and testing it in IRB
I18n.t(:forms, count: 0)
# => "No Forms"
I18n.t(:forms, count: 1)
# => "1 Form"
I18n.t(:forms, count: 10)
# => "10 Forms"
I18n.t(:forms, count: Float::INFINITY)
# => "Unlimited Forms"
This isn't nearly as mysterious as I thought when. I first tried it (getting the idea from this related question.
When you include I18n::Backend::Pluralization it's going to start looking for a key i18n.plural.rule
that should respond to call, anywhere in the load path. So the plurals.rb
file name is unimportant, just need to make sure it's a file in I18n.load_path
.
We make that file a ruby file with a hash so that we can set that i18n.plural.rule
key to a lambda (so it responds to call
) and then the lambda gets called with the count getting passed in. As pointed out there are
Upvotes: 3