0

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

Ryenski
  • 9,582
  • 3
  • 43
  • 47
  • 1
    You need to use quotes when providing strings for interpolation `other: "%{count} Forms"`. In YAML `%` is (rarely) used to give special directives to the interpreter. http://www.yaml.org/refcard.html – max Jul 12 '17 at 18:27
  • Thanks, good catch. That's what was causing the exception. I rephrased the question; I still want to interpolate "Unlimited" in place of "Infinity". – Ryenski Jul 12 '17 at 18:48

1 Answers1

2

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

Simple Lime
  • 10,790
  • 2
  • 17
  • 32
  • 1
    Edited. `finite?` is defined by `Float` so calling `finite?` on a Fixnum causes a `NoMethodError`. – max Jul 12 '17 at 19:02
  • Perfect, exactly what i was looking for. One thing I'm confused about - why is `config/locales/plural.rb` a hash, and what is picking that up? Also how did you figure this out? I read through the source at https://github.com/svenfuchs/rails-i18n and was looking at this all wrong. – Ryenski Jul 12 '17 at 19:05
  • 1
    @mysmallidea I picked it up from [this post](https://stackoverflow.com/questions/6166064/i18n-pluralization) since it's from 2011 and I was unsure if it would still work I throw together an example of what you were wanting in my test app and it still seems to work. I'm still trying to work through the 'how' of it all and why that hash myself, I'll update my answer if I get anywhere in finding anything out – Simple Lime Jul 12 '17 at 19:09
  • 1
    @max it appears you're correct, I'm in ruby 2.4 which doesn't have Fixnum anymore (and Numeric has finite? so when I tested an integer everything worked), I'll update the answer – Simple Lime Jul 12 '17 at 19:10
  • Ah, I tested it on 2.3.1 which explains why I got an error. – max Jul 12 '17 at 19:25
  • @mysmallidea think I've got it figured out, actually pretty simple really. I was thinking it was some rails configuration magic (thus I was looking in ActiveSupport for all of this), but it's just part of the normal i18n gem – Simple Lime Jul 12 '17 at 19:37