i18n-tools 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. data/lib/core_ext/hash/iterate_nested.rb +35 -0
  2. data/lib/core_ext/hash/slice.rb +20 -0
  3. data/lib/core_ext/hash/sorted_yaml_style.rb +17 -0
  4. data/lib/core_ext/hash/symbolize_keys.rb +14 -0
  5. data/lib/core_ext/module/attribute_accessors.rb +48 -0
  6. data/lib/core_ext/object/deep_clone.rb +5 -0
  7. data/lib/core_ext/object/instance_variables.rb +9 -0
  8. data/lib/core_ext/object/meta_class.rb +5 -0
  9. data/lib/core_ext/object/tap.rb +6 -0
  10. data/lib/i18n/backend/simple_storage.rb +119 -0
  11. data/lib/i18n/commands/keys.rb +84 -0
  12. data/lib/i18n/exceptions/key_exists.rb +9 -0
  13. data/lib/i18n/index.rb +33 -0
  14. data/lib/i18n/index/base.rb +38 -0
  15. data/lib/i18n/index/file.rb +55 -0
  16. data/lib/i18n/index/format.rb +49 -0
  17. data/lib/i18n/index/key.rb +45 -0
  18. data/lib/i18n/index/occurence.rb +18 -0
  19. data/lib/i18n/index/simple.rb +69 -0
  20. data/lib/i18n/index/simple/data.rb +34 -0
  21. data/lib/i18n/index/simple/storage.rb +79 -0
  22. data/lib/i18n/ripper2ruby.rb +7 -0
  23. data/lib/i18n/ripper2ruby/translate_args_list.rb +89 -0
  24. data/lib/i18n/ripper2ruby/translate_call.rb +66 -0
  25. data/lib/i18n/translation_properties.rb +38 -0
  26. data/test/all.rb +1 -1
  27. data/test/core_ext/hash_iterate_nested.rb +31 -0
  28. data/test/fixtures/all.rb.src +106 -0
  29. data/test/fixtures/config.yml +3 -0
  30. data/test/fixtures/locale/de.yml +4 -0
  31. data/test/fixtures/locale/en.yml +4 -0
  32. data/test/fixtures/source_1.rb +2 -1
  33. data/test/fixtures/translate/double_key.rb +32 -0
  34. data/test/fixtures/translate/double_scope.rb +32 -0
  35. data/test/fixtures/translate/single_key.rb +10 -0
  36. data/test/fixtures/translate/single_scope.rb +32 -0
  37. data/test/i18n/backend/simple_storage_test.rb +81 -0
  38. data/test/i18n/backend/translation_properties_test.rb +33 -0
  39. data/test/i18n/index/all.rb +1 -0
  40. data/test/i18n/index/args_replace_test.rb +218 -0
  41. data/test/i18n/index/calls_replace_test.rb +67 -0
  42. data/test/i18n/index/commands_test.rb +75 -0
  43. data/test/i18n/index/key_test.rb +32 -0
  44. data/test/i18n/index/simple_test.rb +67 -0
  45. data/test/i18n/ripper2ruby/translate_call_test.rb +98 -0
  46. data/test/test_helper.rb +66 -9
  47. metadata +49 -32
  48. data/MIT-LICENSE +0 -20
  49. data/README.textile +0 -1
  50. data/bin/i18n-keys +0 -6
  51. data/lib/ansi.rb +0 -19
  52. data/lib/i18n/keys.rb +0 -51
  53. data/lib/i18n/keys/commands.rb +0 -53
  54. data/lib/i18n/keys/formatter.rb +0 -39
  55. data/lib/i18n/keys/index.rb +0 -209
  56. data/lib/i18n/keys/occurence.rb +0 -120
  57. data/lib/i18n/parser/erb_parser.rb +0 -54
  58. data/lib/i18n/parser/ruby_parser.rb +0 -93
  59. data/test/commands_test.rb +0 -1
  60. data/test/erb_parser_test.rb +0 -31
  61. data/test/index_test.rb +0 -135
  62. data/test/keys_test.rb +0 -75
  63. data/test/occurence_test.rb +0 -130
  64. data/test/ruby_parser_test.rb +0 -54
@@ -0,0 +1,66 @@
1
+ module Ruby
2
+ class Node
3
+ def select_translate_calls(*args)
4
+ select(Ruby::Call, *args) { |node| node.is_translate_call? }.map { |call| call.to_translate_call }
5
+ end
6
+
7
+ def is_translate_call?
8
+ false
9
+ end
10
+ end
11
+
12
+ class Call
13
+ def to_translate_call
14
+ unless meta_class.include?(TranslateCall)
15
+ meta_class.send(:include, TranslateCall)
16
+ arguments.to_translate_args_list if arguments.respond_to?(:to_translate_args_list)
17
+ end
18
+ self
19
+ end
20
+
21
+ def is_translate_call?
22
+ identifier.try(:token) == 't' &&
23
+ is_translate_method_target?(target) &&
24
+ is_translate_key?(arguments.first.try(:arg))
25
+ end
26
+
27
+ protected
28
+
29
+ def is_translate_method_target?(target)
30
+ target.nil? || target.try(:identifier).try(:token) == 'I18n'
31
+ end
32
+
33
+ def is_translate_key?(arg)
34
+ # TODO ... what to do with Arrays? what to do with DynaSymbols w/ embedded expressions?
35
+ arg && [Ruby::Symbol, Ruby::DynaSymbol, Ruby::String].include?(arg.class) && arg.try(:value)
36
+ end
37
+ end
38
+
39
+ module TranslateCall
40
+ def full_key(*args)
41
+ arguments.full_key(*args)
42
+ end
43
+
44
+ def key(*args)
45
+ arguments.key(*args)
46
+ end
47
+
48
+ def scope(*args)
49
+ arguments.scope(*args)
50
+ end
51
+
52
+ def key_matches?(*args)
53
+ arguments.key_matches?(*args)
54
+ end
55
+
56
+ def replace_key(search, replacement)
57
+ arguments.replace_key(search, replacement)
58
+ end
59
+
60
+ def to_s(options = {})
61
+ context = (options.has_key?(:context) ? self.context(options.update(:width => options[:context].to_i)) : '')
62
+ context = context.split("\n").map(&:strip).join("\n")
63
+ "#{key}: #{filename} [#{row}/#{column}]\n" + context
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ module I18n
2
+ module TranslationProperties
3
+ class << self
4
+ def property_names
5
+ @property_names ||= []
6
+ end
7
+
8
+ def define_property(name)
9
+ unless respond_to?(name)
10
+ attr_accessor(name)
11
+ property_names << name unless property_names.include?(name)
12
+ end
13
+ end
14
+ end
15
+
16
+ def properties
17
+ TranslationProperties.property_names.inject({}) do |properties, name|
18
+ properties[name] = self.send(name)
19
+ properties
20
+ end
21
+ end
22
+
23
+ def set_properties(properties)
24
+ properties.each { |name, value| set_property(name, value) }
25
+ end
26
+
27
+ def set_property(name, value)
28
+ TranslationProperties.define_property(name)
29
+ send(:"#{name}=", value)
30
+ end
31
+
32
+ def unset_properties
33
+ TranslationProperties.property_names.each do |name|
34
+ remove_instance_variable("@#{name}") rescue NameError
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1 +1 @@
1
- Dir[File.dirname(__FILE__) + '/*_test.rb'].each { |file| require file }
1
+ Dir[File.dirname(__FILE__) + '/**/*_test.rb'].each { |file| require file }
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'core_ext/hash/iterate_nested'
3
+
4
+ class HashIterateNestedTest < Test::Unit::TestCase
5
+ def test_hash_each_nested
6
+ hash = { :foo => { :bar => { :baz => :baa, :bas => :bah }, :bor => { :boz => :boo, :bos => :boh } } }
7
+ result = { :keys => [], :values => []}
8
+ hash.each_nested do |keys, value|
9
+ result[:keys] << keys
10
+ result[:values] << value
11
+ end
12
+ assert_equal [[:foo, :bar, :baz], [:foo, :bar, :bas], [:foo, :bor, :boz], [:foo, :bor, :bos]], result[:keys]
13
+ assert_equal [:baa, :bah, :boo, :boh], result[:values]
14
+ end
15
+
16
+ def test_hash_select_nested
17
+ hash = { :foo => { :bar => { :baz => :baa, :bas => :bah }, :bor => { :boz => :boo, :bos => :boh } } }
18
+
19
+ expected = hash
20
+ result = hash.select_nested { |keys, value| keys.include?(:foo) }
21
+ assert_equal expected, result
22
+
23
+ expected = { :foo => { :bar => { :baz => :baa, :bas => :bah } } }
24
+ result = hash.select_nested { |keys, value| keys.include?(:bar) }
25
+ assert_equal expected, result
26
+
27
+ expected = { :foo => { :bor => { :boz => :boo } } }
28
+ result = hash.select_nested { |keys, value| keys.include?(:boz) }
29
+ assert_equal expected, result
30
+ end
31
+ end
@@ -0,0 +1,106 @@
1
+ # occurences of \n will be replaced with actual newlines
2
+
3
+ # numbers
4
+ 1
5
+ 1.1
6
+
7
+ # symbols
8
+ :a
9
+ :"a"
10
+ :"a \n b \n c"
11
+ :'a'
12
+ :'a \n b \n c'
13
+
14
+
15
+ # strings
16
+
17
+ "a"
18
+ 'a'
19
+ %(a)
20
+ %( a \n b \n c )
21
+ %|a|
22
+ %.a.
23
+
24
+
25
+ # arrays
26
+
27
+ [:a,:b,:c]
28
+ [:a,:b, :c]
29
+ [:a, :b,:c]
30
+ [:a, :b, :c]
31
+ [:a, :b, :c ]
32
+ [ :a, :b, :c]
33
+ [ :a, :b, :c ]
34
+
35
+ [ \n :a, \n :b, \n :c \n ]
36
+
37
+ %w(a b c)
38
+ %w(a b c )
39
+ %w( a b c)
40
+ %w( a b c )
41
+
42
+ # hashes
43
+
44
+ {:a=>:a}
45
+ {:a=>:a }
46
+ { :a=>:a}
47
+ {:a => :a}
48
+ { :a=>:a }
49
+ {:a=> :a }
50
+ { :a =>:a}
51
+ { :a => :a }
52
+
53
+ { \n :a => \n :a \n }
54
+
55
+ # constants
56
+
57
+ I18n
58
+
59
+ # assignments
60
+
61
+ a=b
62
+ a,b=c
63
+ a, b=c
64
+ a, b=c,d
65
+ a, b=c, d
66
+ a, b=*c
67
+
68
+ a = b
69
+ a,b = c
70
+ a, b = c
71
+ a, b = c,d
72
+ a, b = c, d
73
+ a, b = *c
74
+
75
+ a, \n b = \n c, \n d
76
+
77
+ # calls
78
+
79
+ t
80
+ t()
81
+ t(:a)
82
+ t :a
83
+ t :a
84
+
85
+ I18n.t
86
+ I18n.t()
87
+ I18n.t(:a)
88
+
89
+ t(:a,:b)
90
+ t(:a, :b)
91
+ t(:a ,:b)
92
+ t(:a, :b )
93
+ t(:a ,:b )
94
+ t( :a, :b)
95
+ t( :a ,:b)
96
+ t( :a, :b )
97
+ t( :a ,:b )
98
+
99
+ t(:a, :b,&c)
100
+ t(:a, :b, &c)
101
+
102
+ t(:a, :b, :c => :c, &c)
103
+ t(:a, :b, { :c => :c }, &c)
104
+
105
+ t( \n:a, \n :b, \n :c => \n :c, \n &d)
106
+
@@ -0,0 +1,3 @@
1
+ indices:
2
+ default:
3
+ pattern: foo
@@ -0,0 +1,4 @@
1
+ de:
2
+ foo:
3
+ baz: Bas
4
+ bar: Bah
@@ -0,0 +1,4 @@
1
+ en:
2
+ foo:
3
+ bar: Bar
4
+ baz: Baz
@@ -2,13 +2,14 @@ class Foo
2
2
  def foo
3
3
  t(:bar)
4
4
  t(:"baaar")
5
- t(:'baar')
5
+ t(:baar, :scope => [:baz, :fooo], :default => 'bla')
6
6
  t(:'foo.bar')
7
7
  t("bar")
8
8
  t('bar_1')
9
9
  1 + 1
10
10
  t(1)
11
11
  t(1.1)
12
+ t(1 + 1)
12
13
  end
13
14
  foo(:outside_)
14
15
  end
@@ -0,0 +1,32 @@
1
+ I18n.t(:"bar.baz",:scope=>:foo)
2
+ I18n.t(:"bar.baz", :scope=>:foo)
3
+ I18n.t(:"bar.baz",:scope =>:foo)
4
+ I18n.t(:"bar.baz",:scope=> :foo)
5
+ I18n.t(:"bar.baz",:scope=>:foo )
6
+ I18n.t(:"bar.baz", :scope =>:foo)
7
+ I18n.t(:"bar.baz", :scope=> :foo)
8
+ I18n.t(:"bar.baz", :scope=>:foo )
9
+ I18n.t(:"bar.baz", :scope =>:foo)
10
+ I18n.t(:"bar.baz", :scope => :foo)
11
+ I18n.t(:"bar.baz", :scope =>:foo )
12
+ I18n.t(:"bar.baz", :scope => :foo )
13
+ t(:"bar.baz",:scope=>:foo)
14
+ t(:"bar.baz", :scope=>:foo)
15
+ t(:"bar.baz",:scope =>:foo)
16
+ t(:"bar.baz",:scope=> :foo)
17
+ t(:"bar.baz",:scope=>:foo )
18
+ t(:"bar.baz", :scope =>:foo)
19
+ t(:"bar.baz", :scope=> :foo)
20
+ t(:"bar.baz", :scope=>:foo )
21
+ t(:"bar.baz", :scope =>:foo)
22
+ t(:"bar.baz", :scope => :foo)
23
+ t(:"bar.baz", :scope =>:foo )
24
+ t(:"bar.baz", :scope => :foo )
25
+ t :"bar.baz",:scope=>:foo
26
+ t :"bar.baz", :scope=>:foo
27
+ t :"bar.baz",:scope =>:foo
28
+ t :"bar.baz",:scope=> :foo
29
+ t :"bar.baz", :scope =>:foo
30
+ t :"bar.baz", :scope=> :foo
31
+ t :"bar.baz", :scope =>:foo
32
+ t :"bar.baz", :scope => :foo
@@ -0,0 +1,32 @@
1
+ I18n.t(:baz,:scope=>[:foo, :bar])
2
+ I18n.t(:baz, :scope=>[:foo, :bar])
3
+ I18n.t(:baz,:scope =>[:foo, :bar])
4
+ I18n.t(:baz,:scope=> [:foo, :bar])
5
+ I18n.t(:baz,:scope=>[:foo, :bar] )
6
+ I18n.t(:baz, :scope =>[:foo, :bar])
7
+ I18n.t(:baz, :scope=> [:foo, :bar])
8
+ I18n.t(:baz, :scope=>[:foo, :bar] )
9
+ I18n.t(:baz, :scope =>[:foo, :bar])
10
+ I18n.t(:baz, :scope => [:foo, :bar])
11
+ I18n.t(:baz, :scope =>[:foo, :bar] )
12
+ I18n.t(:baz, :scope => [:foo, :bar] )
13
+ t(:baz,:scope=>[:foo, :bar])
14
+ t(:baz, :scope=>[:foo, :bar])
15
+ t(:baz,:scope =>[:foo, :bar])
16
+ t(:baz,:scope=> [:foo, :bar])
17
+ t(:baz,:scope=>[:foo, :bar] )
18
+ t(:baz, :scope =>[:foo, :bar])
19
+ t(:baz, :scope=> [:foo, :bar])
20
+ t(:baz, :scope=>[:foo, :bar] )
21
+ t(:baz, :scope =>[:foo, :bar])
22
+ t(:baz, :scope => [:foo, :bar])
23
+ t(:baz, :scope =>[:foo, :bar] )
24
+ t(:baz, :scope => [:foo, :bar] )
25
+ t :baz,:scope=>[:foo, :bar]
26
+ t :baz, :scope=>[:foo, :bar]
27
+ t :baz,:scope =>[:foo, :bar]
28
+ t :baz,:scope=> [:foo, :bar]
29
+ t :baz, :scope =>[:foo, :bar]
30
+ t :baz, :scope=> [:foo, :bar]
31
+ t :baz, :scope =>[:foo, :bar]
32
+ t :baz, :scope => [:foo, :bar]
@@ -0,0 +1,10 @@
1
+ I18n.t('foo')
2
+ I18n.t('foo', :a)
3
+ I18n.t('foo', :a => :a)
4
+ t(:foo)
5
+ t(:foo, :a)
6
+ t(:foo, :a => :a)
7
+ t :foo
8
+ t :foo, :a
9
+ t :foo, :a => :a
10
+
@@ -0,0 +1,32 @@
1
+ I18n.t(:bar,:scope=>:foo)
2
+ I18n.t(:bar, :scope=>:foo)
3
+ I18n.t(:bar,:scope =>:foo)
4
+ I18n.t(:bar,:scope=> :foo)
5
+ I18n.t(:bar,:scope=>:foo )
6
+ I18n.t(:bar, :scope =>:foo)
7
+ I18n.t(:bar, :scope=> :foo)
8
+ I18n.t(:bar, :scope=>:foo )
9
+ I18n.t(:bar, :scope =>:foo)
10
+ I18n.t(:bar, :scope => :foo)
11
+ I18n.t(:bar, :scope =>:foo )
12
+ I18n.t(:bar, :scope => :foo )
13
+ t(:bar,:scope=>:foo)
14
+ t(:bar, :scope=>:foo)
15
+ t(:bar,:scope =>:foo)
16
+ t(:bar,:scope=> :foo)
17
+ t(:bar,:scope=>:foo )
18
+ t(:bar, :scope =>:foo)
19
+ t(:bar, :scope=> :foo)
20
+ t(:bar, :scope=>:foo )
21
+ t(:bar, :scope =>:foo)
22
+ t(:bar, :scope => :foo)
23
+ t(:bar, :scope =>:foo )
24
+ t(:bar, :scope => :foo )
25
+ t :bar,:scope=>:foo
26
+ t :bar, :scope=>:foo
27
+ t :bar,:scope =>:foo
28
+ t :bar,:scope=> :foo
29
+ t :bar, :scope =>:foo
30
+ t :bar, :scope=> :foo
31
+ t :bar, :scope =>:foo
32
+ t :bar, :scope => :foo
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'i18n'
3
+ require 'i18n/backend/simple_storage'
4
+
5
+ class I18nSimpleStorageTest < Test::Unit::TestCase
6
+ def setup
7
+ @filenames = {
8
+ :de => File.dirname(__FILE__) + '/../../fixtures/locale/de.yml',
9
+ :en => File.dirname(__FILE__) + '/../../fixtures/locale/en.yml',
10
+ :pr => File.dirname(__FILE__) + '/../../fixtures/locale/pr.yml'
11
+ }
12
+ I18n.load_path += @filenames.values_at(:de, :en)
13
+ @backend = I18n.backend = I18n::Backend::SimpleStorage.new
14
+ end
15
+
16
+ def teardown
17
+ File.delete(@filenames[:pr]) rescue nil
18
+ end
19
+
20
+ define_method :"test: sets filename property on translations" do
21
+ assert_equal @filenames[:de], I18n.t(:'foo.bar', :locale => :de).filename
22
+ assert_equal @filenames[:de], I18n.t(:'foo.baz', :locale => :de).filename
23
+ assert_equal @filenames[:en], I18n.t(:'foo.bar', :locale => :en).filename
24
+ assert_equal @filenames[:en], I18n.t(:'foo.baz', :locale => :en).filename
25
+ end
26
+
27
+ define_method :"test each_translation" do
28
+ locales, keys, values = [], [], []
29
+ I18n.backend.send(:each_translation) do |locale, key, value|
30
+ locales << locale
31
+ keys << key
32
+ values << value
33
+ end
34
+ assert_equal [:de, :en], locales.uniq
35
+ assert_equal [[:foo, :bar], [:foo, :baz]], keys.uniq.sort
36
+ assert_equal %w(Bah Bar Bas Baz), values.sort
37
+ end
38
+
39
+ define_method :"test select_translations" do
40
+ translations = @backend.send(:select_translations) { |keys, translation| translation.filename =~ /de.yml/ }
41
+ expected = { :de => { :foo => { :bar => "Bah", :baz => "Bas" } } }
42
+ assert_equal expected, translations
43
+ end
44
+
45
+ define_method :"test by_filename" do
46
+ translations = @backend.send(:by_filename, @filenames[:de])
47
+ expected = { :de => { :foo => { :bar => "Bah", :baz => "Bas" } } }
48
+ assert_equal expected, translations
49
+ end
50
+
51
+ define_method :"test save_translations" do
52
+ filename = @filenames[:pr]
53
+ data = @backend.send(:by_filename, @filenames[:de])[:de].deep_clone
54
+
55
+ @backend.send(:set_translation_properties, data, :filename => filename)
56
+ @backend.store_translations(:pr, data)
57
+ @backend.save_translations(filename)
58
+
59
+ expected = I18n.backend.send(:deep_stringify_keys, :pr => data)
60
+ assert_equal(expected, YAML.load_file(filename))
61
+ assert_equal(['bar', 'baz'], YAML.load_file(filename)['pr']['foo'].keys)
62
+ assert_equal "--- \npr: \n foo: \n bar: Bah\n baz: Bas\n", File.read(filename)
63
+ end
64
+
65
+ define_method :"test remove_translation" do
66
+ assert_equal({ :bar => "Bar", :baz => "Baz" }, I18n.t(:foo))
67
+
68
+ @backend.remove_translation([:foo, :bar])
69
+ assert_equal({ :baz => "Baz" }, I18n.t(:foo))
70
+
71
+ @backend.remove_translation([:foo])
72
+ assert_equal "translation missing: en, foo", I18n.t(:foo)
73
+ assert_equal "translation missing: de, foo", I18n.t(:foo, :locale => :de)
74
+ end
75
+
76
+ define_method :"test store_translation does not overwrite existing keys" do
77
+ assert_equal({ :bar => "Bar", :baz => "Baz" }, I18n.t(:foo))
78
+ assert_raises(I18n::KeyExists) { @backend.store_translations(:en, :foo => 'Foo') }
79
+ assert_equal({ :bar => "Bar", :baz => "Baz" }, I18n.t(:foo))
80
+ end
81
+ end