twine 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/twine/cli.rb +63 -48
- data/lib/twine/encoding.rb +16 -14
- data/lib/twine/formatters/abstract.rb +9 -48
- data/lib/twine/formatters/android.rb +30 -26
- data/lib/twine/formatters/apple.rb +20 -48
- data/lib/twine/formatters/django.rb +23 -55
- data/lib/twine/formatters/flash.rb +21 -47
- data/lib/twine/formatters/gettext.rb +25 -26
- data/lib/twine/formatters/jquery.rb +8 -8
- data/lib/twine/formatters/tizen.rb +27 -29
- data/lib/twine/output_processor.rb +2 -2
- data/lib/twine/runner.rb +81 -21
- data/lib/twine/version.rb +1 -1
- data/test/fixtures/enc_utf16be.dummy +0 -0
- data/test/fixtures/enc_utf16be_bom.dummy +0 -0
- data/test/fixtures/enc_utf16le.dummy +0 -0
- data/test/fixtures/enc_utf16le_bom.dummy +0 -0
- data/test/fixtures/enc_utf8.dummy +2 -0
- data/test/test_cli.rb +3 -15
- data/test/test_consume_loc_drop.rb +1 -1
- data/test/test_consume_string_file.rb +73 -7
- data/test/test_formatters.rb +96 -38
- data/test/test_generate_all_string_files.rb +43 -17
- data/test/test_generate_loc_drop.rb +19 -13
- data/test/test_generate_string_file.rb +17 -8
- data/test/test_output_processor.rb +2 -2
- data/test/test_strings_file.rb +2 -2
- data/test/twine_file_dsl.rb +1 -1
- data/test/twine_test_case.rb +6 -7
- metadata +7 -2
data/lib/twine/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test/test_cli.rb
CHANGED
@@ -211,7 +211,7 @@ class CLITestCase < TwineTestCase
|
|
211
211
|
|
212
212
|
def test_default_options
|
213
213
|
parse_with ''
|
214
|
-
expected = {command: 'validate-strings-file', strings_file: 'input.txt', include:
|
214
|
+
expected = {command: 'validate-strings-file', strings_file: 'input.txt', include: :all}
|
215
215
|
assert_equal expected, @options
|
216
216
|
end
|
217
217
|
|
@@ -266,29 +266,17 @@ class CLITestCase < TwineTestCase
|
|
266
266
|
end
|
267
267
|
|
268
268
|
def test_format
|
269
|
-
random_format = Twine::Formatters.formatters.sample.format_name
|
269
|
+
random_format = Twine::Formatters.formatters.sample.format_name.downcase
|
270
270
|
parse_with "--format #{random_format}"
|
271
271
|
assert_equal random_format, @options[:format]
|
272
272
|
end
|
273
273
|
|
274
|
-
def test_format_ignores_case
|
275
|
-
random_format = Twine::Formatters.formatters.sample.format_name
|
276
|
-
parse_with "--format #{random_format.upcase}"
|
277
|
-
assert_equal random_format, @options[:format]
|
278
|
-
end
|
279
|
-
|
280
274
|
def test_include
|
281
|
-
random_set = [
|
275
|
+
random_set = [:all, :translated, :untranslated].sample
|
282
276
|
parse_with "--include #{random_set}"
|
283
277
|
assert_equal random_set, @options[:include]
|
284
278
|
end
|
285
279
|
|
286
|
-
def test_include_ignores_case
|
287
|
-
random_set = ['all', 'translated', 'untranslated'].sample
|
288
|
-
parse_with "--include #{random_set.upcase}"
|
289
|
-
assert_equal random_set, @options[:include]
|
290
|
-
end
|
291
|
-
|
292
280
|
def test_output_path
|
293
281
|
parse_with "--output-file #{@output_path}"
|
294
282
|
assert_equal @output_path, @options[:output_path]
|
@@ -14,31 +14,31 @@ class TestConsumeStringFile < CommandTestCase
|
|
14
14
|
Twine::Runner.new(options, @strings)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def prepare_mock_read_formatter(formatter_class)
|
18
18
|
formatter = prepare_mock_formatter(formatter_class)
|
19
|
-
formatter.expects(:
|
19
|
+
formatter.expects(:read)
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_deducts_android_format_from_output_path
|
23
|
-
|
23
|
+
prepare_mock_read_formatter Twine::Formatters::Android
|
24
24
|
|
25
25
|
new_runner('fr', 'fr.xml').consume_string_file
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_deducts_apple_format_from_output_path
|
29
|
-
|
29
|
+
prepare_mock_read_formatter Twine::Formatters::Apple
|
30
30
|
|
31
31
|
new_runner('fr', 'fr.strings').consume_string_file
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_deducts_jquery_format_from_output_path
|
35
|
-
|
35
|
+
prepare_mock_read_formatter Twine::Formatters::JQuery
|
36
36
|
|
37
37
|
new_runner('fr', 'fr.json').consume_string_file
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_deducts_gettext_format_from_output_path
|
41
|
-
|
41
|
+
prepare_mock_read_formatter Twine::Formatters::Gettext
|
42
42
|
|
43
43
|
new_runner('fr', 'fr.po').consume_string_file
|
44
44
|
end
|
@@ -46,8 +46,74 @@ class TestConsumeStringFile < CommandTestCase
|
|
46
46
|
def test_deducts_language_from_input_path
|
47
47
|
random_language = KNOWN_LANGUAGES.sample
|
48
48
|
formatter = prepare_mock_formatter Twine::Formatters::Android
|
49
|
-
formatter.expects(:
|
49
|
+
formatter.expects(:read).with(anything, random_language)
|
50
50
|
|
51
51
|
new_runner(nil, "#{random_language}.xml").consume_string_file
|
52
52
|
end
|
53
|
+
|
54
|
+
class TestEncodings < CommandTestCase
|
55
|
+
class DummyFormatter < Twine::Formatters::Abstract
|
56
|
+
attr_reader :content
|
57
|
+
|
58
|
+
def extension
|
59
|
+
'.dummy'
|
60
|
+
end
|
61
|
+
|
62
|
+
def format_name
|
63
|
+
'dummy'
|
64
|
+
end
|
65
|
+
|
66
|
+
def read(io, lang)
|
67
|
+
@content = io.read
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def new_runner(input_path, encoding = nil)
|
72
|
+
options = {}
|
73
|
+
options[:output_path] = @output_path
|
74
|
+
options[:input_path] = input_path
|
75
|
+
options[:encoding] = encoding if encoding
|
76
|
+
options[:languages] = 'en'
|
77
|
+
|
78
|
+
@strings = Twine::StringsFile.new
|
79
|
+
@strings.language_codes.concat KNOWN_LANGUAGES
|
80
|
+
|
81
|
+
Twine::Runner.new(options, @strings)
|
82
|
+
end
|
83
|
+
|
84
|
+
def setup
|
85
|
+
super
|
86
|
+
@expected_content = "Üß`\nda\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_reads_utf8
|
90
|
+
formatter = prepare_mock_formatter DummyFormatter
|
91
|
+
new_runner(fixture_path('enc_utf8.dummy')).consume_string_file
|
92
|
+
assert_equal @expected_content, formatter.content
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_reads_utf16le_bom
|
96
|
+
formatter = prepare_mock_formatter DummyFormatter
|
97
|
+
new_runner(fixture_path('enc_utf16le_bom.dummy')).consume_string_file
|
98
|
+
assert_equal @expected_content, formatter.content
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_reads_utf16be_bom
|
102
|
+
formatter = prepare_mock_formatter DummyFormatter
|
103
|
+
new_runner(fixture_path('enc_utf16be_bom.dummy')).consume_string_file
|
104
|
+
assert_equal @expected_content, formatter.content
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_reads_utf16le
|
108
|
+
formatter = prepare_mock_formatter DummyFormatter
|
109
|
+
new_runner(fixture_path('enc_utf16le.dummy'), 'UTF-16LE').consume_string_file
|
110
|
+
assert_equal @expected_content, formatter.content
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_reads_utf16be
|
114
|
+
formatter = prepare_mock_formatter DummyFormatter
|
115
|
+
new_runner(fixture_path('enc_utf16be.dummy'), 'UTF-16BE').consume_string_file
|
116
|
+
assert_equal @expected_content, formatter.content
|
117
|
+
end
|
118
|
+
end
|
53
119
|
end
|
data/test/test_formatters.rb
CHANGED
@@ -41,8 +41,8 @@ class TestAndroidFormatter < FormatterTest
|
|
41
41
|
super Twine::Formatters::Android
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
@formatter.
|
44
|
+
def test_read_format
|
45
|
+
@formatter.read content_io('formatter_android.xml'), 'en'
|
46
46
|
|
47
47
|
assert_file_contents_read_correctly
|
48
48
|
end
|
@@ -67,11 +67,10 @@ class TestAndroidFormatter < FormatterTest
|
|
67
67
|
assert_equal '@value', @strings.strings_map['key1'].translations['en']
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
70
|
+
def test_format_file
|
71
71
|
formatter = Twine::Formatters::Android.new
|
72
72
|
formatter.strings = @twine_file
|
73
|
-
|
74
|
-
assert_equal content('formatter_android.xml'), output_content
|
73
|
+
assert_equal content('formatter_android.xml'), formatter.format_file('en')
|
75
74
|
end
|
76
75
|
|
77
76
|
def test_format_key_with_space
|
@@ -100,6 +99,31 @@ class TestAndroidFormatter < FormatterTest
|
|
100
99
|
identifier = '@android:string/cancel'
|
101
100
|
assert_equal identifier, @formatter.format_value(identifier)
|
102
101
|
end
|
102
|
+
|
103
|
+
def test_deducts_language_from_resource_folder
|
104
|
+
language = %w(en de fr).sample
|
105
|
+
assert_equal language, @formatter.determine_language_given_path("res/values-#{language}")
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_deducts_language_and_region_from_resource_folder
|
109
|
+
assert_equal 'de-AT', @formatter.determine_language_given_path("res/values-de-rAT")
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_maps_laguage_deducted_from_resource_folder
|
113
|
+
assert_equal 'zh-Hans', @formatter.determine_language_given_path("res/values-zh-rCN")
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_does_not_deduct_language_from_device_capability_resource_folder
|
117
|
+
assert_nil @formatter.determine_language_given_path('res/values-w820dp')
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_output_path_is_prefixed
|
121
|
+
assert_equal 'values-en', @formatter.output_path_for_language('en')
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_output_path_language_mappings
|
125
|
+
assert_equal 'values-zh-rCN', @formatter.output_path_for_language('zh-Hans')
|
126
|
+
end
|
103
127
|
end
|
104
128
|
|
105
129
|
class TestAppleFormatter < FormatterTest
|
@@ -107,17 +131,56 @@ class TestAppleFormatter < FormatterTest
|
|
107
131
|
super Twine::Formatters::Apple
|
108
132
|
end
|
109
133
|
|
110
|
-
def
|
111
|
-
@formatter.
|
134
|
+
def test_read_format
|
135
|
+
@formatter.read content_io('formatter_apple.strings'), 'en'
|
112
136
|
|
113
137
|
assert_file_contents_read_correctly
|
114
138
|
end
|
115
139
|
|
116
|
-
def
|
140
|
+
def test_reads_quoted_keys
|
141
|
+
@formatter.read StringIO.new('"key" = "value"'), 'en'
|
142
|
+
assert_equal 'value', @strings.strings_map['key'].translations['en']
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_reads_unquoted_keys
|
146
|
+
@formatter.read StringIO.new('key = "value"'), 'en'
|
147
|
+
assert_equal 'value', @strings.strings_map['key'].translations['en']
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_ignores_leading_whitespace_before_quoted_keys
|
151
|
+
@formatter.read StringIO.new("\t \"key\" = \"value\""), 'en'
|
152
|
+
assert_equal 'value', @strings.strings_map['key'].translations['en']
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_ignores_leading_whitespace_before_unquoted_keys
|
156
|
+
@formatter.read StringIO.new("\t key = \"value\""), 'en'
|
157
|
+
assert_equal 'value', @strings.strings_map['key'].translations['en']
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_allows_quotes_in_quoted_keys
|
161
|
+
@formatter.read StringIO.new('"ke\"y" = "value"'), 'en'
|
162
|
+
assert_equal 'value', @strings.strings_map['ke"y'].translations['en']
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_does_not_allow_quotes_in_quoted_keys
|
166
|
+
@formatter.read StringIO.new('ke"y = "value"'), 'en'
|
167
|
+
assert_nil @strings.strings_map['key']
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_allows_equal_signs_in_quoted_keys
|
171
|
+
@formatter.read StringIO.new('"k=ey" = "value"'), 'en'
|
172
|
+
assert_equal 'value', @strings.strings_map['k=ey'].translations['en']
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_does_not_allow_equal_signs_in_unquoted_keys
|
176
|
+
@formatter.read StringIO.new('k=ey = "value"'), 'en'
|
177
|
+
assert_nil @strings.strings_map['key']
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_format_file
|
117
181
|
formatter = Twine::Formatters::Apple.new
|
118
182
|
formatter.strings = @twine_file
|
119
|
-
|
120
|
-
assert_equal content('formatter_apple.strings'), output_content
|
183
|
+
assert_equal content('formatter_apple.strings'), formatter.format_file('en')
|
121
184
|
end
|
122
185
|
|
123
186
|
def test_format_key_with_space
|
@@ -139,17 +202,16 @@ class TestJQueryFormatter < FormatterTest
|
|
139
202
|
super Twine::Formatters::JQuery
|
140
203
|
end
|
141
204
|
|
142
|
-
def
|
143
|
-
@formatter.
|
205
|
+
def test_read_format
|
206
|
+
@formatter.read content_io('formatter_jquery.json'), 'en'
|
144
207
|
|
145
208
|
assert_translations_read_correctly
|
146
209
|
end
|
147
210
|
|
148
|
-
def
|
211
|
+
def test_format_file
|
149
212
|
formatter = Twine::Formatters::JQuery.new
|
150
213
|
formatter.strings = @twine_file
|
151
|
-
|
152
|
-
assert_equal content('formatter_jquery.json'), output_content
|
214
|
+
assert_equal content('formatter_jquery.json'), formatter.format_file('en')
|
153
215
|
end
|
154
216
|
|
155
217
|
def test_format_value_with_newline
|
@@ -163,23 +225,22 @@ class TestGettextFormatter < FormatterTest
|
|
163
225
|
super Twine::Formatters::Gettext
|
164
226
|
end
|
165
227
|
|
166
|
-
def
|
167
|
-
@formatter.
|
228
|
+
def test_read_format
|
229
|
+
@formatter.read content_io('formatter_gettext.po'), 'en'
|
168
230
|
|
169
231
|
assert_file_contents_read_correctly
|
170
232
|
end
|
171
233
|
|
172
|
-
def
|
173
|
-
@formatter.
|
234
|
+
def test_read_with_multiple_line_value
|
235
|
+
@formatter.read content_io('gettext_multiline.po'), 'en'
|
174
236
|
|
175
237
|
assert_equal 'multiline\nstring', @strings.strings_map['key1'].translations['en']
|
176
238
|
end
|
177
239
|
|
178
|
-
def
|
240
|
+
def test_format_file
|
179
241
|
formatter = Twine::Formatters::Gettext.new
|
180
242
|
formatter.strings = @twine_file
|
181
|
-
|
182
|
-
assert_equal content('formatter_gettext.po'), output_content
|
243
|
+
assert_equal content('formatter_gettext.po'), formatter.format_file('en')
|
183
244
|
end
|
184
245
|
|
185
246
|
end
|
@@ -190,18 +251,17 @@ class TestTizenFormatter < FormatterTest
|
|
190
251
|
super Twine::Formatters::Tizen
|
191
252
|
end
|
192
253
|
|
193
|
-
def
|
194
|
-
skip 'the current implementation of Tizen formatter does not support
|
195
|
-
@formatter.
|
254
|
+
def test_read_format
|
255
|
+
skip 'the current implementation of Tizen formatter does not support reading'
|
256
|
+
@formatter.read content_io('formatter_tizen.xml'), 'en'
|
196
257
|
|
197
258
|
assert_file_contents_read_correctly
|
198
259
|
end
|
199
260
|
|
200
|
-
def
|
261
|
+
def test_format_file
|
201
262
|
formatter = Twine::Formatters::Tizen.new
|
202
263
|
formatter.strings = @twine_file
|
203
|
-
|
204
|
-
assert_equal content('formatter_tizen.xml'), output_content
|
264
|
+
assert_equal content('formatter_tizen.xml'), formatter.format_file('en')
|
205
265
|
end
|
206
266
|
|
207
267
|
end
|
@@ -211,17 +271,16 @@ class TestDjangoFormatter < FormatterTest
|
|
211
271
|
super Twine::Formatters::Django
|
212
272
|
end
|
213
273
|
|
214
|
-
def
|
215
|
-
@formatter.
|
274
|
+
def test_read_format
|
275
|
+
@formatter.read content_io('formatter_django.po'), 'en'
|
216
276
|
|
217
277
|
assert_file_contents_read_correctly
|
218
278
|
end
|
219
279
|
|
220
|
-
def
|
280
|
+
def test_format_file
|
221
281
|
formatter = Twine::Formatters::Django.new
|
222
282
|
formatter.strings = @twine_file
|
223
|
-
|
224
|
-
assert_equal content('formatter_django.po'), output_content
|
283
|
+
assert_equal content('formatter_django.po'), formatter.format_file('en')
|
225
284
|
end
|
226
285
|
end
|
227
286
|
|
@@ -230,16 +289,15 @@ class TestFlashFormatter < FormatterTest
|
|
230
289
|
super Twine::Formatters::Flash
|
231
290
|
end
|
232
291
|
|
233
|
-
def
|
234
|
-
@formatter.
|
292
|
+
def test_read_format
|
293
|
+
@formatter.read content_io('formatter_flash.properties'), 'en'
|
235
294
|
|
236
295
|
assert_file_contents_read_correctly
|
237
296
|
end
|
238
297
|
|
239
|
-
def
|
298
|
+
def test_format_file
|
240
299
|
formatter = Twine::Formatters::Flash.new
|
241
300
|
formatter.strings = @twine_file
|
242
|
-
|
243
|
-
assert_equal content('formatter_flash.properties'), output_content
|
301
|
+
assert_equal content('formatter_flash.properties'), formatter.format_file('en')
|
244
302
|
end
|
245
303
|
end
|
@@ -1,48 +1,74 @@
|
|
1
1
|
require 'command_test_case'
|
2
2
|
|
3
3
|
class TestGenerateAllStringFiles < CommandTestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
options[:create_folders] = create_folders
|
4
|
+
def new_runner(create_folders, twine_file = nil)
|
5
|
+
options = {}
|
6
|
+
options[:output_path] = @output_dir
|
7
|
+
options[:format] = 'apple'
|
8
|
+
options[:create_folders] = create_folders
|
10
9
|
|
10
|
+
unless twine_file
|
11
11
|
twine_file = build_twine_file 'en', 'es' do
|
12
12
|
add_section 'Section' do
|
13
13
|
add_row key: 'value'
|
14
14
|
end
|
15
15
|
end
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
+
Twine::Runner.new(options, twine_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestDoNotCreateFolders < TestGenerateAllStringFiles
|
22
|
+
def new_runner(twine_file = nil)
|
23
|
+
super(false, twine_file)
|
18
24
|
end
|
19
25
|
|
20
26
|
def test_fails_if_output_folder_does_not_exist
|
21
27
|
assert_raises Twine::Error do
|
22
|
-
new_runner
|
28
|
+
new_runner.generate_all_string_files
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
26
|
-
def
|
27
|
-
|
28
|
-
new_runner
|
29
|
-
|
32
|
+
def test_does_not_create_language_folders
|
33
|
+
Dir.mkdir File.join @output_dir, 'en.lproj'
|
34
|
+
new_runner.generate_all_string_files
|
35
|
+
refute File.exists?(File.join(@output_dir, 'es.lproj')), "language folder should not be created"
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
38
|
+
def test_prints_empty_file_warnings
|
33
39
|
Dir.mkdir File.join @output_dir, 'en.lproj'
|
34
|
-
|
35
|
-
|
40
|
+
empty_twine_file = build_twine_file('en') {}
|
41
|
+
new_runner(empty_twine_file).generate_all_string_files
|
42
|
+
assert_match "Skipping file at path", Twine::stderr.string
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class TestCreateFolders < TestGenerateAllStringFiles
|
47
|
+
def new_runner(twine_file = nil)
|
48
|
+
super(true, twine_file)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_creates_output_folder
|
52
|
+
FileUtils.remove_entry_secure @output_dir
|
53
|
+
new_runner.generate_all_string_files
|
54
|
+
assert File.exists? @output_dir
|
36
55
|
end
|
37
56
|
|
38
57
|
def test_creates_language_folders
|
39
|
-
new_runner
|
58
|
+
new_runner.generate_all_string_files
|
40
59
|
assert File.exists?(File.join(@output_dir, 'en.lproj')), "language folder 'en.lproj' should be created"
|
41
60
|
assert File.exists?(File.join(@output_dir, 'es.lproj')), "language folder 'es.lproj' should be created"
|
42
61
|
end
|
62
|
+
|
63
|
+
def test_prints_empty_file_warnings
|
64
|
+
empty_twine_file = build_twine_file('en') {}
|
65
|
+
new_runner(empty_twine_file).generate_all_string_files
|
66
|
+
|
67
|
+
assert_match "Skipping file at path", Twine::stderr.string
|
68
|
+
end
|
43
69
|
end
|
44
70
|
|
45
|
-
class
|
71
|
+
class TestValidate < CommandTestCase
|
46
72
|
def new_runner(validate)
|
47
73
|
Dir.mkdir File.join @output_dir, 'values-en'
|
48
74
|
|