Skip to content

Commit

Permalink
Merge pull request #19 from freetwix/feature/pluralization
Browse files Browse the repository at this point in the history
fixed pluralization handling
  • Loading branch information
thomasdarde committed Sep 11, 2012
2 parents 93e6210 + 0631b89 commit 925fcb6
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 29 deletions.
1 change: 1 addition & 0 deletions .rvmrc
@@ -0,0 +1 @@
rvm --create ruby-1.9.3-p194@tolk
3 changes: 2 additions & 1 deletion app/models/tolk/locale.rb
Expand Up @@ -64,7 +64,8 @@ def special_key_or_prefix?(prefix, key)
self.special_prefixes.include?(prefix) || self.special_keys.include?(key) self.special_prefixes.include?(prefix) || self.special_keys.include?(key)
end end


PLURALIZATION_KEYS = ['none', 'one', 'two', 'few', 'many', 'other'] # http://cldr.unicode.org/index/cldr-spec/plural-rules - TODO: usage of 'none' isn't standard-conform
PLURALIZATION_KEYS = ['none', 'zero', 'one', 'two', 'few', 'many', 'other']
def pluralization_data?(data) def pluralization_data?(data)
keys = data.keys.map(&:to_s) keys = data.keys.map(&:to_s)
keys.all? {|k| PLURALIZATION_KEYS.include?(k) } keys.all? {|k| PLURALIZATION_KEYS.include?(k) }
Expand Down
16 changes: 12 additions & 4 deletions app/models/tolk/translation.rb
Expand Up @@ -57,12 +57,20 @@ def value
end end


def self.detect_variables(search_in) def self.detect_variables(search_in)
case search_in variables = case search_in
when String then Set.new(search_in.scan(/\{\{(\w+)\}\}/).flatten + search_in.scan(/\%\{(\w+)\}/).flatten) when String then Set.new(search_in.scan(/\{\{(\w+)\}\}/).flatten + search_in.scan(/\%\{(\w+)\}/).flatten)
when Array then search_in.inject(Set[]) { |carry, item| carry + detect_variables(item) } when Array then search_in.inject(Set[]) { |carry, item| carry + detect_variables(item) }
when Hash then search_in.values.inject(Set[]) { |carry, item| carry + detect_variables(item) } when Hash then search_in.values.inject(Set[]) { |carry, item| carry + detect_variables(item) }
else Set[] else Set[]
end end

# delete special i18n variable used for pluralization itself (might not be used in all values of
# the pluralization keys, but is essential to use pluralization at all)
if search_in.is_a?(Hash) && Tolk::Locale.pluralization_data?(search_in)
variables.delete_if {|v| v == 'count' }
else
variables
end
end end


def variables def variables
Expand Down Expand Up @@ -110,10 +118,10 @@ def set_previous_text


def check_matching_variables def check_matching_variables
unless variables_match? unless variables_match?
if primary_translation.variables.empty? || primary_translation.variables.class == Set if primary_translation.variables.empty?
self.errors.add(:text, "The original does not contain variables, so they should not be included.") self.errors.add(:variables, "The primary translation does not contain substitutions, so this should neither.")
else else
self.errors.add(:text, "The translation should contain the variables #{primary_translation.to_a.to_sentence}.") self.errors.add(:variables, "The translation should contain the substitutions of the primary translation: (#{primary_translation.variables.to_a.join(', ')}), found (#{self.variables.to_a.join(', ')}).")
end end
end end
end end
Expand Down
14 changes: 9 additions & 5 deletions lib/tolk/import.rb
Expand Up @@ -8,13 +8,13 @@ module ClassMethods


def import_secondary_locales def import_secondary_locales
locales = Dir.entries(self.locales_config_path) locales = Dir.entries(self.locales_config_path)

locale_block_filter = Proc.new { locale_block_filter = Proc.new {
|l| ['.', '..'].include?(l) || |l| ['.', '..'].include?(l) ||
!l.ends_with?('.yml') || !l.ends_with?('.yml') ||
l.match(/(.*\.){2,}/) # reject files of type xxx.en.yml l.match(/(.*\.){2,}/) # reject files of type xxx.en.yml
} }
locales = locales.reject(&locale_block_filter).map {|x| x.split('.').first } locales = locales.reject(&locale_block_filter).map {|x| x.split('.').first }
locales = locales - [Tolk::Locale.primary_locale.name] locales = locales - [Tolk::Locale.primary_locale.name]
locales.each {|l| import_locale(l) } locales.each {|l| import_locale(l) }
end end
Expand All @@ -32,9 +32,13 @@ def import_locale(locale_name)


if phrase if phrase
translation = locale.translations.new(:text => value, :phrase => phrase) translation = locale.translations.new(:text => value, :phrase => phrase)
count = count + 1 if translation.save if translation.save
count = count + 1
elsif translation.errors[:variables].present?
puts "[WARN] Key '#{key}' from '#{locale_name}.yml' could not be saved: #{translation.errors[:variables].first}"
end
else else
puts "[ERROR] Key '#{key}' was found in #{locale_name}.yml but #{Tolk::Locale.primary_language_name} translation is missing" puts "[ERROR] Key '#{key}' was found in '#{locale_name}.yml' but #{Tolk::Locale.primary_language_name} translation is missing"
end end
end end


Expand Down
8 changes: 7 additions & 1 deletion test/locales/formats/en.yml
Expand Up @@ -9,7 +9,13 @@ en:
number_array: [1, 2, 3] number_array: [1, 2, 3]
string_array: ['sun', 'moon'] string_array: ['sun', 'moon']
pluralization: pluralization:
other: Hello none: none
zero: zero
one: one
two: two
few: few
many: many
other: other
not_pluralization: not_pluralization:
other: World other: World
lifo: fifo lifo: fifo
Expand Down
14 changes: 11 additions & 3 deletions test/unit/format_test.rb
Expand Up @@ -27,11 +27,19 @@ def test_all_formats_are_loaded_properly
assert_equal ['sun', 'moon'], @en.get('string_array') assert_equal ['sun', 'moon'], @en.get('string_array')
end end


def test_pluaralization def test_pluralization
result = {'other' => 'Hello'} result = {
"none" => "none",
"zero" => "zero",
"one" => "one",
"two" => "two",
"few" => "few",
"many" => "many",
"other" => "other"
}
assert_equal result, @en.get('pluralization') assert_equal result, @en.get('pluralization')


assert ! @en.get('not_pluralization') assert_nil @en.get('not_pluralization')
assert_equal 'World', @en.get('not_pluralization.other') assert_equal 'World', @en.get('not_pluralization.other')
assert_equal 'fifo', @en.get('not_pluralization.lifo') assert_equal 'fifo', @en.get('not_pluralization.lifo')
end end
Expand Down
3 changes: 0 additions & 3 deletions test/unit/import_test.rb
Expand Up @@ -19,10 +19,7 @@ def setup
test "skips gem translations files (xxx.en.yml)" do test "skips gem translations files (xxx.en.yml)" do
Tolk::Locale.sync! Tolk::Locale.sync!
Tolk::Locale.import_secondary_locales Tolk::Locale.import_secondary_locales



assert_equal 0, Tolk::Phrase.where(key: 'gem_hello_world').count assert_equal 0, Tolk::Phrase.where(key: 'gem_hello_world').count

end end

end end
65 changes: 53 additions & 12 deletions test/unit/translation_test.rb
Expand Up @@ -9,36 +9,77 @@ def setup
end end


test "translation is inavlid when a duplicate exists" do test "translation is inavlid when a duplicate exists" do
translation = Tolk::Translation.new :phrase => tolk_translations(:hello_world_da).phrase, :locale => tolk_translations(:hello_world_da).locale translation = Tolk::Translation.new(:phrase => tolk_translations(:hello_world_da).phrase, :locale => tolk_translations(:hello_world_da).locale)
translation.text = "Revised Hello World" translation.text = "Revised Hello World"
assert translation.invalid? assert(translation.invalid?)
assert translation.errors[:phrase_id] assert(translation.errors[:phrase_id])
end end

test "translation is not changed when text is assigned an equal value in numberic form" do test "translation is not changed when text is assigned an equal value in numberic form" do
translation = tolk_translations(:human_format_precision_en) translation = tolk_translations(:human_format_precision_en)
assert_equal "1", translation.text assert_equal("1", translation.text)
translation.text = "1" translation.text = "1"
assert_equal false, translation.changed? assert_equal(false, translation.changed?)
translation.text = 1 translation.text = 1
assert_equal false, translation.changed? assert_equal(false, translation.changed?)
end end


test "translation with string value" do test "translation with string value" do
assert_equal "Hello World", tolk_translations(:hello_world_en).value assert_equal("Hello World", tolk_translations(:hello_world_en).value)
end end


test "translation with string value with variables" do test "translation with string value with variables" do
text = "{{attribute}} {{message}}" text = "{{attribute}} {{message}}"
assert_equal text, Tolk::Translation.new(:text => text).value assert_equal(text, Tolk::Translation.new(:text => text).value)
end end


test "translation with numeric value" do test "translation with numeric value" do
assert_equal 1, tolk_translations(:human_format_precision_en).value assert_equal(1, tolk_translations(:human_format_precision_en).value)
end end

test "translation with hash value" do test "translation with hash value" do
hash = {:foo => "bar"} hash = {:foo => "bar"}
assert_equal hash, Tolk::Translation.new(:text => hash).value assert_equal(hash, Tolk::Translation.new(:text => hash).value)
end

test "pluralization translation special variable 'count' not a variable" do
text = {
'zero' => "{{message}}",
'many' => "{{message}} {{count}}",
'other' => "{{message}} {{count}}"
}
assert_equal(Set['message'], Tolk::Translation.detect_variables(text))
end

test "validation for variables (mismatch)" do
primary_text = {
'zero' => "{{message}}",
'many' => "{{message}} {{count}}",
}
text = {
'zero' => "{{message}}",
'many' => "{{foo}}",
}

Tolk::Translation.new(:text => text).tap do |t|
t.stubs(:primary_translation).returns(Tolk::Translation.new(:text => primary_text))
t.valid?
assert_equal ["The translation should contain the substitutions of the primary translation: (message), found (message, foo)."], t.errors[:variables]
end
end

test "validation for variables (no variables in primary)" do
primary_text = {
'foo' => "nada"
}
text = {
'foo' => "{{foo}} nada"
}

Tolk::Translation.new(:text => text).tap do |t|
t.stubs(:primary_translation).returns(Tolk::Translation.new(:text => primary_text))
t.valid?
assert_equal ["The primary translation does not contain substitutions, so this should neither."], t.errors[:variables]
end
end end
end end

0 comments on commit 925fcb6

Please sign in to comment.