Permalink
Browse files

initial implementation of a Pluralization module

  • Loading branch information...
1 parent 98bd63c commit 9ca4c9ed52d4706566a6abeb2d78722dcc5d4764 Sven Fuchs committed Jul 14, 2009
@@ -0,0 +1,28 @@
+module I18n
+ module Backend
+ module Pluralization
+ def pluralize(locale, entry, count)
+ return entry unless entry.is_a?(Hash) and count
+
+ pluralizer = pluralizer(locale)
+ if pluralizer.respond_to?(:call)
+ key = count == 0 && entry.has_key?(:zero) ? :zero : pluralizer.call(count)
+ raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
+ entry[key]
+ else
+ super
+ end
+ end
+
+ protected
+
+ def pluralizers
+ @pluralizers ||= {}
+ end
+
+ def pluralizer(locale)
+ pluralizers[locale] ||= lookup(locale, :"i18n.pluralize")
+ end
+ end
+ end
+end
@@ -0,0 +1,72 @@
+require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
+require 'i18n/backend/pluralization'
+
+module PluralizationSetup
+ def setup
+ super
+ class << I18n.backend
+ include I18n::Backend::Pluralization
+ end
+ I18n.load_path << locales_dir + '/plurals.rb'
+ end
+end
+
+class I18nPluralizationBackendApiBasicsTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Api::Basics
+end
+
+class I18nPluralizationBackendApiTranslateTest < Test::Unit::TestCase
+ include Tests::Backend::Simple::Setup::Base
+ include PluralizationSetup
+ include Tests::Backend::Api::Translation
+end
+
+class I18nPluralizationBackendApiInterpolateTest < Test::Unit::TestCase
+ include Tests::Backend::Simple::Setup::Base
+ include PluralizationSetup
+ include Tests::Backend::Api::Interpolation
+end
+
+class I18nPluralizationBackendApiLambdaTest < Test::Unit::TestCase
+ include Tests::Backend::Simple::Setup::Base
+ include PluralizationSetup
+ include Tests::Backend::Api::Lambda
+end
+
+class I18nPluralizationBackendApiTranslateLinkedTest < Test::Unit::TestCase
+ include Tests::Backend::Simple::Setup::Base
+ include PluralizationSetup
+ include Tests::Backend::Api::Link
+end
+
+class I18nPluralizationBackendApiPluralizeTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Simple::Setup::Base
+ include Tests::Backend::Api::Pluralization
+end
+
+class I18nPluralizationBackendApiLocalizeDateTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Simple::Setup::Localization
+ include Tests::Backend::Api::Localization::Date
+end
+
+class I18nPluralizationBackendApiLocalizeDateTimeTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Simple::Setup::Localization
+ include Tests::Backend::Api::Localization::DateTime
+end
+
+class I18nPluralizationBackendApiLocalizeTimeTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Simple::Setup::Localization
+ include Tests::Backend::Api::Localization::Time
+end
+
+class I18nPluralizationBackendApiLocalizeLambdaTest < Test::Unit::TestCase
+ include PluralizationSetup
+ include Tests::Backend::Simple::Setup::Localization
+ include Tests::Backend::Api::Localization::Lambda
+end
+
@@ -0,0 +1,39 @@
+require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
+require 'i18n/backend/pluralization'
+
+class I18nPluralizationBackendTest < Test::Unit::TestCase
+ def setup
+ I18n.backend = I18n::Backend::Simple.new
+ class << I18n.backend
+ include I18n::Backend::Pluralization
+ end
+ @pluralizer = lambda { |n| n == 1 ? :one : n == 0 || (2..10).include?(n % 100) ? :few : (11..19).include?(n % 100) ? :many : :other }
+ backend_store_translations(:foo, :i18n => { :pluralize => @pluralizer })
+ @entry = { :zero => 'zero', :one => 'one', :few => 'few', :many => 'many', :other => 'other' }
+ end
+
+ define_method :"test: pluralization picks a pluralizer from :'i18n.pluralize'" do
+ assert_equal @pluralizer, I18n.backend.send(:pluralizer, :foo)
+ end
+
+ define_method :"test: pluralization picks :one for 1" do
+ assert_equal 'one', I18n.t(:count => 1, :default => @entry, :locale => :foo)
+ end
+
+ define_method :"test: pluralization picks :few for 2" do
+ assert_equal 'few', I18n.t(:count => 2, :default => @entry, :locale => :foo)
+ end
+
+ define_method :"test: pluralization picks :many for 11" do
+ assert_equal 'many', I18n.t(:count => 11, :default => @entry, :locale => :foo)
+ end
+
+ define_method :"test: pluralization picks zero for 0 if the key is contained in the data" do
+ assert_equal 'zero', I18n.t(:count => 0, :default => @entry, :locale => :foo)
+ end
+
+ define_method :"test: pluralization picks few for 0 if the key is not contained in the data" do
+ @entry.delete(:zero)
+ assert_equal 'few', I18n.t(:count => 0, :default => @entry, :locale => :foo)
+ end
+end
@@ -0,0 +1,110 @@
+{
+ :af => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :am => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :ar => { :i18n => { :pluralize => lambda { |n| n == 0 ? :zero : n == 1 ? :one : n == 2 ? :two : (3..10).include?(n % 100) ? :few : (11..99).include?(n % 100) ? :many : :other } } },
+ :az => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :be => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :bg => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :bh => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :bn => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :bo => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :bs => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :ca => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :cs => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : (2..4).include?(n) ? :few : :other } } },
+ :cy => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : n == 8 || n == 11 ? :many : :other } } },
+ :da => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :de => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :dz => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :el => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :en => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :eo => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :es => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :et => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :eu => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :fa => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :fi => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :fil => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :fo => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :fr => { :i18n => { :pluralize => lambda { |n| n && n != 2 ? :one : :other } } },
+ :fur => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :fy => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ga => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :gl => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :gu => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :guw => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :ha => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :he => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :hi => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :hr => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :hu => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :id => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :is => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :it => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :iw => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ja => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :jv => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :ka => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :km => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :kn => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :ko => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :ku => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :lb => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ln => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :lt => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && !(11..19).include?(n % 100) ? :one : (2..9).include?(n % 10) && !(11..19).include?(n % 100) ? :few : :other } } },
+ :lv => { :i18n => { :pluralize => lambda { |n| n == 0 ? :zero : n % 10 == 1 && n % 100 != 11 ? :one : :other } } },
+ :mg => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :mk => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 ? :one : :other } } },
+ :ml => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :mn => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :mo => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 0 ? :few : :other } } },
+ :mr => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ms => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :mt => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 0 || (2..10).include?(n % 100) ? :few : (11..19).include?(n % 100) ? :many : :other } } },
+ :my => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :nah => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :nb => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ne => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :nl => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :nn => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :no => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :nso => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :om => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :or => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :pa => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :pap => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :pl => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) && !(22..24).include?(n % 100) ? :few : :other } } },
+ :ps => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :pt => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :"pt-PT" => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
@jamesarosen

jamesarosen Jan 19, 2012

@svenfuchs can you point to where in the CLDR they distinguish between :pt and :"pt-PT"? I'm not doubting the validity of this rule; I'm just trying to understand where it came from. I'm asking because I want to do a JS port of this logic and I want to get my sources right. I don't see the distinction in the Language Plural Rules table.

@svenfuchs

svenfuchs Jan 19, 2012

Owner

@jamesarosen I actually don't remember where i got this from. I might have copied this file from somewhere else where a portuguese speaking person added this. The cldr table that you link specifies 0 as "other" for portuguese, so i would guess that maybe for portuguese as spoken in brazil etc it's different? I am sorry i can't give you a better answer :(

@jamesarosen

jamesarosen Jan 19, 2012

That's OK. I'll use the official CLDR source for now. If someone from Portugal chimes in on this topic I'm happy to change it. (They should also submit a bug to CLDR.) Thanks for the quick response :)

+ :ro => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 0 ? :few : :other } } },
+ :ru => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :se => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :sh => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :sk => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : (2..4).include?(n) ? :few : :other } } },
+ :sl => { :i18n => { :pluralize => lambda { |n| n % 100 == 1 ? :one : n % 100 == 2 ? :two : (3..4).include?(n % 100) ? :few : :other } } },
+ :sma => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :smi => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :smj => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :smn => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :sms => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } },
+ :so => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :sq => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :sr => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :sv => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :sw => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :ta => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :te => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :th => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :ti => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :tk => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :tl => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :to => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :tr => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :uk => { :i18n => { :pluralize => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : (2..4).include?(n % 10) && !(12..14).include?(n % 100) ? :few : n % 10 == 0 || (5..9).include?(n % 10) || (11..14).include?(n % 100) ? :many : :other } } },
+ :ur => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } },
+ :vi => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :wa => { :i18n => { :pluralize => lambda { |n| (0..1).include?(n) ? :one : :other } } },
+ :yo => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :zh => { :i18n => { :pluralize => lambda { |n| :other } } },
+ :zu => { :i18n => { :pluralize => lambda { |n| n == 1 ? :one : :other } } }
+}

0 comments on commit 9ca4c9e

Please sign in to comment.