rails-i18nterface 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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