@@ -16,40 +16,81 @@ module Backend
1616 module Pluralization
1717 # Overwrites the Base backend translate method so that it will check the
1818 # translation meta data space (:i18n) for a locale specific pluralization
19- # rule and use it to pluralize the given entry. I.e. the library expects
19+ # rule and use it to pluralize the given entry. I.e., the library expects
2020 # pluralization rules to be stored at I18n.t(:'i18n.plural.rule')
2121 #
2222 # Pluralization rules are expected to respond to #call(count) and
23- # return a pluralization key. Valid keys depend on the translation data
24- # hash (entry) but it is generally recommended to follow CLDR's style,
25- # i.e., return one of the keys :zero, :one, :few, :many, :other.
23+ # return a pluralization key. Valid keys depend on the pluralization
24+ # rules for the locale, as defined in the CLDR.
25+ # As of v41, 6 locale-specific plural categories are defined:
26+ # :few, :many, :one, :other, :two, :zero
2627 #
27- # The :zero key is always picked directly when count equals 0 AND the
28- # translation data has the key :zero. This way translators are free to
29- # either pick a special :zero translation even for languages where the
30- # pluralizer does not return a :zero key.
28+ # n.b., The :one plural category does not imply the number 1.
29+ # Instead, :one is a category for any number that behaves like 1 in
30+ # that locale. For example, in some locales, :one is used for numbers
31+ # that end in "1" (like 1, 21, 151) but that don't end in
32+ # 11 (like 11, 111, 10311).
33+ # Similar notes apply to the :two, and :zero plural categories.
34+ #
35+ # If you want to have different strings for the categories of count == 0
36+ # (e.g. "I don't have any cars") or count == 1 (e.g. "I have a single car")
37+ # use the explicit `"0"` and `"1"` keys.
38+ # https://unicode-org.github.io/cldr/ldml/tr35-numbers.html#Explicit_0_1_rules
3139 def pluralize ( locale , entry , count )
3240 return entry unless entry . is_a? ( Hash ) && count
3341
3442 pluralizer = pluralizer ( locale )
3543 if pluralizer . respond_to? ( :call )
36- key = count == 0 && entry . has_key? ( :zero ) ? :zero : pluralizer . call ( count )
37- raise InvalidPluralizationData . new ( entry , count , key ) unless entry . has_key? ( key )
38- entry [ key ]
44+ # Deprecation: The use of the `zero` key in this way is incorrect.
45+ # Users that want a different string for the case of `count == 0` should use the explicit "0" key instead.
46+ # We keep this incorrect behaviour for now for backwards compatibility until we can remove it.
47+ # Ref: https://github.com/ruby-i18n/i18n/issues/629
48+ return entry [ :zero ] if count == 0 && entry . has_key? ( :zero )
49+
50+ # "0" and "1" are special cases
51+ # https://unicode-org.github.io/cldr/ldml/tr35-numbers.html#Explicit_0_1_rules
52+ if count == 0 || count == 1
53+ value = entry [ symbolic_count ( count ) ]
54+ return value if value
55+ end
56+
57+ # Lateral Inheritance of "count" attribute (http://www.unicode.org/reports/tr35/#Lateral_Inheritance):
58+ # > If there is no value for a path, and that path has a [@count="x"] attribute and value, then:
59+ # > 1. If "x" is numeric, the path falls back to the path with [@count=«the plural rules category for x for that locale»], within that the same locale.
60+ # > 2. If "x" is anything but "other", it falls back to a path [@count="other"], within that the same locale.
61+ # > 3. If "x" is "other", it falls back to the path that is completely missing the count item, within that the same locale.
62+ # Note: We don't yet implement #3 above, since we haven't decided how lateral inheritance attributes should be represented.
63+ plural_rule_category = pluralizer . call ( count )
64+
65+ value = if entry . has_key? ( plural_rule_category ) || entry . has_key? ( :other )
66+ entry [ plural_rule_category ] || entry [ :other ]
67+ else
68+ raise InvalidPluralizationData . new ( entry , count , plural_rule_category )
69+ end
3970 else
4071 super
4172 end
4273 end
4374
4475 protected
4576
46- def pluralizers
47- @pluralizers ||= { }
48- end
77+ def pluralizers
78+ @pluralizers ||= { }
79+ end
4980
50- def pluralizer ( locale )
51- pluralizers [ locale ] ||= I18n . t ( :'i18n.plural.rule' , :locale => locale , :resolve => false )
52- end
81+ def pluralizer ( locale )
82+ pluralizers [ locale ] ||= I18n . t ( :'i18n.plural.rule' , :locale => locale , :resolve => false )
83+ end
84+
85+ private
86+
87+ # Normalizes categories of 0.0 and 1.0
88+ # and returns the symbolic version
89+ def symbolic_count ( count )
90+ count = 0 if count == 0
91+ count = 1 if count == 1
92+ count . to_s . to_sym
93+ end
5394 end
5495 end
5596end
0 commit comments