rails_translation_manager 0.1.0 → 1.1.2
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +20 -0
- data/Jenkinsfile +3 -1
- data/Rakefile +13 -7
- data/config/locales/plurals.rb +49 -0
- data/lib/rails_translation_manager/cleaner.rb +14 -0
- data/lib/rails_translation_manager/i18n_tasks_option_parser.rb +10 -0
- data/lib/rails_translation_manager/importer.rb +32 -14
- data/lib/rails_translation_manager/locale_checker/all_locales.rb +61 -0
- data/lib/rails_translation_manager/locale_checker/base_checker.rb +13 -0
- data/lib/rails_translation_manager/locale_checker/incompatible_plurals.rb +79 -0
- data/lib/rails_translation_manager/locale_checker/locale_checker_helper.rb +23 -0
- data/lib/rails_translation_manager/locale_checker/missing_english_locales.rb +31 -0
- data/lib/rails_translation_manager/locale_checker/missing_foreign_locales.rb +31 -0
- data/lib/rails_translation_manager/locale_checker/plural_forms.rb +16 -0
- data/lib/rails_translation_manager/locale_checker.rb +50 -0
- data/lib/rails_translation_manager/version.rb +1 -1
- data/lib/rails_translation_manager.rb +21 -3
- data/lib/tasks/translation.rake +43 -42
- data/rails_translation_manager.gemspec +6 -2
- data/spec/locales/cleaner/clean.yml +5 -0
- data/spec/locales/cleaner/with_whitespace.yml +5 -0
- data/spec/locales/importer/fr.csv +8 -0
- data/spec/locales/importer/hy_with_byte_order_mark.csv +4 -0
- data/spec/locales/in_sync/cy/browse.yml +12 -0
- data/spec/locales/in_sync/en/browse.yml +8 -0
- data/spec/locales/out_of_sync/cy.yml +3 -0
- data/spec/locales/out_of_sync/en.yml +6 -0
- data/spec/rails_translation_manager/cleaner_spec.rb +13 -0
- data/spec/rails_translation_manager/importer_spec.rb +93 -0
- data/spec/rails_translation_manager/locale_checker/all_locales_spec.rb +24 -0
- data/spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb +94 -0
- data/spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb +61 -0
- data/spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb +72 -0
- data/spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb +80 -0
- data/spec/rails_translation_manager/locale_checker/plural_forms_spec.rb +27 -0
- data/spec/rails_translation_manager/locale_checker_spec.rb +68 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/tasks.rb +7 -0
- data/spec/tasks/translation_spec.rb +127 -0
- data/test/rails_translation_manager/yaml_writer_test.rb +2 -0
- data/tmp/.gitkeep +0 -0
- metadata +117 -18
- data/lib/rails_translation_manager/stealer.rb +0 -85
- data/lib/rails_translation_manager/validator.rb +0 -92
- data/test/rails_translation_manager/importer_test.rb +0 -132
- data/test/rails_translation_manager/stealer_test.rb +0 -251
- data/test/rails_translation_manager/validator_test.rb +0 -51
@@ -1,132 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "rails_translation_manager/importer"
|
3
|
-
require "tmpdir"
|
4
|
-
require "csv"
|
5
|
-
|
6
|
-
module RailsTranslationManager
|
7
|
-
class ImporterTest < Minitest::Test
|
8
|
-
test 'should create a new locale file for a filled in translation csv file' do
|
9
|
-
given_csv(:fr,
|
10
|
-
[:key, :source, :translation],
|
11
|
-
["world_location.type.country", "Country", "Pays"],
|
12
|
-
["world_location.country", "Germany", "Allemange"],
|
13
|
-
["other.nested.key", "original", "translated"]
|
14
|
-
)
|
15
|
-
|
16
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
17
|
-
|
18
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
19
|
-
expected = {"fr" => {
|
20
|
-
"world_location" => {
|
21
|
-
"country" => "Allemange",
|
22
|
-
"type" => {
|
23
|
-
"country" => "Pays"
|
24
|
-
}
|
25
|
-
},
|
26
|
-
"other" => {
|
27
|
-
"nested" => {
|
28
|
-
"key" => "translated"
|
29
|
-
}
|
30
|
-
}
|
31
|
-
}}
|
32
|
-
assert_equal expected, yaml_translation_data
|
33
|
-
end
|
34
|
-
|
35
|
-
test 'imports arrays from CSV as arrays' do
|
36
|
-
given_csv(:fr,
|
37
|
-
[:key, :source, :translation],
|
38
|
-
["fruit", ["Apples", "Bananas", "Pears"], ["Pommes", "Bananes", "Poires"]]
|
39
|
-
)
|
40
|
-
|
41
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
42
|
-
|
43
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
44
|
-
expected = {"fr" => {
|
45
|
-
"fruit" => ["Pommes", "Bananes", "Poires"]
|
46
|
-
}}
|
47
|
-
assert_equal expected, yaml_translation_data
|
48
|
-
end
|
49
|
-
|
50
|
-
test 'interprets string "nil" as nil' do
|
51
|
-
given_csv(:fr,
|
52
|
-
[:key, :source, :translation],
|
53
|
-
["things", ["one", nil, "two"], ["une", nil, "deux"]]
|
54
|
-
)
|
55
|
-
|
56
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
57
|
-
|
58
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
59
|
-
expected = {"fr" => {
|
60
|
-
"things" => ["une", nil, "deux"]
|
61
|
-
}}
|
62
|
-
assert_equal expected, yaml_translation_data
|
63
|
-
end
|
64
|
-
|
65
|
-
test 'interprets string ":thing" as symbol' do
|
66
|
-
given_csv(:fr,
|
67
|
-
[:key, :source, :translation],
|
68
|
-
["sentiment", ":whatever", ":bof"]
|
69
|
-
)
|
70
|
-
|
71
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
72
|
-
|
73
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
74
|
-
expected = {"fr" => {
|
75
|
-
"sentiment" => :bof
|
76
|
-
}}
|
77
|
-
assert_equal expected, yaml_translation_data
|
78
|
-
end
|
79
|
-
|
80
|
-
test 'interprets integer strings as integers' do
|
81
|
-
given_csv(:fr,
|
82
|
-
[:key, :source, :translation],
|
83
|
-
["price", "123", "123"]
|
84
|
-
)
|
85
|
-
|
86
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
87
|
-
|
88
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
89
|
-
expected = {"fr" => {
|
90
|
-
"price" => 123
|
91
|
-
}}
|
92
|
-
assert_equal expected, yaml_translation_data
|
93
|
-
end
|
94
|
-
|
95
|
-
test 'interprets boolean values as booleans, not strings' do
|
96
|
-
given_csv(:fr,
|
97
|
-
[:key, :source, :translation],
|
98
|
-
["key1", "is true", "true"],
|
99
|
-
["key2", "is false", "false"]
|
100
|
-
)
|
101
|
-
|
102
|
-
Importer.new(:fr, csv_path(:fr), import_directory).import
|
103
|
-
|
104
|
-
yaml_translation_data = YAML.load_file(File.join(import_directory, "fr.yml"))
|
105
|
-
expected = {"fr" => {
|
106
|
-
"key1" => true,
|
107
|
-
"key2" => false
|
108
|
-
}}
|
109
|
-
assert_equal expected, yaml_translation_data
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def csv_path(locale)
|
115
|
-
File.join(import_directory, "#{locale}.csv")
|
116
|
-
end
|
117
|
-
|
118
|
-
def given_csv(locale, header_row, *rows)
|
119
|
-
csv = CSV.generate do |csv|
|
120
|
-
csv << CSV::Row.new(["key", "source", "translation"], ["key", "source", "translation"], true)
|
121
|
-
rows.each do |row|
|
122
|
-
csv << CSV::Row.new(["key", "source", "translation"], row)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
File.open(csv_path(locale), "w") { |f| f.write csv.to_s }
|
126
|
-
end
|
127
|
-
|
128
|
-
def import_directory
|
129
|
-
@import_directory ||= Dir.mktmpdir
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
@@ -1,251 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
require "rails_translation_manager/stealer"
|
4
|
-
require "fileutils"
|
5
|
-
require "tmpdir"
|
6
|
-
require "csv"
|
7
|
-
require "i18n"
|
8
|
-
|
9
|
-
module RailsTranslationManager
|
10
|
-
class StealerTest < Minitest::Test
|
11
|
-
|
12
|
-
test "converts subtree of items to the same depth" do
|
13
|
-
|
14
|
-
original = {
|
15
|
-
"fr" => {
|
16
|
-
"document" => {
|
17
|
-
"type" => {
|
18
|
-
"type1" => 'premier genre',
|
19
|
-
"type2" => 'deuxième genre',
|
20
|
-
"type3" => 'troisième genre'
|
21
|
-
}
|
22
|
-
}
|
23
|
-
}
|
24
|
-
}
|
25
|
-
|
26
|
-
conversion_mapping = {
|
27
|
-
"document.type" => "content_item.format",
|
28
|
-
}
|
29
|
-
|
30
|
-
expected = {
|
31
|
-
"fr" => {
|
32
|
-
"content_item" => {
|
33
|
-
"format" => {
|
34
|
-
"type1" => 'premier genre',
|
35
|
-
"type2" => 'deuxième genre',
|
36
|
-
"type3" => 'troisième genre'
|
37
|
-
}
|
38
|
-
}
|
39
|
-
}
|
40
|
-
}
|
41
|
-
stealer_test(original, conversion_mapping, expected)
|
42
|
-
end
|
43
|
-
|
44
|
-
test "converts a subtree of items to a different depth" do
|
45
|
-
original = {
|
46
|
-
"fr" => {
|
47
|
-
"document" => {
|
48
|
-
"published" => 'publiée',
|
49
|
-
}
|
50
|
-
}
|
51
|
-
}
|
52
|
-
conversion_mapping = {
|
53
|
-
"document.published" => "content_item.metadata.published"
|
54
|
-
}
|
55
|
-
|
56
|
-
expected = {
|
57
|
-
"fr" => {
|
58
|
-
"content_item" => {
|
59
|
-
"metadata" => {
|
60
|
-
"published" => 'publiée'
|
61
|
-
}
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
|
-
stealer_test(original, conversion_mapping, expected)
|
67
|
-
end
|
68
|
-
|
69
|
-
test "combines multiple mappings" do
|
70
|
-
original = {
|
71
|
-
"fr" => {
|
72
|
-
"document" => {
|
73
|
-
"type" => {
|
74
|
-
"type1" => 'premier genre',
|
75
|
-
},
|
76
|
-
"published" => 'publiée',
|
77
|
-
}
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
conversion_mapping = {
|
82
|
-
"document.type" => "content_item.format",
|
83
|
-
"document.published" => "content_item.metadata.published"
|
84
|
-
}
|
85
|
-
expected = {
|
86
|
-
"fr" => {
|
87
|
-
"content_item" => {
|
88
|
-
"format" => {
|
89
|
-
"type1" => 'premier genre',
|
90
|
-
},
|
91
|
-
"metadata" => {
|
92
|
-
"published" => 'publiée',
|
93
|
-
}
|
94
|
-
}
|
95
|
-
}
|
96
|
-
}
|
97
|
-
stealer_test(original, conversion_mapping, expected)
|
98
|
-
end
|
99
|
-
|
100
|
-
test "does not copy over keys with no mapping" do
|
101
|
-
original = {
|
102
|
-
"fr" => {
|
103
|
-
"document" => {
|
104
|
-
"published" => 'publiée',
|
105
|
-
"do_not_want" => 'non voulu'
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
109
|
-
conversion_mapping = {
|
110
|
-
"document.published" => "content_item.metadata.published"
|
111
|
-
}
|
112
|
-
|
113
|
-
expected = {
|
114
|
-
"fr" => {
|
115
|
-
"content_item" => {
|
116
|
-
"metadata" => {
|
117
|
-
"published" => 'publiée'
|
118
|
-
}
|
119
|
-
}
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
|
-
stealer_test(original, conversion_mapping, expected)
|
124
|
-
end
|
125
|
-
|
126
|
-
test "overrides existing translations present in mapping" do
|
127
|
-
original = {
|
128
|
-
"fr" => {
|
129
|
-
"document" => {
|
130
|
-
"published" => 'publiée',
|
131
|
-
"updated" => 'mise au jour',
|
132
|
-
}
|
133
|
-
}
|
134
|
-
}
|
135
|
-
|
136
|
-
conversion_mapping = {
|
137
|
-
"document.published" => "content_item.metadata.published",
|
138
|
-
"document.updated" => "content_item.metadata.updated"
|
139
|
-
}
|
140
|
-
|
141
|
-
existing = {
|
142
|
-
"fr" => {
|
143
|
-
"content_item" => {
|
144
|
-
"metadata" => {
|
145
|
-
"updated" => 'mauvaise traduction'
|
146
|
-
}
|
147
|
-
}
|
148
|
-
}
|
149
|
-
}
|
150
|
-
|
151
|
-
expected = {
|
152
|
-
"fr" => {
|
153
|
-
"content_item" => {
|
154
|
-
"metadata" => {
|
155
|
-
"published" => 'publiée',
|
156
|
-
"updated" => 'mise au jour',
|
157
|
-
}
|
158
|
-
}
|
159
|
-
}
|
160
|
-
}
|
161
|
-
stealer_test(original, conversion_mapping, expected, existing)
|
162
|
-
end
|
163
|
-
|
164
|
-
test "does not override existing translations not in mapping" do
|
165
|
-
original = {
|
166
|
-
"fr" => {
|
167
|
-
"document" => {
|
168
|
-
"published" => 'publiée',
|
169
|
-
}
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
conversion_mapping = {
|
174
|
-
"document.published" => "content_item.metadata.published"
|
175
|
-
}
|
176
|
-
|
177
|
-
existing = {
|
178
|
-
"fr" => {
|
179
|
-
"content_item" => {
|
180
|
-
"metadata" => {
|
181
|
-
"updated" => 'mise au jour',
|
182
|
-
}
|
183
|
-
}
|
184
|
-
}
|
185
|
-
}
|
186
|
-
|
187
|
-
expected = {
|
188
|
-
"fr" => {
|
189
|
-
"content_item" => {
|
190
|
-
"metadata" => {
|
191
|
-
"published" => 'publiée',
|
192
|
-
"updated" => 'mise au jour',
|
193
|
-
}
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
stealer_test(original, conversion_mapping, expected, existing)
|
198
|
-
end
|
199
|
-
|
200
|
-
private
|
201
|
-
|
202
|
-
def stealer_test(original, mapping, expected, existing=nil)
|
203
|
-
write_source_data(original)
|
204
|
-
write_converter_data(mapping)
|
205
|
-
|
206
|
-
if existing.present?
|
207
|
-
File.open(locale_file, 'w') do |f|
|
208
|
-
f.puts(existing.to_yaml)
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
stealer = RailsTranslationManager::Stealer.new("fr", source_dir, converter_path, locales_dir)
|
213
|
-
stealer.steal_locale
|
214
|
-
|
215
|
-
assert_equal expected, YAML.load_file(locale_file)
|
216
|
-
end
|
217
|
-
|
218
|
-
def source_dir
|
219
|
-
@source_dir ||= Dir.mktmpdir
|
220
|
-
end
|
221
|
-
|
222
|
-
def source_locale_path
|
223
|
-
File.join(source_dir, 'config/locales')
|
224
|
-
end
|
225
|
-
|
226
|
-
def write_source_data(data)
|
227
|
-
FileUtils.mkdir_p(source_locale_path)
|
228
|
-
File.open(File.join(source_locale_path, 'fr.yml'), 'w') do |f|
|
229
|
-
f.puts(data.to_yaml)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def write_converter_data(data)
|
234
|
-
File.open(converter_path, 'w') do |f|
|
235
|
-
f.puts(data.to_yaml)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def converter_path
|
240
|
-
@converter_path ||= Tempfile.new('fr').path
|
241
|
-
end
|
242
|
-
|
243
|
-
def locales_dir
|
244
|
-
@locales_dir ||= Dir.mktmpdir
|
245
|
-
end
|
246
|
-
|
247
|
-
def locale_file
|
248
|
-
File.join(locales_dir, 'fr.yml')
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'test_helper'
|
3
|
-
require 'rails_translation_manager/validator'
|
4
|
-
require 'tmpdir'
|
5
|
-
require 'fileutils'
|
6
|
-
|
7
|
-
module RailsTranslationManager
|
8
|
-
class ValidatorTest < Minitest::Test
|
9
|
-
def setup
|
10
|
-
@translation_path = Dir.mktmpdir
|
11
|
-
@translation_validator = Validator.new(@translation_path)
|
12
|
-
end
|
13
|
-
|
14
|
-
def teardown
|
15
|
-
FileUtils.remove_entry_secure(@translation_path)
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_translation_file(locale, content)
|
19
|
-
File.open(File.join(@translation_path, "#{locale}.yml"), "w") do |f|
|
20
|
-
f.write(content.lstrip)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
test "can create a flattened list of substitutions" do
|
25
|
-
translation_file = YAML.load(%q{
|
26
|
-
en:
|
27
|
-
view: View '%{title}'
|
28
|
-
test: foo
|
29
|
-
})
|
30
|
-
expected = [Validator::TranslationEntry.new(%w{en view}, "View '%{title}'")]
|
31
|
-
assert_equal expected, @translation_validator.substitutions_in(translation_file)
|
32
|
-
end
|
33
|
-
|
34
|
-
test "detects extra substitution keys" do
|
35
|
-
create_translation_file("en", %q{
|
36
|
-
en:
|
37
|
-
document:
|
38
|
-
view: View '%{title}'
|
39
|
-
})
|
40
|
-
create_translation_file("sr", %q{
|
41
|
-
sr:
|
42
|
-
document:
|
43
|
-
view: Pročitajte '%{naslov}'
|
44
|
-
})
|
45
|
-
errors = Validator.new(@translation_path).check!
|
46
|
-
|
47
|
-
expected = %q{Key "sr.document.view": Extra substitutions: ["naslov"]. Missing substitutions: ["title"].}
|
48
|
-
assert_equal [expected], errors.map(&:to_s)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|