translations_sync 0.4.5 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +13 -0
- data/README +72 -47
- data/Rakefile +1 -1
- data/lib/tasks/translations_sync.rake +15 -9
- data/lib/translations_sync.rb +69 -21
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42096ed5df2d1d00a7071691ae3f9b61348b565b
|
4
|
+
data.tar.gz: b84217b76307b0ce2102ac99a906739f96d51e5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12153a22337d9e26444b2721904993537ce3451bc52f83b72effd6626a561f5804d1c198d85899a2b39f15568038dc22fcb06582633d6f5207c33ae294137fdd
|
7
|
+
data.tar.gz: 66f9a4a78afaf838b40498665ef4057483fade91cc2a07d020d5f056faa3fe090f83567280075993fe37529eaca0b5a7c0f2b91fa614dfef04476c468f5e7848
|
data/Changelog
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
2016-06-17 v.0.4.7
|
2
|
+
* Parameter IGNORE is added
|
3
|
+
* Documentation is refised
|
4
|
+
|
5
|
+
2016-06-17 v.0.4.6
|
6
|
+
* The locale may be not only suffix, but also directory
|
7
|
+
|
8
|
+
2014-12-19 v.0.4.5
|
9
|
+
* Ignore gem faker and use I18n.available_locales as default list of locales
|
10
|
+
|
11
|
+
2014-12-19 v.0.4.4
|
12
|
+
* skipped
|
13
|
+
|
1
14
|
2014-05-20 v.0.4.3
|
2
15
|
* Dot can be used as separator between name and locale instead of underscore
|
3
16
|
|
data/README
CHANGED
@@ -1,74 +1,99 @@
|
|
1
1
|
TranslationsSync
|
2
2
|
================
|
3
3
|
|
4
|
-
This
|
5
|
-
the project that uses yaml based locales, in particular, I18n.
|
4
|
+
This gem is intended to help the developer to synchronize the different
|
5
|
+
locales for the project that uses yaml based locales, in particular, I18n.
|
6
6
|
|
7
7
|
|
8
8
|
Requirements
|
9
|
-
|
10
|
-
|
11
|
-
gem 'ya2yaml'
|
9
|
+
------------
|
12
10
|
|
11
|
+
gem 'ya2yaml'
|
12
|
+
gem 'active_support'
|
13
13
|
|
14
14
|
Installation
|
15
|
-
|
15
|
+
------------
|
16
|
+
|
17
|
+
1. Add to your Gemfile
|
16
18
|
|
17
|
-
|
18
|
-
rails plugin install http://github.com/dima4p/translations_sync/
|
19
|
+
gem 'translations_sync'
|
19
20
|
|
20
|
-
2.
|
21
|
-
gem 'translations_sync'
|
21
|
+
2. If you are using the gem without bundle just install it
|
22
22
|
|
23
|
-
|
24
|
-
the rake file into your project's directory lib/tasks.
|
23
|
+
gem install translations_sync
|
25
24
|
|
26
|
-
|
25
|
+
Then execute the following command to copy the rake file into your
|
26
|
+
project's directory lib/tasks.
|
27
27
|
|
28
|
-
|
28
|
+
translations_sync
|
29
29
|
|
30
|
-
|
30
|
+
Or, if you keep your rake tasks in other place, you can give the argument
|
31
|
+
with the proper path
|
32
|
+
|
33
|
+
translations_sync path/to/directory
|
31
34
|
|
32
35
|
|
33
36
|
Description
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
The
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
37
|
+
-----------
|
38
|
+
|
39
|
+
This gem allows different organizations of translation files. They can be
|
40
|
+
grouped in the directories that correspond to locales, or the locale
|
41
|
+
may be defined in the suffix of a file name separated by a dot or underscore.
|
42
|
+
Let us call the file name without locale suffix and extension as
|
43
|
+
**base name**
|
44
|
+
|
45
|
+
When a file name is to be given as parameter in the description below
|
46
|
+
it should not include nor locale prefix, nor locale suffix and extension
|
47
|
+
whichever organization is used.
|
48
|
+
|
49
|
+
The main goal of the gem to assist in managing the translations for the
|
50
|
+
project. This can be done by using the `rake` tasks described below.
|
51
|
+
|
52
|
+
The following parameters can be given:
|
53
|
+
|
54
|
+
* `LIST=comma,separated,list` specifies the locales that should
|
55
|
+
participate in synchronization.
|
56
|
+
For example, `LIST=en,de,fr,zh-CN`
|
57
|
+
If omitted, I18n.available_locales will be used.
|
58
|
+
The order of the locales is important as the existing for the first
|
59
|
+
locale in the list will be provided for a missing translation(s).
|
60
|
+
The locale in LIST must not be present in I18n.available_locales.
|
61
|
+
This allows easily to add new locales to the project.
|
62
|
+
* `EXCLUDE=comma,separated,list` specifies the locales that should NOT participate.
|
63
|
+
* `NAME=name`. By default missing translations are written to the
|
64
|
+
**base name** "missing".
|
65
|
+
This parameter tells to use the given name as **base name**.
|
66
|
+
If any of the corresponding files exist, the missing translations will
|
67
|
+
be added to them.
|
68
|
+
* `SOURCE=name`. Only files with the given **base name** will be considered.
|
69
|
+
* `IN=name`. It is equivalent to `NAME=name SOURCE=name`
|
70
|
+
* `KEY=path.to.key`. Points to the key to be moved or removed.
|
71
|
+
Obviously, it should not include locale.
|
72
|
+
* `TO=path.to.key`.
|
73
|
+
|
74
|
+
Rake tasks
|
75
|
+
----------
|
76
|
+
|
77
|
+
### rake translations:sync
|
78
|
+
|
79
|
+
This task verifies that all the translation keys are present in all
|
80
|
+
files specifed by the given parameters and if any is missing creates/updates
|
81
|
+
corresponding file(s).
|
82
|
+
|
83
|
+
### rake translations:singles
|
57
84
|
|
58
85
|
This task generates a single file config/locales/singles.yml that contains the
|
59
|
-
translations
|
86
|
+
translations occurring only in one locale.
|
60
87
|
|
61
|
-
|
88
|
+
### rake translations:move KEY=key.to.move TO=where.to.move
|
62
89
|
|
63
90
|
This task moves the content of given KEY under the TO.
|
64
|
-
You can use all the parameters available for the translations:sync task
|
65
|
-
value for the NAME equal to 'moved'.
|
66
|
-
|
67
|
-
4. rake translations:remove KEY=key.to.remove
|
91
|
+
You can use all the parameters available for the translations:sync task
|
92
|
+
with the default value for the NAME equal to 'moved'.
|
68
93
|
|
69
|
-
|
94
|
+
### rake translations:remove KEY=key.to.remove
|
70
95
|
|
71
|
-
|
96
|
+
This task removes the key from the translations. NAME defaults to 'removed' here.
|
72
97
|
|
73
98
|
|
74
|
-
Copyright (c) 2010-
|
99
|
+
Copyright (c) 2010-2016 Dmitri Koulikoff, released under the MIT license
|
data/Rakefile
CHANGED
@@ -5,13 +5,19 @@ namespace :translations do
|
|
5
5
|
|
6
6
|
def get_ts(skip_source = false)
|
7
7
|
source = skip_source ? nil : ENV['SOURCE'] || ENV['IN']
|
8
|
-
|
8
|
+
params = {}
|
9
|
+
params[:list] = ENV['LIST']
|
10
|
+
params[:exclude] = ENV['EXCLUDE']
|
11
|
+
params[:source] = ENV['SOURCE'] || ENV['IN'] unless skip_source
|
12
|
+
params[:ignore] = ENV['IGNORE']
|
13
|
+
TranslationsSync.new params
|
9
14
|
end
|
10
15
|
|
11
|
-
def
|
16
|
+
def save_moved_files(ts, default_name)
|
17
|
+
translations = ts.moved
|
12
18
|
name = ENV['NAME'] || ENV['IN'] || default_name
|
13
19
|
translations.keys.sort.each do |lang|
|
14
|
-
filename =
|
20
|
+
filename = ts.filename_for name, lang
|
15
21
|
print filename + ' ... '
|
16
22
|
if File.exist? filename
|
17
23
|
status = 'updated'
|
@@ -30,8 +36,7 @@ namespace :translations do
|
|
30
36
|
ts = get_ts
|
31
37
|
name = ENV['NAME'] || ENV['IN'] || 'missing'
|
32
38
|
ts.missing.keys.sort.each do |lang|
|
33
|
-
filename =
|
34
|
-
"#{name}#{ts.separator}#{lang}.yml"
|
39
|
+
filename = ts.filename_for name, lang
|
35
40
|
print filename + ' ... '
|
36
41
|
if File.exist? filename
|
37
42
|
hash = YAML::load(File.open(filename))
|
@@ -52,7 +57,7 @@ namespace :translations do
|
|
52
57
|
desc "Detects the translations existing only in one locale" + PARAMS
|
53
58
|
task :singles => :environment do
|
54
59
|
ts = get_ts false
|
55
|
-
filename =
|
60
|
+
filename = ts.filename_for 'singles', nil
|
56
61
|
if ts.singles.size > 0
|
57
62
|
File.open(filename, "w") do |file|
|
58
63
|
file.write(TranslationsSync.to_yaml ts.singles)
|
@@ -66,9 +71,10 @@ namespace :translations do
|
|
66
71
|
desc "Moves the key in the translations" + PARAMS + " KEY=key.to.move TO=where.to.move IN=filespec"
|
67
72
|
task :move => :environment do
|
68
73
|
key = ENV['KEY'] or raise "Parameter KEY must be given"
|
74
|
+
to = ENV['TO'] or raise "Parameter TO must be given"
|
69
75
|
ts = get_ts
|
70
|
-
if ts.move key,
|
71
|
-
|
76
|
+
if ts.move key, to
|
77
|
+
save_moved_files ts, 'moved'
|
72
78
|
else
|
73
79
|
puts "The key \"#{key}\" was not found"
|
74
80
|
end
|
@@ -79,7 +85,7 @@ namespace :translations do
|
|
79
85
|
key = ENV['KEY'] or raise "Parameter KEY must be given"
|
80
86
|
ts = get_ts
|
81
87
|
if ts.remove key
|
82
|
-
|
88
|
+
save_moved_files ts, 'removed'
|
83
89
|
else
|
84
90
|
puts "The key \"#{key}\" was not found"
|
85
91
|
end
|
data/lib/translations_sync.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'ya2yaml'
|
3
3
|
require 'i18n'
|
4
|
+
require 'active_support/hash_with_indifferent_access'
|
4
5
|
|
5
6
|
class Hash
|
6
7
|
def stringify_keys!
|
@@ -22,6 +23,7 @@ end
|
|
22
23
|
class TranslationsSync
|
23
24
|
|
24
25
|
attr_accessor :translations, :list
|
26
|
+
attr_reader :flat
|
25
27
|
EXCLUDE_LIST = ''
|
26
28
|
TAIL = '=TODO'
|
27
29
|
PKORDER = {'zero' => 0, 'one' => 1, 'two' => 2, 'few' => 3, 'many' => 5, 'other' => 9}
|
@@ -53,9 +55,17 @@ class TranslationsSync
|
|
53
55
|
end
|
54
56
|
end # class << self
|
55
57
|
|
56
|
-
def initialize(
|
57
|
-
|
58
|
-
|
58
|
+
def initialize(*args)
|
59
|
+
params = args.pop if args.last.is_a? Hash
|
60
|
+
params = (params || {}).with_indifferent_access
|
61
|
+
unless args.size == 0
|
62
|
+
list, exclude, source = agrs
|
63
|
+
puts 'Deprecation warning: a Hash should be used to pass paramteters'
|
64
|
+
end
|
65
|
+
list ||= params[:list]
|
66
|
+
exclude ||= params[:exclude]
|
67
|
+
source ||= params[:source]
|
68
|
+
ignore = params[:ignore]
|
59
69
|
@full_list = list ? list.split(',').map(&:to_sym) : I18n.available_locales
|
60
70
|
@full_list = @full_list.uniq
|
61
71
|
exclude = (exclude || EXCLUDE_LIST).split(',').map(&:to_sym)
|
@@ -79,20 +89,29 @@ class TranslationsSync
|
|
79
89
|
acc
|
80
90
|
end
|
81
91
|
|
92
|
+
translations_path_re = Regexp.new "#{translations_dir}(\\/[a-z]{2}(?:-[A-Z]{2})?)?\\/[-_/0-9a-zA-Z]+(?:(_|.)[a-z]{2}(?:-[A-Z]{2})?)?\\.(?:yml|rb)\\Z"
|
93
|
+
I18n.load_path.find do |path|
|
94
|
+
path.match translations_path_re
|
95
|
+
end
|
96
|
+
@prefix = $1 or @separator = $2
|
97
|
+
|
82
98
|
if source
|
83
|
-
|
99
|
+
translations_path_re = Regexp.new "#{translations_dir}(\\/[a-z]{2}(?:-[A-Z]{2})?)?\\/#{Regexp.escape source}(?:(_|.)[a-z]{2}(?:-[A-Z]{2})?)?\\.(?:yml|rb)\\Z"
|
84
100
|
I18n.load_path.reject! do |path|
|
85
|
-
path !~
|
101
|
+
path !~ translations_path_re
|
86
102
|
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
103
|
+
end
|
104
|
+
|
105
|
+
if ignore
|
106
|
+
translations_path_re = Regexp.new "#{translations_dir}#{'\\/[^/]+' if @prefix}\\/#{Regexp.escape ignore}"
|
107
|
+
I18n.load_path.reject! do |path|
|
108
|
+
path =~ translations_path_re
|
92
109
|
end
|
93
|
-
I18n.backend.send(:init_translations)
|
94
110
|
end
|
95
111
|
|
112
|
+
I18n.reload!
|
113
|
+
I18n.backend.send(:init_translations)
|
114
|
+
translations = I18n.backend.send :translations
|
96
115
|
@flat = {}
|
97
116
|
@list.each do |lang|
|
98
117
|
flatten_keys(lang, translations[lang] || {}, @flat)
|
@@ -108,7 +127,7 @@ class TranslationsSync
|
|
108
127
|
unless @locales_with_missing
|
109
128
|
size = list.size
|
110
129
|
@locales_with_missing = []
|
111
|
-
|
130
|
+
flat.each_pair do |key, val|
|
112
131
|
if val.size < size
|
113
132
|
(@locales_with_missing += list - val.keys).uniq!
|
114
133
|
break if @locales_with_missing.size == size
|
@@ -124,7 +143,7 @@ class TranslationsSync
|
|
124
143
|
locales_with_missing.each do |lang|
|
125
144
|
@missing[lang] = {}
|
126
145
|
end
|
127
|
-
|
146
|
+
flat.each_pair do |key, val|
|
128
147
|
(locales_with_missing - val.keys).each do |lang|
|
129
148
|
push_to_hash @missing[lang], lang, key, val, :missing
|
130
149
|
end
|
@@ -138,7 +157,7 @@ class TranslationsSync
|
|
138
157
|
unless @locales_with_singles
|
139
158
|
size = list.size
|
140
159
|
@locales_with_singles = []
|
141
|
-
|
160
|
+
flat.each_pair do |key, val|
|
142
161
|
if val.size < size
|
143
162
|
(@locales_with_singles += val.keys).uniq! if val.size == 1
|
144
163
|
break if @locales_with_singles.size == size
|
@@ -154,7 +173,7 @@ class TranslationsSync
|
|
154
173
|
locales_with_singles.each do |lang|
|
155
174
|
@singles[lang] = {}
|
156
175
|
end
|
157
|
-
|
176
|
+
flat.each_pair do |key, val|
|
158
177
|
lang = val.keys.first
|
159
178
|
push_to_hash @singles[lang], lang, key, val, :singles if val.size == 1
|
160
179
|
end
|
@@ -170,14 +189,17 @@ class TranslationsSync
|
|
170
189
|
destination ||= ''
|
171
190
|
destination = destination.split('.').map(&:to_sym)
|
172
191
|
destination << key.last if destination.size == 0
|
192
|
+
puts "key=#{key.inspect} destination=#{destination.inspect}"
|
173
193
|
result = false
|
174
|
-
|
194
|
+
flat.each_pair do |array, val|
|
175
195
|
if array[0, key_length] == key
|
176
196
|
array[0, key_length] = destination
|
197
|
+
puts array.inspect
|
177
198
|
result = true
|
178
199
|
end
|
179
200
|
end
|
180
201
|
@moved = nil
|
202
|
+
puts result
|
181
203
|
result
|
182
204
|
end
|
183
205
|
|
@@ -187,7 +209,8 @@ class TranslationsSync
|
|
187
209
|
@list.each do |lang|
|
188
210
|
@moved[lang] = {}
|
189
211
|
end
|
190
|
-
|
212
|
+
flat.each_pair do |key, val|
|
213
|
+
puts key.inspect
|
191
214
|
val.keys.each do |lang|
|
192
215
|
push_to_hash @moved[lang], lang, key, val, :moved
|
193
216
|
end
|
@@ -204,7 +227,7 @@ class TranslationsSync
|
|
204
227
|
key = key.split('.').map(&:to_sym)
|
205
228
|
key_length = key.length
|
206
229
|
result = false
|
207
|
-
|
230
|
+
flat.reject! do |array, val|
|
208
231
|
r = array[0, key_length] == key
|
209
232
|
result ||= r
|
210
233
|
r
|
@@ -213,8 +236,16 @@ class TranslationsSync
|
|
213
236
|
result
|
214
237
|
end
|
215
238
|
|
216
|
-
def
|
217
|
-
|
239
|
+
def filename_for(name, lang = nil)
|
240
|
+
if lang
|
241
|
+
if @prefix
|
242
|
+
"#{translations_dir}/#{lang}/#{name}.yml"
|
243
|
+
else
|
244
|
+
"#{translations_dir}/#{name}#{@separator}#{lang}.yml"
|
245
|
+
end
|
246
|
+
else
|
247
|
+
"#{translations_dir}/#{name}.yml"
|
248
|
+
end
|
218
249
|
end
|
219
250
|
|
220
251
|
private
|
@@ -277,11 +308,28 @@ class TranslationsSync
|
|
277
308
|
value.stringify_keys! if value.is_a? Hash
|
278
309
|
h[key.to_s] = value
|
279
310
|
when :moved
|
280
|
-
value = val[target]
|
311
|
+
value = val[target]
|
312
|
+
raise "The translations are not synchronized for #{keys.inspect}" if value.nil?
|
281
313
|
value.stringify_keys! if value.is_a? Hash
|
282
314
|
h[key.to_s] = value
|
283
315
|
end
|
284
316
|
keys.push key
|
285
317
|
end
|
286
318
|
|
319
|
+
def translations_dir
|
320
|
+
@translations_dir ||=
|
321
|
+
common_prefix(I18n.config.load_path.grep Regexp.new FileUtils.pwd)
|
322
|
+
end
|
323
|
+
|
324
|
+
def common_prefix(paths)
|
325
|
+
return '' if paths.empty?
|
326
|
+
return paths.first.split('/').slice(0...-1).join('/') if paths.length <= 1
|
327
|
+
arr = paths.sort
|
328
|
+
first = arr.first.split('/')
|
329
|
+
last = arr.last.split('/')
|
330
|
+
i = 0
|
331
|
+
i += 1 while first[i] == last[i] && i <= first.length
|
332
|
+
first.slice(0, i).join('/')
|
333
|
+
end
|
334
|
+
|
287
335
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: translations_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitri Koulikoff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: ya2yaml
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,8 +75,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
75
|
version: '0'
|
62
76
|
requirements: []
|
63
77
|
rubyforge_project:
|
64
|
-
rubygems_version: 2.
|
78
|
+
rubygems_version: 2.5.1
|
65
79
|
signing_key:
|
66
80
|
specification_version: 4
|
67
|
-
summary: Synchronizes the different locales represeinted in yaml for
|
81
|
+
summary: Synchronizes the different locales translations represeinted in yaml for
|
82
|
+
I18n
|
68
83
|
test_files: []
|