Ryenski
Ryenski

Reputation: 9692

Rails i18n pluralization: Infinity

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: 0

Views: 800

Answers (1)

Simple Lime
Simple Lime

Reputation: 11035

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"

What is this doing?

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: 2

Related Questions