Module: Air18n::SmartCount
- Defined in:
- lib/air18n/smart_count.rb
Constant Summary collapse
- INTERPOLATION_VARIABLE_NAME =
Option to translate() that holds number which controls which plural form is used.
:smart_count
- DELIMITER =
Delimiter between forms of translation.
This delimiter must be unique and rare because we assume that any phrase that includes it uses smart counting.
'||||'
- PLURAL_TYPES =
{ :chinese_like => { :num_forms => 1, :doc => nil, :rule => lambda { |n| 0 } }, :german_like => { :num_forms => 2, :doc => ['When count is 1', 'Everything else (0, 2, 3, ...)'], :rule => lambda { |n| n != 1 ? 1 : 0 } }, :french_like => { :num_forms => 2, :doc => ['When count is 0 or 1', 'Everything else (2, 3, 4, ...)'], :rule => lambda { |n| n > 1 ? 1 : 0 } }, :russian_like => { :num_forms => 3, :doc => ['When count ends in 1, excluding 11 (1, 21, 31, ...)', 'When count ends in 2-4, excluding 12-14 (2, 3, 4, 22, ...)', 'Everything else (0, 5, 6, ...)'], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2 } }, :czech_like => { :num_forms => 3, :doc => ['When count is 1', 'When count is 2, 3, 4', 'Everything else (0, 5, 6, ...)'], :rule => lambda { |n| (n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2 } }, :polish_like => { :num_forms => 3, :doc => ['When count is 1', 'When count ends in 2-4, excluding 12-14 (2, 3, 4, 22, ...)', 'Everything else (0, 5, 6, ...)'], :rule => lambda { |n| (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2) } }, :icelandic_like => { :num_forms => 2, :doc => ['When count ends in 1, excluding 11 (1, 21, 31, ...)', 'Everything else (0, 2, 3, ...)'], :rule => lambda { |n| (n % 10 != 1 || n % 100 == 11) ? 1 : 0 } }, }
- PLURAL_TYPE_NAME_TO_LANGUAGES =
{ :chinese_like => [:id, :ja, :ko, :ms, :th, :tr, :zh, ], :german_like => [:da, :de, :en, :es, :fi, :el, :he, :hu, :it, :nl, :no, :pt, :sv, ], :french_like => [:fr, :tl, ], :russian_like => [:hr, :ru, ], :czech_like => [:cs], :polish_like => [:pl], :icelandic_like => [:is], }
- LANGUAGE_TO_PLURAL_TYPE_NAME =
PLURAL_TYPE_NAME_TO_LANGUAGES.inject({}) do |carry, (type, languages)| languages.each { |l| carry[l] = type } carry end
Class Method Summary collapse
- .applies?(text) ⇒ Boolean
-
.choose(text, locale, count) ⇒ Object
Chooses the right version of ‘text’ for the value of the ‘smart_count’ in ‘locale’.
-
.dedupe_things_like_tags_or_variables(locale, things) ⇒ Object
Takes a list of things (for example tags or variables), counts up how many of each thing there are, then returns a new list that has each thing but with a possibly different count.
-
.hint(source_text, target_locale) ⇒ Object
Returns a hint for translators translating source_text to target_locale, or nil if there is no smart-count-related hint.
- .num_forms(locale) ⇒ Object
- .plural_type_index(locale, count) ⇒ Object
- .plural_type_name(locale) ⇒ Object
- .valid?(source_text, target_text, source_locale, target_locale) ⇒ Boolean
Class Method Details
.applies?(text) ⇒ Boolean
137 138 139 |
# File 'lib/air18n/smart_count.rb', line 137 def applies?(text) !!text.index(DELIMITER) end |
.choose(text, locale, count) ⇒ Object
Chooses the right version of ‘text’ for the value of the ‘smart_count’ in ‘locale’.
Examples:
choose("%{smart_count} bewertung |||| %{smart_count} bewertungen",
:de, 0)
=> "%{smart_count} bewertungen"
choose("%{smart_count} bewertung |||| %{smart_count} bewertungen",
:de, 1)
=> "%{smart_count} bewertung"
choose("%{smart_count} bewertung |||| %{smart_count} bewertungen",
:de, 2)
=> "%{smart_count} bewertungen"
choose("%{smart_count} bewertung |||| %{smart_count} bewertungen",
:de, nil)
=> "%{smart_count} bewertung |||| %{smart_count} bewertungen"
If ‘count’ is nil or ‘text’ contains too few alternative versions, this method degrades gracefully by returning the first version of text.
Returns if nil if text is blank.
105 106 107 108 109 110 111 112 113 |
# File 'lib/air18n/smart_count.rb', line 105 def choose(text, locale, count) if count.present? && text.present? texts = text.split(DELIMITER) chosen_text = texts[plural_type_index(locale, count)] || texts.first chosen_text.strip else text end end |
.dedupe_things_like_tags_or_variables(locale, things) ⇒ Object
Takes a list of things (for example tags or variables), counts up how many of each thing there are, then returns a new list that has each thing but with a possibly different count.
The count of each thing in the returned list is determined by:
-
If the count is a multiple of the number of plural forms for ‘locale’,
count is divided by the number of plural forms.
-
Otherwise count is set to 0.
The returned list is reordered so that all instances of the same thing are consecutive, and are ordered in the same order as the first of each thing in the original list.
This method is useful for ensuring that HTML tags or interpolation variables match in smart-count phrases between languages that might have different numbers of plural forms.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/air18n/smart_count.rb', line 161 def (locale, things) return things if things.blank? num_forms = num_forms(locale) grouped_things = things.group_by { |t| t } deduped = grouped_things.inject([]) do |carry, (thing, list_of_things)| count_of_thing = list_of_things.size if count_of_thing % num_forms == 0 deduped_count_of_thing = count_of_thing / num_forms else deduped_count_of_thing = 0 end deduped_count_of_thing.times { carry << thing } carry end end |
.hint(source_text, target_locale) ⇒ Object
Returns a hint for translators translating source_text to target_locale, or nil if there is no smart-count-related hint.
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/air18n/smart_count.rb', line 126 def hint(source_text, target_locale) if applies?(source_text) doc_array = PLURAL_TYPES[plural_type_name(target_locale)][:doc] if doc_array doc_string = doc_array.join(' ' + DELIMITER + ' ') n = num_forms(target_locale) "Must specify #{n} forms separated by \"#{DELIMITER}\": \"#{doc_string}\"" end end end |
.num_forms(locale) ⇒ Object
141 142 143 |
# File 'lib/air18n/smart_count.rb', line 141 def num_forms(locale) PLURAL_TYPES[plural_type_name(locale)][:num_forms] end |
.plural_type_index(locale, count) ⇒ Object
120 121 122 |
# File 'lib/air18n/smart_count.rb', line 120 def plural_type_index(locale, count) PLURAL_TYPES[plural_type_name(locale)][:rule].call(count) end |
.plural_type_name(locale) ⇒ Object
115 116 117 118 |
# File 'lib/air18n/smart_count.rb', line 115 def plural_type_name(locale) LANGUAGE_TO_PLURAL_TYPE_NAME[I18n.language_from_locale(locale)] || LANGUAGE_TO_PLURAL_TYPE_NAME[I18n.default_language] end |
.valid?(source_text, target_text, source_locale, target_locale) ⇒ Boolean
178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/air18n/smart_count.rb', line 178 def valid?(source_text, target_text, source_locale, target_locale) if applies?(source_text) || applies?(target_text) size = target_text.split(DELIMITER).size num_forms = num_forms(target_locale) if size == num_forms { :valid => true } else { :valid => false, :reason => "Must specify #{num_forms} forms separated by \"#{DELIMITER}\" (#{size} #{size == 1? 'was' : 'were'} specified)" } end else { :valid => true } end end |