rails-i18nterface 0.1.3 → 0.1.4

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.
data/README.md CHANGED
@@ -8,21 +8,23 @@ This is a fork of an overhaul of a fork of a fork of rails-translate.
8
8
 
9
9
  It was originally created by [Peter Marklund and Joakim Westerlund @ mynewsdesk](https://github.com/mynewsdesk/translate)
10
10
  and later adapted to rails 3.0 by [Claudius Coenen](https://github.com/ccoenen/rails-translate).
11
- This version is a spinoff of Claudius Coenen's version by [Larry Sprock](https://github.com/lardawge/rails-i18nterface).
11
+ This version is a spin-off of Claudius Coenen's version by [Larry Sprock](https://github.com/lardawge/rails-i18nterface).
12
12
  It was renamed, refactored and prepared for rails 3.1 as an Engine. Over this work
13
13
  [Michal Hantl](https://github.com/hakunin/rails-i18nterface) made a bunch of nice UI modifications
14
- on his fork. Since then it was more or less abandonned.
14
+ on his fork. Since then it was more or less abandoned.
15
15
 
16
16
  I took over the evolution with some new features:
17
17
 
18
18
  * testing using [combustion](https://github.com/pat/combustion) and [rspec](https://github.com/rspec/rspec)
19
19
  * redesign of the layout
20
- * navigation overhaul, spliting the namespaces in a foldable menu
20
+ * navigation overhaul, splitting the name-spaces in a foldable menu
21
21
  * gathering of first-level translations under a ROOT container
22
22
  * gemification and release of a version 0.1.0
23
23
  * (the 0.0.1 was the work from Larry Sprock but was not published as a gem)
24
24
  * compatibility with rails 4 and ruby 2
25
25
 
26
+ Check the [Changelog](https://github.com/mose/rails-i18nterface/blob/master/changelog.md) for details about further changes.
27
+
26
28
  ![rails-i18nterface](http://mose.fr/rails-i18nterface.png)
27
29
 
28
30
  ## Usage
@@ -65,7 +67,7 @@ end
65
67
  (this example is for devise users, but you can adjust it to return true or false
66
68
  according to your own context).
67
69
 
68
- ### Confifuration
70
+ ### Configuration
69
71
 
70
72
  You can configure `from_locales` and `to_locales` explicitly in your
71
73
  `environments/development.rb` by adding
@@ -81,6 +83,8 @@ Where `[:en]` and `[:ja, :es, :fr]` could be replaced by locale list of your cho
81
83
  * extract code from the controller to a lib
82
84
  * refactor the libs in a cleaner way
83
85
  * apply rubocop and follow his law
86
+ * make the application thread-safe
87
+ * remove those damn global variables
84
88
  * extend testing to refactored libs
85
89
  * change navigation to an ajax-driven reload
86
90
  * add a way to gather .one and .other and .few under same translation line
@@ -1,12 +1,14 @@
1
1
  module RailsI18nterface
2
2
  class TranslateController < RailsI18nterface::ApplicationController
3
3
 
4
+ include Utils
5
+
4
6
  before_filter :init_translations
5
7
  before_filter :set_locale
6
8
 
7
9
  def index
8
10
  @dbvalues = {}
9
- initialize_keys
11
+ @keys = initialize_keys
10
12
  load_db_translations
11
13
  @deep_keys = RailsI18nterface::Keys.to_deep_hash(@keys)
12
14
  filter_by_key_pattern
@@ -46,61 +48,15 @@ module RailsI18nterface
46
48
  locale = params[:locale].to_sym
47
49
  keys = {locale => I18n.backend.send(:translations)[locale] || {}}
48
50
  Translation.where(:locale => @to_locale).each { |translation|
49
- next if translation.value == ''
50
- next if !translation.value
51
+ next if !translation.value or translation.value == ''
51
52
  set_nested(keys[locale], translation.key.split("."), translation.value)
52
53
  }
53
54
  remove_blanks keys
54
- yaml = keys_to_yaml(deep_stringify_keys(keys))
55
+ yaml = RailsI18nterface::Yamlfile.new.keys_to_yaml(keys)
55
56
  response.headers['Content-Disposition'] = "attachment; filename=#{locale}.yml"
56
57
  render :text => yaml
57
58
  end
58
59
 
59
- def remove_blanks hash
60
- hash.each { |k, v|
61
- if !v || v == ''
62
- hash.delete k
63
- end
64
- if v.is_a? Hash
65
- remove_blanks v
66
- if v == {}
67
- hash.delete k
68
- end
69
- end
70
- }
71
- end
72
-
73
- def set_nested(hash, key, value)
74
- if key.length == 1
75
- hash[key[0]] = value
76
- else
77
- k = key.shift
78
- set_nested(hash[k] ||= {}, key, value)
79
- end
80
- end
81
-
82
- private
83
-
84
- # Stringifying keys for prettier YAML
85
- def deep_stringify_keys(hash)
86
- hash.inject({}) { |result, (key, value)|
87
- value = deep_stringify_keys(value) if value.is_a? Hash
88
- result[(key.to_s rescue key) || key] = value
89
- result
90
- }
91
- end
92
-
93
- def keys_to_yaml(keys)
94
- # Using ya2yaml, if available, for UTF8 support
95
- if keys.respond_to?(:ya2yaml)
96
- keys.ya2yaml(:escape_as_utf8 => true)
97
- else
98
- keys.to_yaml
99
- end
100
- end
101
-
102
- public
103
-
104
60
  def update
105
61
  params[:key].each { |k, v|
106
62
  t = Translation.where(:key => k, :locale => @to_locale).first
@@ -134,8 +90,8 @@ module RailsI18nterface
134
90
 
135
91
  def initialize_keys
136
92
  @files = RailsI18nterface::Keys.files
137
- @keys = (@files.keys.map(&:to_s) + RailsI18nterface::Keys.new.i18n_keys(@from_locale)).uniq
138
- @keys.reject! do |key|
93
+ keys = (@files.keys.map(&:to_s) + RailsI18nterface::Keys.new.i18n_keys(@from_locale)).uniq
94
+ keys.reject! do |key|
139
95
  from_text = lookup(@from_locale, key)
140
96
  # When translating from one language to another, make sure there is a text to translate from.
141
97
  # Always exclude non string translation objects as we don't support editing them in the UI.
@@ -227,7 +183,7 @@ module RailsI18nterface
227
183
  end
228
184
 
229
185
  def per_page
230
- 50
186
+ params[:per_page] ? params[:per_page].to_i : 50
231
187
  end
232
188
  helper_method :per_page
233
189
 
@@ -1,8 +1,10 @@
1
1
  require "rails-i18nterface/engine"
2
- require "rails-i18nterface/file"
2
+ require "rails-i18nterface/yamlfile"
3
+ require "rails-i18nterface/sourcefiles"
3
4
  require "rails-i18nterface/keys"
4
5
  require "rails-i18nterface/log"
5
6
  require "rails-i18nterface/storage"
7
+ require "rails-i18nterface/utils"
6
8
 
7
9
  module RailsI18nterface
8
10
  end
@@ -1,192 +1,143 @@
1
1
  #require 'pathname'
2
2
 
3
- class RailsI18nterface::Keys
4
- # Allows keys extracted from lookups in files to be cached
5
- def self.files
6
- @@files ||= new.files
7
- end
8
-
9
- def self.names
10
- @@names || new.names
11
- end
12
- # Allows flushing of the files cache
13
- def self.files=(files)
14
- @@files = files
15
- end
16
-
17
- def files
18
- @files ||= extract_files
19
- end
20
- alias_method :to_hash, :files
21
-
22
- def names
23
- @names ||= build_namespaces
24
- end
25
- alias_method :to_tree, :names
3
+ module RailsI18nterface
4
+ class Keys
26
5
 
27
- def keys
28
- files.keys
29
- end
30
- alias_method :to_a, :keys
6
+ # Allows keys extracted from lookups in files to be cached
7
+ def self.files
8
+ @@files ||= new.files
9
+ end
31
10
 
32
- def i18n_keys(locale)
33
- I18n.backend.send(:init_translations) unless I18n.backend.initialized?
34
- self.class.to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort
35
- end
11
+ def self.names
12
+ @@names || new.names
13
+ end
14
+ # Allows flushing of the files cache
15
+ def self.files=(files)
16
+ @@files = files
17
+ end
36
18
 
37
- def untranslated_keys
38
- self.class.translated_locales.inject({}) do |missing, locale|
39
- missing[locale] = i18n_keys(I18n.default_locale).map do |key|
40
- I18n.backend.send(:lookup, locale, key).nil? ? key : nil
41
- end.compact
42
- missing
19
+ def files
20
+ @files ||= RailsI18nterface::Sourcefiles.extract_files
43
21
  end
44
- end
22
+ alias_method :to_hash, :files
45
23
 
46
- def missing_keys
47
- locale = I18n.default_locale
48
- yaml_keys = {}
49
- yaml_keys = RailsI18nterface::Storage.file_paths(locale).inject({}) do |keys, path|
50
- keys = keys.deep_merge(RailsI18nterface::File.new(path).read[locale.to_s])
24
+ def names
25
+ @names ||= i18n_keys
51
26
  end
52
- files.reject { |key, file| self.class.contains_key?(yaml_keys, key) }
53
- end
27
+ alias_method :to_tree, :names
54
28
 
55
- def self.translated_locales
56
- I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) }
57
- end
29
+ def keys
30
+ files.keys
31
+ end
32
+ alias_method :to_a, :keys
58
33
 
59
- # Checks if a nested hash contains the keys in dot separated I18n key.
60
- #
61
- # Example:
62
- #
63
- # hash = {
64
- # :foo => {
65
- # :bar => {
66
- # :baz => 1
67
- # }
68
- # }
69
- # }
70
- #
71
- # contains_key?("foo", key) # => true
72
- # contains_key?("foo.bar", key) # => true
73
- # contains_key?("foo.bar.baz", key) # => true
74
- # contains_key?("foo.bar.baz.bla", key) # => false
75
- #
76
- def self.contains_key?(hash, key)
77
- keys = key.to_s.split(".")
78
- return false if keys.empty?
79
- !keys.inject(HashWithIndifferentAccess.new(hash)) do |memo, key|
80
- memo.is_a?(Hash) ? memo.try(:[], key) : nil
81
- end.nil?
82
- end
34
+ def i18n_keys(locale)
35
+ I18n.backend.send(:init_translations) unless I18n.backend.initialized?
36
+ self.class.to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort
37
+ end
83
38
 
84
- # Convert something like:
85
- #
86
- # {
87
- # :pressrelease => {
88
- # :label => {
89
- # :one => "Pressmeddelande"
90
- # }
91
- # }
92
- # }
93
- #
94
- # to:
95
- #
96
- # {'pressrelease.label.one' => "Pressmeddelande"}
97
- #
98
- def self.to_shallow_hash(hash)
99
- hash.inject({}) do |shallow_hash, (key, value)|
100
- if value.is_a?(Hash)
101
- to_shallow_hash(value).each do |sub_key, sub_value|
102
- shallow_hash[[key, sub_key].join(".")] = sub_value
103
- end
104
- else
105
- shallow_hash[key.to_s] = value
39
+ def untranslated_keys
40
+ self.class.translated_locales.inject({}) do |missing, locale|
41
+ missing[locale] = i18n_keys(I18n.default_locale).map do |key|
42
+ I18n.backend.send(:lookup, locale, key).nil? ? key : nil
43
+ end.compact
44
+ missing
106
45
  end
107
- shallow_hash
108
46
  end
109
- end
110
47
 
111
- # Convert something like:
112
- #
113
- # {'pressrelease.label.one' => "Pressmeddelande"}
114
- #
115
- # to:
116
- #
117
- # {
118
- # :pressrelease => {
119
- # :label => {
120
- # :one => "Pressmeddelande"
121
- # }
122
- # }
123
- # }
124
- def self.to_deep_hash(hash)
125
- hash.inject({}) do |deep_hash, (key, value)|
126
- keys = key.to_s.split('.').reverse
127
- leaf_key = keys.shift
128
- key_hash = keys.inject({leaf_key.to_sym => value}) { |hash, key| {key.to_sym => hash} }
129
- deep_merge!(deep_hash, key_hash)
130
- deep_hash
48
+ def missing_keys
49
+ locale = I18n.default_locale
50
+ yaml_keys = {}
51
+ yaml_keys = Storage.file_paths(locale).inject({}) do |keys, path|
52
+ keys = keys.deep_merge(Yamlfile.new(path).read[locale.to_s])
53
+ end
54
+ files.reject { |key, file| self.class.contains_key?(yaml_keys, key) }
131
55
  end
132
- end
133
56
 
134
- # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
135
- def self.deep_merge!(hash1, hash2)
136
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
137
- hash1.merge!(hash2, &merger)
138
- end
57
+ def self.translated_locales
58
+ I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) }
59
+ end
139
60
 
140
- private
61
+ # Checks if a nested hash contains the keys in dot separated I18n key.
62
+ #
63
+ # Example:
64
+ #
65
+ # hash = {
66
+ # :foo => {
67
+ # :bar => {
68
+ # :baz => 1
69
+ # }
70
+ # }
71
+ # }
72
+ #
73
+ # contains_key?("foo", key) # => true
74
+ # contains_key?("foo.bar", key) # => true
75
+ # contains_key?("foo.bar.baz", key) # => true
76
+ # contains_key?("foo.bar.baz.bla", key) # => false
77
+ #
78
+ def self.contains_key?(hash, key)
79
+ keys = key.to_s.split(".")
80
+ return false if keys.empty?
81
+ !keys.inject(HashWithIndifferentAccess.new(hash)) do |memo, key|
82
+ memo.is_a?(Hash) ? memo.try(:[], key) : nil
83
+ end.nil?
84
+ end
141
85
 
142
- def extract_files
143
- files_to_scan.inject(HashWithIndifferentAccess.new) do |files, file|
144
- begin#hack to avoid UTF-8 error
145
- IO.read(file).scan(i18n_lookup_pattern).flatten.map(&:to_sym).each do |key|
146
- path = Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(Rails.root)).to_s
147
- #puts path
148
- if key[0] == '.'
149
- key = guess_namespace(path) + key.to_s
86
+ # Convert something like:
87
+ #
88
+ # {
89
+ # :pressrelease => {
90
+ # :label => {
91
+ # :one => "Pressmeddelande"
92
+ # }
93
+ # }
94
+ # }
95
+ #
96
+ # to:
97
+ #
98
+ # {'pressrelease.label.one' => "Pressmeddelande"}
99
+ #
100
+ def self.to_shallow_hash(hash)
101
+ hash.inject({}) do |shallow_hash, (key, value)|
102
+ if value.is_a?(Hash)
103
+ to_shallow_hash(value).each do |sub_key, sub_value|
104
+ shallow_hash[[key, sub_key].join(".")] = sub_value
150
105
  end
151
- #puts key
152
- #puts
153
- files[key] ||= []
154
- files[key] << path if !files[key].include?(path)
106
+ else
107
+ shallow_hash[key.to_s] = value
155
108
  end
156
- rescue Exception => e
157
- puts e.inspect
158
- puts e.backtrace
159
- puts "bug in Translation plugin, please debug, informations :"
160
- puts file.inspect
161
- puts i18n_lookup_pattern.inspect
109
+ shallow_hash
162
110
  end
163
- files
164
111
  end
165
- end
166
112
 
167
- def guess_namespace(path)
168
- parts = path.split(/\//)
169
- case parts[0]
170
- when 'app'
171
- parts.shift
172
- if parts[0] == 'views'
173
- parts.shift
174
- parts[-1].gsub!(/\.(erb|haml|slim)$/,'')
113
+ # Convert something like:
114
+ #
115
+ # {'pressrelease.label.one' => "Pressmeddelande"}
116
+ #
117
+ # to:
118
+ #
119
+ # {
120
+ # :pressrelease => {
121
+ # :label => {
122
+ # :one => "Pressmeddelande"
123
+ # }
124
+ # }
125
+ # }
126
+ def self.to_deep_hash(hash)
127
+ hash.inject({}) do |deep_hash, (key, value)|
128
+ keys = key.to_s.split('.').reverse
129
+ leaf_key = keys.shift
130
+ key_hash = keys.inject({leaf_key.to_sym => value}) { |hash, key| {key.to_sym => hash} }
131
+ deep_merge!(deep_hash, key_hash)
132
+ deep_hash
175
133
  end
176
134
  end
177
- parts.join('.')
178
- end
179
135
 
180
- def build_namespaces
181
- i18n_keys
182
- end
183
-
184
- def i18n_lookup_pattern
185
- /\b(?:I18n\.t|I18n\.translate|t)(?:\s|\():?(?:'|")(\.?[a-z0-9_\.]+)(?:'|")/
186
- end
136
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
137
+ def self.deep_merge!(hash1, hash2)
138
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
139
+ hash1.merge!(hash2, &merger)
140
+ end
187
141
 
188
- def files_to_scan
189
- Dir.glob(File.join(RailsI18nterface::Storage.root_dir, "{app,config,lib}", "**","*.{rb,erb,haml,slim,rhtml}")) +
190
- Dir.glob(File.join(RailsI18nterface::Storage.root_dir, "{public,app/assets}", "javascripts", "**","*.{js,coffee}"))
191
142
  end
192
- end
143
+ end