svenfuchs-i18n-tools 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
data/test/all.rb CHANGED
@@ -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