twine 0.8.1 → 0.9.0
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/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
|
|