ruby-on-railsinternationalizationrails-i18n

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"?


Solution

  • 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