How to pluralize "There is/are N object/objects"?
Asked Answered
U

4

22

Pluralizing a single word is simple:

pluralize(@total_users, "user")

But what if I want to print "There is/are N user/users":

There are 0 users
There is 1 user
There are 2 users

, i.e., how to pluralize a sentence?

Uneasy answered 9/1, 2012 at 14:40 Comment(0)
D
34

You can add a custom inflection for it. By default, Rails will add an inflections.rb to config/initializers. There you can add:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular "is", "are"
end

You will then be able to use pluralize(@total_users, "is") to return is/are using the same rules as user/users.

EDIT: You clarified the question on how to pluralize a sentence. This is much more difficult to do generically, but if you want to do it, you'll have to dive into NLP.

As the comment suggests, you could do something with I18n if you just want to do it with a few sentences, you could build something like this:

  def pluralize_sentence(count, i18n_id, plural_i18n_id = nil)
    if count == 1
      I18n.t(i18n_id, :count => count)
    else
      I18n.t(plural_i18n_id || (i18n_id + "_plural"), :count => count)
    end
  end

  pluralize_sentence(@total_users, "user_count")

And in config/locales/en.yml:

  en:
    user_count: "There is %{count} user."
    user_count_plural: "There are %{count} users."
Dumbhead answered 9/1, 2012 at 15:1 Comment(3)
Actually, i think the question is more about how to interpolate the number of users, i.e. something which might look like a mix between i18n and pluralisation e.g. pluralize(@total_users, "there is $1 user")... which will obviously miserably fail :)Mollusc
In Agile Development with Rails, Fourth Edition, page 217, they use one and other in the YAML file to pluralize error messages. This is used without any extra code to display the page errors, so it should work directly with t().Uneasy
One problem I hit with this solution is if you have a model that ends in 'are' (in my case ExtendedCare) all your code breaksHereby
D
8

This is probably best covered by the Rails i18n pluralization features. Adapted from http://guides.rubyonrails.org/i18n.html#pluralization

I18n.backend.store_translations :en, :user_msg => {
  :one => 'There is 1 user',
  :other => 'There are %{count} users'
}
I18n.translate :user_msg, :count => 2
# => 'There are 2 users'
Deport answered 14/4, 2013 at 2:19 Comment(0)
B
5

I think the first part of Martin Gordon's answer is pretty good.

Alternatively, it's kind of messy but you can always just write the logic yourself:

"There #{@users.size == 1 ? 'is' : 'are'} #{@users.size} user#{'s' unless @users.size == 1}."
Bib answered 9/1, 2012 at 16:43 Comment(0)
C
0

UPDATE to code: I no longer use the inflections route as stated in @Martin Gordon's answer. For some reason it would cause other non-related functions to error. I did extensive tests to confirm, though could not track down a reason why. So, below is now what I use and it works.

There are many ways to do this. This is how I did it using Rails 6.0.3.4 and Ruby 2.7.1.

I wanted to pluralize this sentence:

  • Singular: There is 1 private group
  • Plural: There are 2 private groups

What I did is I went to application_helper.rb and added this code:

def pluralize_private_statement(list, word)
  num_in_list = list.count
  is_or_are = num_in_list == 1 ? 'is' : 'are'
  return "There " + is_or_are + " " + num_in_list.to_s + " private " + word.pluralize(num_in_list)
end

Now, all I have to use in my view is:

<%= pluralize_private_statement(private_groups, "group") %>
# private_groups = 2
# -> There are 2 private groups

What the code in application_helper.rb does is first create a variable for the number of items in the list passed and store it in num_in_list. Then it creates a second varible checking if the num_in_list is equal to 1 and if so returns 'is' otherwise it returns 'are'. Then, it returns the sentence that is constructed with the information obtained.

The first part of the sentence is a simple string, then the is_or_are variable which holds either 'is' or 'are' as explained above. Then it adds a space with the number of list items, converted from an integer to a string, followed by the 'private' word. Then it adds the pluralization of the word passed to the initial function; but, only returns the singular/plural word without a number attached as pluralize(@total_users, "is") would do.

Here is how you could use it for your specific question.

First, add this to your application_helper.rb file:

def pluralize_sentence(list, word)
  num_in_list = list.count
  is_or_are = num_in_list == 1 ? 'is' : 'are'
  return "There " + is_or_are + " " + num_in_list.to_s + " " + word.pluralize(num_in_list)
end

Lastly, you can use this code wherever you wish to have the pluralized sentence:

<%= pluralize_sentence(@total_users, "user") %>

Happy Coding!

Cangue answered 18/12, 2020 at 20:29 Comment(1)
Instead, try this: is_or_are = num_in_list != 1 ? 'are' : 'is' and then you will also get the correct behavior for the zero case, i.e. There are 0 usersFriction

© 2022 - 2024 — McMap. All rights reserved.