@@ -16,40 +16,75 @@ module Backend
16
16
module Pluralization
17
17
# Overwrites the Base backend translate method so that it will check the
18
18
# 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
20
20
# pluralization rules to be stored at I18n.t(:'i18n.plural.rule')
21
21
#
22
22
# 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
26
27
#
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
31
39
def pluralize ( locale , entry , count )
32
40
return entry unless entry . is_a? ( Hash ) && count
33
41
34
42
pluralizer = pluralizer ( locale )
35
43
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
+ # "0" and "1" are special cases
45
+ # https://unicode-org.github.io/cldr/ldml/tr35-numbers.html#Explicit_0_1_rules
46
+ if count == 0 || count == 1
47
+ value = entry [ symbolic_count ( count ) ]
48
+ return value if value
49
+ end
50
+
51
+ # Lateral Inheritance of "count" attribute (http://www.unicode.org/reports/tr35/#Lateral_Inheritance):
52
+ # > If there is no value for a path, and that path has a [@count="x"] attribute and value, then:
53
+ # > 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.
54
+ # > 2. If "x" is anything but "other", it falls back to a path [@count="other"], within that the same locale.
55
+ # > 3. If "x" is "other", it falls back to the path that is completely missing the count item, within that the same locale.
56
+ # Note: We don't yet implement #3 above, since we haven't decided how lateral inheritance attributes should be represented.
57
+ plural_rule_category = pluralizer . call ( count )
58
+
59
+ value = if entry . has_key? ( plural_rule_category ) || entry . has_key? ( :other )
60
+ entry [ plural_rule_category ] || entry [ :other ]
61
+ else
62
+ raise InvalidPluralizationData . new ( entry , count , plural_rule_category )
63
+ end
39
64
else
40
65
super
41
66
end
42
67
end
43
68
44
69
protected
45
70
46
- def pluralizers
47
- @pluralizers ||= { }
48
- end
71
+ def pluralizers
72
+ @pluralizers ||= { }
73
+ end
49
74
50
- def pluralizer ( locale )
51
- pluralizers [ locale ] ||= I18n . t ( :'i18n.plural.rule' , :locale => locale , :resolve => false )
52
- end
75
+ def pluralizer ( locale )
76
+ pluralizers [ locale ] ||= I18n . t ( :'i18n.plural.rule' , :locale => locale , :resolve => false )
77
+ end
78
+
79
+ private
80
+
81
+ # Normalizes categories of 0.0 and 1.0
82
+ # and returns the symbolic version
83
+ def symbolic_count ( count )
84
+ count = 0 if count == 0
85
+ count = 1 if count == 1
86
+ count . to_s . to_sym
87
+ end
53
88
end
54
89
end
55
90
end
0 commit comments