twine 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/twine.rb +1 -1
- data/lib/twine/cli.rb +7 -1
- data/lib/twine/formatters.rb +7 -13
- data/lib/twine/formatters/abstract.rb +38 -33
- data/lib/twine/formatters/android.rb +12 -5
- data/lib/twine/formatters/apple.rb +11 -5
- data/lib/twine/formatters/django.rb +18 -10
- data/lib/twine/formatters/flash.rb +11 -5
- data/lib/twine/formatters/gettext.rb +26 -19
- data/lib/twine/formatters/jquery.rb +11 -14
- data/lib/twine/formatters/tizen.rb +11 -30
- data/lib/twine/runner.rb +66 -56
- data/lib/twine/version.rb +1 -1
- data/test/command_test_case.rb +4 -2
- data/test/fixtures/formatter_django.po +1 -1
- data/test/fixtures/formatter_flash.properties +1 -1
- data/test/test_abstract_formatter.rb +21 -8
- data/test/test_cli.rb +22 -2
- data/test/test_formatters.rb +17 -8
- data/test/test_generate_all_string_files.rb +34 -2
- data/test/test_generate_loc_drop.rb +30 -0
- data/test/test_generate_string_file.rb +34 -3
- data/test/test_validate_strings_file.rb +11 -5
- data/test/twine_test_case.rb +5 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebc7f372d107cb4c3b9a12da92b792c510209d59
|
4
|
+
data.tar.gz: 72ccda8290612adfc0f7ac75f86756bc1d945333
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44bf1d87f0b3e88e70cc8962dd708a35866a74710e95706ae5e4061c02995b00afb6175acb1d5219605ec391b60ceeddf01edb83bd253d73e14681847cd8aac6
|
7
|
+
data.tar.gz: ea504d997033b778bb9f458fb33ef1f75bfb4d57c6da1771685f092c3fa1b2362f8bdf82d2a85cbcaade440c42617f21e130c7baab7767f5522f27843f78ca5f
|
data/lib/twine.rb
CHANGED
@@ -23,11 +23,11 @@ module Twine
|
|
23
23
|
|
24
24
|
require 'twine/plugin'
|
25
25
|
require 'twine/cli'
|
26
|
+
require 'twine/stringsfile'
|
26
27
|
require 'twine/encoding'
|
27
28
|
require 'twine/output_processor'
|
28
29
|
require 'twine/placeholders'
|
29
30
|
require 'twine/formatters'
|
30
31
|
require 'twine/runner'
|
31
|
-
require 'twine/stringsfile'
|
32
32
|
require 'twine/version'
|
33
33
|
end
|
data/lib/twine/cli.rb
CHANGED
@@ -46,7 +46,7 @@ module Twine
|
|
46
46
|
opts.on('-u', '--untagged', 'If you have specified tags using the --tags flag, then only those tags will be selected. If you also want to select all strings that are untagged, then you can specify this option to do so.') do |u|
|
47
47
|
options[:untagged] = true
|
48
48
|
end
|
49
|
-
formats = Formatters.formatters.map
|
49
|
+
formats = Formatters.formatters.map(&:format_name)
|
50
50
|
opts.on('-f', '--format FORMAT', "The file format to read or write (#{formats.join(', ')}). Additional formatters can be placed in the formats/ directory.") do |format|
|
51
51
|
unless formats.include?(format.downcase)
|
52
52
|
raise Twine::Error.new "Invalid format: #{format}"
|
@@ -89,6 +89,12 @@ module Twine
|
|
89
89
|
end
|
90
90
|
options[:output_encoding] = e
|
91
91
|
end
|
92
|
+
opts.on('--validate', 'Validate the strings file before formatting it') do
|
93
|
+
options[:validate] = true
|
94
|
+
end
|
95
|
+
opts.on('-p', '--pedantic', 'When validating a strings file, perform additional checks that go beyond pure validity (like presence of tags)') do
|
96
|
+
options[:pedantic] = true
|
97
|
+
end
|
92
98
|
opts.on('-h', '--help', 'Show this message.') do |h|
|
93
99
|
puts opts.help
|
94
100
|
exit
|
data/lib/twine/formatters.rb
CHANGED
@@ -1,15 +1,6 @@
|
|
1
|
-
require 'twine/formatters/abstract'
|
2
|
-
require 'twine/formatters/android'
|
3
|
-
require 'twine/formatters/apple'
|
4
|
-
require 'twine/formatters/flash'
|
5
|
-
require 'twine/formatters/gettext'
|
6
|
-
require 'twine/formatters/jquery'
|
7
|
-
require 'twine/formatters/django'
|
8
|
-
require 'twine/formatters/tizen'
|
9
|
-
|
10
1
|
module Twine
|
11
2
|
module Formatters
|
12
|
-
@formatters = [
|
3
|
+
@formatters = []
|
13
4
|
|
14
5
|
class << self
|
15
6
|
attr_reader :formatters
|
@@ -22,9 +13,12 @@ module Twine
|
|
22
13
|
# returns array of active formatters
|
23
14
|
#
|
24
15
|
def register_formatter formatter_class
|
25
|
-
|
26
|
-
@formatters << formatter_class
|
16
|
+
@formatters << formatter_class.new
|
27
17
|
end
|
28
18
|
end
|
29
19
|
end
|
30
|
-
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Dir[File.join(File.dirname(__FILE__), 'formatters', '*.rb')].each do |file|
|
23
|
+
require file
|
24
|
+
end
|
@@ -3,17 +3,28 @@ require 'fileutils'
|
|
3
3
|
module Twine
|
4
4
|
module Formatters
|
5
5
|
class Abstract
|
6
|
-
|
7
|
-
|
6
|
+
attr_accessor :strings
|
7
|
+
attr_accessor :options
|
8
8
|
|
9
|
-
def
|
10
|
-
|
9
|
+
def initialize
|
10
|
+
@strings = StringsFile.new
|
11
|
+
@options = {}
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def format_name
|
15
|
+
raise NotImplementedError.new("You must implement format_name in your formatter class.")
|
16
|
+
end
|
17
|
+
|
18
|
+
def extension
|
19
|
+
raise NotImplementedError.new("You must implement extension in your formatter class.")
|
20
|
+
end
|
21
|
+
|
22
|
+
def can_handle_directory?(path)
|
23
|
+
raise NotImplementedError.new("You must implement can_handle_directory? in your formatter class.")
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_file_name
|
27
|
+
raise NotImplementedError.new("You must implement default_file_name in your formatter class.")
|
17
28
|
end
|
18
29
|
|
19
30
|
def set_translation_for_key(key, lang, value)
|
@@ -64,10 +75,6 @@ module Twine
|
|
64
75
|
end
|
65
76
|
end
|
66
77
|
|
67
|
-
def default_file_name
|
68
|
-
raise NotImplementedError.new("You must implement default_file_name in your formatter class.")
|
69
|
-
end
|
70
|
-
|
71
78
|
def determine_language_given_path(path)
|
72
79
|
raise NotImplementedError.new("You must implement determine_language_given_path in your formatter class.")
|
73
80
|
end
|
@@ -92,21 +99,25 @@ module Twine
|
|
92
99
|
|
93
100
|
def format_sections(strings, lang)
|
94
101
|
sections = strings.sections.map { |section| format_section(section, lang) }
|
95
|
-
sections.join("\n")
|
102
|
+
sections.compact.join("\n")
|
96
103
|
end
|
97
104
|
|
98
105
|
def format_section_header(section)
|
99
106
|
end
|
100
107
|
|
108
|
+
def should_include_row(row, lang)
|
109
|
+
row.translated_string_for_lang(lang)
|
110
|
+
end
|
111
|
+
|
101
112
|
def format_section(section, lang)
|
102
|
-
rows = section.rows.
|
113
|
+
rows = section.rows.select { |row| should_include_row(row, lang) }
|
114
|
+
return if rows.empty?
|
103
115
|
|
104
116
|
result = ""
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
117
|
+
|
118
|
+
if section.name && section.name.length > 0
|
119
|
+
section_header = format_section_header(section)
|
120
|
+
result += "\n#{section_header}" if section_header
|
110
121
|
end
|
111
122
|
|
112
123
|
rows.map! { |row| format_row(row, lang) }
|
@@ -115,16 +126,8 @@ module Twine
|
|
115
126
|
result += rows.join
|
116
127
|
end
|
117
128
|
|
118
|
-
def row_pattern
|
119
|
-
"%{comment}%{key_value}"
|
120
|
-
end
|
121
|
-
|
122
129
|
def format_row(row, lang)
|
123
|
-
|
124
|
-
|
125
|
-
result = row_pattern.scan(/%\{([a-z_]+)\}/).flatten
|
126
|
-
result.map! { |element| send("format_#{element}".to_sym, row, lang) }
|
127
|
-
result.flatten.join
|
130
|
+
[format_comment(row, lang), format_key_value(row, lang)].compact.join
|
128
131
|
end
|
129
132
|
|
130
133
|
def format_comment(row, lang)
|
@@ -152,10 +155,10 @@ module Twine
|
|
152
155
|
end
|
153
156
|
|
154
157
|
def write_file(path, lang)
|
155
|
-
|
156
|
-
|
157
|
-
processed_strings = @output_processor.process(lang)
|
158
|
+
output_processor = Processors::OutputProcessor.new(@strings, @options)
|
159
|
+
processed_strings = output_processor.process(lang)
|
158
160
|
|
161
|
+
encoding = @options[:output_encoding] || 'UTF-8'
|
159
162
|
File.open(path, "w:#{encoding}") do |f|
|
160
163
|
f.puts format_file(processed_strings, lang)
|
161
164
|
end
|
@@ -169,7 +172,8 @@ module Twine
|
|
169
172
|
|
170
173
|
FileUtils.mkdir_p(output_path)
|
171
174
|
|
172
|
-
|
175
|
+
file_path = File.join(output_path, file_name)
|
176
|
+
write_file(file_path, lang)
|
173
177
|
end
|
174
178
|
else
|
175
179
|
language_written = false
|
@@ -182,7 +186,8 @@ module Twine
|
|
182
186
|
lang = determine_language_given_path(item)
|
183
187
|
next unless lang
|
184
188
|
|
185
|
-
|
189
|
+
file_path = File.join(item, file_name)
|
190
|
+
write_file(file_path, lang)
|
186
191
|
language_written = true
|
187
192
|
end
|
188
193
|
|
@@ -7,9 +7,6 @@ module Twine
|
|
7
7
|
class Android < Abstract
|
8
8
|
include Twine::Placeholders
|
9
9
|
|
10
|
-
FORMAT_NAME = 'android'
|
11
|
-
EXTENSION = '.xml'
|
12
|
-
DEFAULT_FILE_NAME = 'strings.xml'
|
13
10
|
LANG_CODES = Hash[
|
14
11
|
'zh' => 'zh-Hans',
|
15
12
|
'zh-rCN' => 'zh-Hans',
|
@@ -20,12 +17,20 @@ module Twine
|
|
20
17
|
# TODO: spanish
|
21
18
|
]
|
22
19
|
|
23
|
-
def
|
20
|
+
def format_name
|
21
|
+
'android'
|
22
|
+
end
|
23
|
+
|
24
|
+
def extension
|
25
|
+
'.xml'
|
26
|
+
end
|
27
|
+
|
28
|
+
def can_handle_directory?(path)
|
24
29
|
Dir.entries(path).any? { |item| /^values.*$/.match(item) }
|
25
30
|
end
|
26
31
|
|
27
32
|
def default_file_name
|
28
|
-
return
|
33
|
+
return 'strings.xml'
|
29
34
|
end
|
30
35
|
|
31
36
|
def determine_language_given_path(path)
|
@@ -135,3 +140,5 @@ module Twine
|
|
135
140
|
end
|
136
141
|
end
|
137
142
|
end
|
143
|
+
|
144
|
+
Twine::Formatters.formatters << Twine::Formatters::Android.new
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Twine
|
2
2
|
module Formatters
|
3
3
|
class Apple < Abstract
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def format_name
|
5
|
+
'apple'
|
6
|
+
end
|
7
|
+
|
8
|
+
def extension
|
9
|
+
'.strings'
|
10
|
+
end
|
7
11
|
|
8
|
-
def
|
12
|
+
def can_handle_directory?(path)
|
9
13
|
Dir.entries(path).any? { |item| /^.+\.lproj$/.match(item) }
|
10
14
|
end
|
11
15
|
|
12
16
|
def default_file_name
|
13
|
-
return
|
17
|
+
return 'Localizable.strings'
|
14
18
|
end
|
15
19
|
|
16
20
|
def determine_language_given_path(path)
|
@@ -111,3 +115,5 @@ module Twine
|
|
111
115
|
end
|
112
116
|
end
|
113
117
|
end
|
118
|
+
|
119
|
+
Twine::Formatters.formatters << Twine::Formatters::Apple.new
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Twine
|
2
2
|
module Formatters
|
3
3
|
class Django < Abstract
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def format_name
|
5
|
+
'django'
|
6
|
+
end
|
7
|
+
|
8
|
+
def extension
|
9
|
+
'.po'
|
10
|
+
end
|
7
11
|
|
8
|
-
def
|
9
|
-
|
12
|
+
def can_handle_directory?(path)
|
13
|
+
Dir.entries(path).any? { |item| /^.+\.po$/.match(item) }
|
10
14
|
end
|
11
15
|
|
12
16
|
def default_file_name
|
13
|
-
return
|
17
|
+
return 'strings.po'
|
14
18
|
end
|
15
19
|
|
16
20
|
def determine_language_given_path(path)
|
@@ -92,7 +96,9 @@ module Twine
|
|
92
96
|
|
93
97
|
def format_file(strings, lang)
|
94
98
|
@default_lang = strings.language_codes[0]
|
95
|
-
super
|
99
|
+
result = super
|
100
|
+
@default_lang = nil
|
101
|
+
result
|
96
102
|
end
|
97
103
|
|
98
104
|
def format_header(lang)
|
@@ -103,11 +109,11 @@ module Twine
|
|
103
109
|
"#--------- #{section.name} ---------#\n"
|
104
110
|
end
|
105
111
|
|
106
|
-
def
|
107
|
-
|
112
|
+
def format_row(row, lang)
|
113
|
+
[format_comment(row, lang), format_base_translation(row), format_key_value(row, lang)].compact.join
|
108
114
|
end
|
109
115
|
|
110
|
-
def format_base_translation(row
|
116
|
+
def format_base_translation(row)
|
111
117
|
base_translation = row.translations[@default_lang]
|
112
118
|
"# base translation: \"#{base_translation}\"\n" if base_translation
|
113
119
|
end
|
@@ -131,3 +137,5 @@ module Twine
|
|
131
137
|
end
|
132
138
|
end
|
133
139
|
end
|
140
|
+
|
141
|
+
Twine::Formatters.formatters << Twine::Formatters::Django.new
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Twine
|
2
2
|
module Formatters
|
3
3
|
class Flash < Abstract
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def format_name
|
5
|
+
'flash'
|
6
|
+
end
|
7
|
+
|
8
|
+
def extension
|
9
|
+
'.properties'
|
10
|
+
end
|
7
11
|
|
8
|
-
def
|
12
|
+
def can_handle_directory?(path)
|
9
13
|
return false
|
10
14
|
end
|
11
15
|
|
12
16
|
def default_file_name
|
13
|
-
return
|
17
|
+
return 'resources.properties'
|
14
18
|
end
|
15
19
|
|
16
20
|
def determine_language_given_path(path)
|
@@ -93,3 +97,5 @@ module Twine
|
|
93
97
|
end
|
94
98
|
end
|
95
99
|
end
|
100
|
+
|
101
|
+
Twine::Formatters.formatters << Twine::Formatters::Flash.new
|
@@ -3,16 +3,20 @@
|
|
3
3
|
module Twine
|
4
4
|
module Formatters
|
5
5
|
class Gettext < Abstract
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def format_name
|
7
|
+
'gettext'
|
8
|
+
end
|
9
|
+
|
10
|
+
def extension
|
11
|
+
'.po'
|
12
|
+
end
|
9
13
|
|
10
|
-
def
|
14
|
+
def can_handle_directory?(path)
|
11
15
|
Dir.entries(path).any? { |item| /^.+\.po$/.match(item) }
|
12
16
|
end
|
13
17
|
|
14
18
|
def default_file_name
|
15
|
-
return
|
19
|
+
return 'strings.po'
|
16
20
|
end
|
17
21
|
|
18
22
|
def determine_language_given_path(path)
|
@@ -62,7 +66,9 @@ module Twine
|
|
62
66
|
|
63
67
|
def format_file(strings, lang)
|
64
68
|
@default_lang = strings.language_codes[0]
|
65
|
-
super
|
69
|
+
result = super
|
70
|
+
@default_lang = nil
|
71
|
+
result
|
66
72
|
end
|
67
73
|
|
68
74
|
def format_header(lang)
|
@@ -73,31 +79,32 @@ module Twine
|
|
73
79
|
"# SECTION: #{section.name}"
|
74
80
|
end
|
75
81
|
|
76
|
-
def
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
def format_row(row, lang)
|
81
|
-
return nil unless row.translated_string_for_lang(@default_lang)
|
82
|
-
|
83
|
-
super
|
82
|
+
def should_include_row(row, lang)
|
83
|
+
super and row.translated_string_for_lang(@default_lang)
|
84
84
|
end
|
85
85
|
|
86
86
|
def format_comment(row, lang)
|
87
87
|
"#. \"#{escape_quotes(row.comment)}\"\n" if row.comment
|
88
88
|
end
|
89
89
|
|
90
|
-
def
|
91
|
-
|
90
|
+
def format_key_value(row, lang)
|
91
|
+
value = row.translated_string_for_lang(lang)
|
92
|
+
[format_key(row.key.dup), format_base_translation(row), format_value(value.dup)].compact.join
|
93
|
+
end
|
94
|
+
|
95
|
+
def format_key(key)
|
96
|
+
"msgctxt \"#{key}\"\n"
|
92
97
|
end
|
93
98
|
|
94
|
-
def format_base_translation(row
|
99
|
+
def format_base_translation(row)
|
95
100
|
"msgid \"#{row.translations[@default_lang]}\"\n"
|
96
101
|
end
|
97
102
|
|
98
|
-
def format_value(
|
99
|
-
"msgstr \"#{
|
103
|
+
def format_value(value)
|
104
|
+
"msgstr \"#{value}\"\n"
|
100
105
|
end
|
101
106
|
end
|
102
107
|
end
|
103
108
|
end
|
109
|
+
|
110
|
+
Twine::Formatters.formatters << Twine::Formatters::Gettext.new
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Twine
|
2
2
|
module Formatters
|
3
3
|
class JQuery < Abstract
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def format_name
|
5
|
+
'jquery'
|
6
|
+
end
|
7
|
+
|
8
|
+
def extension
|
9
|
+
'.json'
|
10
|
+
end
|
7
11
|
|
8
|
-
def
|
12
|
+
def can_handle_directory?(path)
|
9
13
|
Dir.entries(path).any? { |item| /^.+\.json$/.match(item) }
|
10
14
|
end
|
11
15
|
|
12
16
|
def default_file_name
|
13
|
-
return
|
17
|
+
return 'localize.json'
|
14
18
|
end
|
15
19
|
|
16
20
|
def determine_language_given_path(path)
|
@@ -71,15 +75,8 @@ module Twine
|
|
71
75
|
def format_value(value)
|
72
76
|
escape_quotes(value)
|
73
77
|
end
|
74
|
-
|
75
|
-
def write_file(path, lang)
|
76
|
-
begin
|
77
|
-
require "json"
|
78
|
-
rescue LoadError
|
79
|
-
raise Twine::Error.new "You must run 'gem install json' in order to read or write jquery-localize files."
|
80
|
-
end
|
81
|
-
super
|
82
|
-
end
|
83
78
|
end
|
84
79
|
end
|
85
80
|
end
|
81
|
+
|
82
|
+
Twine::Formatters.formatters << Twine::Formatters::JQuery.new
|
@@ -7,9 +7,6 @@ module Twine
|
|
7
7
|
class Tizen < Abstract
|
8
8
|
include Twine::Placeholders
|
9
9
|
|
10
|
-
FORMAT_NAME = 'tizen'
|
11
|
-
EXTENSION = '.xml'
|
12
|
-
DEFAULT_FILE_NAME = 'strings.xml'
|
13
10
|
LANG_CODES = Hash[
|
14
11
|
'eng-GB' => 'en',
|
15
12
|
'rus-RU' => 'ru',
|
@@ -22,39 +19,21 @@ module Twine
|
|
22
19
|
'por-PT' => 'pt',
|
23
20
|
'ukr-UA' => 'uk'
|
24
21
|
]
|
25
|
-
DEFAULT_LANG_CODES = Hash[
|
26
|
-
]
|
27
22
|
|
28
|
-
def
|
29
|
-
|
23
|
+
def format_name
|
24
|
+
'tizen'
|
30
25
|
end
|
31
26
|
|
32
|
-
def
|
33
|
-
|
27
|
+
def extension
|
28
|
+
'.xml'
|
34
29
|
end
|
35
30
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
end
|
31
|
+
def can_handle_directory?(path)
|
32
|
+
Dir.entries(path).any? { |item| /^values.*$/.match(item) }
|
33
|
+
end
|
40
34
|
|
41
|
-
|
42
|
-
|
43
|
-
if item == "." or item == ".."
|
44
|
-
next
|
45
|
-
end
|
46
|
-
item = File.join(path, item)
|
47
|
-
if !File.directory?(item)
|
48
|
-
lang = determine_language_given_path(item)
|
49
|
-
if lang
|
50
|
-
write_file(item, lang)
|
51
|
-
langs_written << lang
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
if langs_written.empty?
|
56
|
-
raise Twine::Error.new("Failed to genertate any files: No languages found at #{path}")
|
57
|
-
end
|
35
|
+
def default_file_name
|
36
|
+
return 'strings.xml'
|
58
37
|
end
|
59
38
|
|
60
39
|
def determine_language_given_path(path)
|
@@ -156,3 +135,5 @@ module Twine
|
|
156
135
|
end
|
157
136
|
end
|
158
137
|
end
|
138
|
+
|
139
|
+
Twine::Formatters.formatters << Twine::Formatters::Tizen.new
|
data/lib/twine/runner.rb
CHANGED
@@ -43,13 +43,17 @@ module Twine
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def generate_string_file
|
46
|
+
validate_strings_file if @options[:validate]
|
47
|
+
|
46
48
|
lang = nil
|
47
49
|
lang = @options[:languages][0] if @options[:languages]
|
48
50
|
|
49
|
-
|
51
|
+
write_string_file(@options[:output_path], lang)
|
50
52
|
end
|
51
53
|
|
52
54
|
def generate_all_string_files
|
55
|
+
validate_strings_file if @options[:validate]
|
56
|
+
|
53
57
|
if !File.directory?(@options[:output_path])
|
54
58
|
if @options[:create_folders]
|
55
59
|
FileUtils.mkdir_p(@options[:output_path])
|
@@ -58,13 +62,13 @@ module Twine
|
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
61
|
-
|
62
|
-
|
65
|
+
formatter_for_directory = find_formatter { |f| f.can_handle_directory?(@options[:output_path]) }
|
66
|
+
formatter = formatter_for_format(@options[:format]) || formatter_for_directory
|
67
|
+
|
68
|
+
unless formatter
|
63
69
|
raise Twine::Error.new "Could not determine format given the contents of #{@options[:output_path]}"
|
64
70
|
end
|
65
71
|
|
66
|
-
formatter = formatter_for_format(format)
|
67
|
-
|
68
72
|
formatter.write_all_files(@options[:output_path])
|
69
73
|
end
|
70
74
|
|
@@ -74,7 +78,7 @@ module Twine
|
|
74
78
|
lang = @options[:languages][0]
|
75
79
|
end
|
76
80
|
|
77
|
-
|
81
|
+
read_string_file(@options[:input_path], lang)
|
78
82
|
output_path = @options[:output_path] || @options[:strings_file]
|
79
83
|
write_strings_data(output_path)
|
80
84
|
end
|
@@ -87,7 +91,7 @@ module Twine
|
|
87
91
|
Dir.glob(File.join(@options[:input_path], "**/*")) do |item|
|
88
92
|
if File.file?(item)
|
89
93
|
begin
|
90
|
-
|
94
|
+
read_string_file(item)
|
91
95
|
rescue Twine::Error => e
|
92
96
|
Twine::stderr.puts "#{e.message}"
|
93
97
|
end
|
@@ -98,35 +102,9 @@ module Twine
|
|
98
102
|
write_strings_data(output_path)
|
99
103
|
end
|
100
104
|
|
101
|
-
def read_write_string_file(path, is_read, lang)
|
102
|
-
if is_read && !File.file?(path)
|
103
|
-
raise Twine::Error.new("File does not exist: #{path}")
|
104
|
-
end
|
105
|
-
|
106
|
-
format = @options[:format] || determine_format_given_path(path)
|
107
|
-
unless format
|
108
|
-
raise Twine::Error.new "Unable to determine format of #{path}"
|
109
|
-
end
|
110
|
-
|
111
|
-
formatter = formatter_for_format(format)
|
112
|
-
|
113
|
-
lang = lang || determine_language_given_path(path) || formatter.determine_language_given_path(path)
|
114
|
-
unless lang
|
115
|
-
raise Twine::Error.new "Unable to determine language for #{path}"
|
116
|
-
end
|
117
|
-
|
118
|
-
if !@strings.language_codes.include? lang
|
119
|
-
@strings.language_codes << lang
|
120
|
-
end
|
121
|
-
|
122
|
-
if is_read
|
123
|
-
formatter.read_file(path, lang)
|
124
|
-
else
|
125
|
-
formatter.write_file(path, lang)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
105
|
def generate_loc_drop
|
106
|
+
validate_strings_file if @options[:validate]
|
107
|
+
|
130
108
|
require_rubyzip
|
131
109
|
|
132
110
|
if File.file?(@options[:output_path])
|
@@ -140,7 +118,7 @@ module Twine
|
|
140
118
|
formatter = formatter_for_format(@options[:format])
|
141
119
|
@strings.language_codes.each do |lang|
|
142
120
|
if @options[:languages] == nil || @options[:languages].length == 0 || @options[:languages].include?(lang)
|
143
|
-
file_name = lang + formatter.
|
121
|
+
file_name = lang + formatter.extension
|
144
122
|
real_path = File.join(dir, file_name)
|
145
123
|
zip_path = File.join('Locales', file_name)
|
146
124
|
formatter.write_file(real_path, lang)
|
@@ -166,7 +144,7 @@ module Twine
|
|
166
144
|
FileUtils.mkdir_p(File.dirname(real_path))
|
167
145
|
zipfile.extract(entry.name, real_path)
|
168
146
|
begin
|
169
|
-
|
147
|
+
read_string_file(real_path)
|
170
148
|
rescue Twine::Error => e
|
171
149
|
Twine::stderr.puts "#{e.message}"
|
172
150
|
end
|
@@ -207,10 +185,12 @@ module Twine
|
|
207
185
|
errors << "Found duplicate string key(s):\n#{join_keys.call(duplicate_keys)}"
|
208
186
|
end
|
209
187
|
|
210
|
-
if
|
211
|
-
|
212
|
-
|
213
|
-
|
188
|
+
if @options[:pedantic]
|
189
|
+
if keys_without_tags.length == total_strings
|
190
|
+
errors << "None of your strings have tags."
|
191
|
+
elsif keys_without_tags.length > 0
|
192
|
+
errors << "Found strings without tags:\n#{join_keys.call(keys_without_tags)}"
|
193
|
+
end
|
214
194
|
end
|
215
195
|
|
216
196
|
unless invalid_keys.empty?
|
@@ -222,34 +202,64 @@ module Twine
|
|
222
202
|
Twine::stdout.puts "#{@options[:strings_file]} is valid."
|
223
203
|
end
|
224
204
|
|
205
|
+
private
|
206
|
+
|
207
|
+
def require_rubyzip
|
208
|
+
begin
|
209
|
+
require 'zip'
|
210
|
+
rescue LoadError
|
211
|
+
raise Twine::Error.new "You must run 'gem install rubyzip' in order to create or consume localization drops."
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
225
215
|
def determine_language_given_path(path)
|
226
216
|
code = File.basename(path, File.extname(path))
|
227
217
|
return code if @strings.language_codes.include? code
|
228
218
|
end
|
229
219
|
|
230
|
-
def
|
231
|
-
|
232
|
-
return formatter::FORMAT_NAME if formatter
|
220
|
+
def formatter_for_format(format)
|
221
|
+
find_formatter { |f| f.format_name == format }
|
233
222
|
end
|
234
223
|
|
235
|
-
def
|
236
|
-
formatter = Formatters.formatters.find
|
237
|
-
return
|
224
|
+
def find_formatter(&block)
|
225
|
+
formatter = Formatters.formatters.find &block
|
226
|
+
return nil unless formatter
|
227
|
+
formatter.strings = @strings
|
228
|
+
formatter.options = @options
|
229
|
+
formatter
|
238
230
|
end
|
239
231
|
|
240
|
-
def
|
241
|
-
|
242
|
-
|
232
|
+
def read_string_file(path, lang = nil)
|
233
|
+
unless File.file?(path)
|
234
|
+
raise Twine::Error.new("File does not exist: #{path}")
|
235
|
+
end
|
236
|
+
|
237
|
+
formatter, lang = prepare_read_write(path, lang)
|
238
|
+
|
239
|
+
formatter.read_file(path, lang)
|
243
240
|
end
|
244
241
|
|
245
|
-
|
242
|
+
def write_string_file(path, lang)
|
243
|
+
formatter, lang = prepare_read_write(path, lang)
|
244
|
+
formatter.write_file(path, lang)
|
245
|
+
end
|
246
246
|
|
247
|
-
def
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
247
|
+
def prepare_read_write(path, lang)
|
248
|
+
formatter_for_path = find_formatter { |f| f.extension == File.extname(path) }
|
249
|
+
formatter = formatter_for_format(@options[:format]) || formatter_for_path
|
250
|
+
|
251
|
+
unless formatter
|
252
|
+
raise Twine::Error.new "Unable to determine format of #{path}"
|
253
|
+
end
|
254
|
+
|
255
|
+
lang = lang || determine_language_given_path(path) || formatter.determine_language_given_path(path)
|
256
|
+
unless lang
|
257
|
+
raise Twine::Error.new "Unable to determine language for #{path}"
|
252
258
|
end
|
259
|
+
|
260
|
+
@strings.language_codes << lang unless @strings.language_codes.include? lang
|
261
|
+
|
262
|
+
return formatter, lang
|
253
263
|
end
|
254
264
|
end
|
255
265
|
end
|
data/lib/twine/version.rb
CHANGED
data/test/command_test_case.rb
CHANGED
@@ -5,8 +5,10 @@ class CommandTestCase < TwineTestCase
|
|
5
5
|
strings = Twine::StringsFile.new
|
6
6
|
strings.language_codes.concat KNOWN_LANGUAGES
|
7
7
|
|
8
|
-
formatter = formatter_class.new
|
9
|
-
|
8
|
+
formatter = formatter_class.new
|
9
|
+
formatter.strings = strings
|
10
|
+
Twine::Formatters.formatters.clear
|
11
|
+
Twine::Formatters.formatters << formatter
|
10
12
|
formatter
|
11
13
|
end
|
12
14
|
end
|
@@ -12,7 +12,8 @@ class TestAbstractFormatter < TwineTestCase
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
@formatter = Twine::Formatters::Abstract.new
|
15
|
+
@formatter = Twine::Formatters::Abstract.new
|
16
|
+
@formatter.strings = @strings
|
16
17
|
end
|
17
18
|
|
18
19
|
def test_set_translation_updates_existing_value
|
@@ -46,7 +47,9 @@ class TestAbstractFormatter < TwineTestCase
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def test_set_translation_consume_all_adds_new_key
|
49
|
-
formatter = Twine::Formatters::Abstract.new
|
50
|
+
formatter = Twine::Formatters::Abstract.new
|
51
|
+
formatter.strings = @strings
|
52
|
+
formatter.options = { consume_all: true }
|
50
53
|
formatter.set_translation_for_key 'new-key', 'en', 'new-key-english'
|
51
54
|
|
52
55
|
assert_equal 'new-key-english', @strings.strings_map['new-key'].translations['en']
|
@@ -54,14 +57,18 @@ class TestAbstractFormatter < TwineTestCase
|
|
54
57
|
|
55
58
|
def test_set_translation_consume_all_adds_tags
|
56
59
|
random_tag = SecureRandom.uuid
|
57
|
-
formatter = Twine::Formatters::Abstract.new
|
60
|
+
formatter = Twine::Formatters::Abstract.new
|
61
|
+
formatter.strings = @strings
|
62
|
+
formatter.options = { consume_all: true, tags: [random_tag] }
|
58
63
|
formatter.set_translation_for_key 'new-key', 'en', 'new-key-english'
|
59
64
|
|
60
65
|
assert_equal [random_tag], @strings.strings_map['new-key'].tags
|
61
66
|
end
|
62
67
|
|
63
68
|
def test_set_translation_adds_new_keys_to_category_uncategoriezed
|
64
|
-
formatter = Twine::Formatters::Abstract.new
|
69
|
+
formatter = Twine::Formatters::Abstract.new
|
70
|
+
formatter.strings = @strings
|
71
|
+
formatter.options = { consume_all: true }
|
65
72
|
formatter.set_translation_for_key 'new-key', 'en', 'new-key-english'
|
66
73
|
|
67
74
|
assert_equal 'Uncategorized', @strings.sections[0].name
|
@@ -80,7 +87,8 @@ class TestAbstractFormatter < TwineTestCase
|
|
80
87
|
end
|
81
88
|
end
|
82
89
|
|
83
|
-
@formatter = Twine::Formatters::Abstract.new
|
90
|
+
@formatter = Twine::Formatters::Abstract.new
|
91
|
+
@formatter.strings = @strings
|
84
92
|
end
|
85
93
|
|
86
94
|
def test_set_translation_does_not_add_unchanged_translation
|
@@ -108,14 +116,17 @@ class TestAbstractFormatter < TwineTestCase
|
|
108
116
|
end
|
109
117
|
|
110
118
|
def test_set_comment_for_key_does_not_update_comment
|
111
|
-
formatter = Twine::Formatters::Abstract.new
|
119
|
+
formatter = Twine::Formatters::Abstract.new
|
120
|
+
formatter.strings = @strings
|
112
121
|
formatter.set_comment_for_key('key', 'comment')
|
113
122
|
|
114
123
|
assert_nil formatter.strings.strings_map['key'].comment
|
115
124
|
end
|
116
125
|
|
117
126
|
def test_set_comment_for_key_updates_comment_with_update_comments
|
118
|
-
formatter = Twine::Formatters::Abstract.new
|
127
|
+
formatter = Twine::Formatters::Abstract.new
|
128
|
+
formatter.strings = @strings
|
129
|
+
formatter.options = { consume_comments: true }
|
119
130
|
formatter.set_comment_for_key('key', 'comment')
|
120
131
|
|
121
132
|
assert_equal 'comment', formatter.strings.strings_map['key'].comment
|
@@ -133,7 +144,9 @@ class TestAbstractFormatter < TwineTestCase
|
|
133
144
|
end
|
134
145
|
end
|
135
146
|
|
136
|
-
@formatter = Twine::Formatters::Abstract.new
|
147
|
+
@formatter = Twine::Formatters::Abstract.new
|
148
|
+
@formatter.strings = @strings
|
149
|
+
@formatter.options = { consume_comments: true }
|
137
150
|
end
|
138
151
|
|
139
152
|
def test_set_comment_does_not_add_unchanged_comment
|
data/test/test_cli.rb
CHANGED
@@ -21,6 +21,11 @@ class CLITestCase < TwineTestCase
|
|
21
21
|
assert_equal @strings_file_path, @options[:strings_file]
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_pedantic
|
25
|
+
parse "validate-strings-file #{@strings_file_path} --pedantic"
|
26
|
+
assert @options[:pedantic]
|
27
|
+
end
|
28
|
+
|
24
29
|
def test_missing_parameter
|
25
30
|
assert_raises Twine::Error do
|
26
31
|
parse 'validate-strings-file'
|
@@ -49,6 +54,11 @@ class CLITestCase < TwineTestCase
|
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
57
|
+
def test_validate
|
58
|
+
parse "generate-string-file #{@strings_file_path} #{@output_path} --validate"
|
59
|
+
assert @options[:validate]
|
60
|
+
end
|
61
|
+
|
52
62
|
def test_extra_parameter
|
53
63
|
assert_raises Twine::Error do
|
54
64
|
parse 'generate-string-file strings output extra'
|
@@ -77,6 +87,11 @@ class CLITestCase < TwineTestCase
|
|
77
87
|
end
|
78
88
|
end
|
79
89
|
|
90
|
+
def test_validate
|
91
|
+
parse "generate-all-string-files #{@strings_file_path} #{@output_dir} --validate"
|
92
|
+
assert @options[:validate]
|
93
|
+
end
|
94
|
+
|
80
95
|
def test_extra_parameter
|
81
96
|
assert_raises Twine::Error do
|
82
97
|
parse "generate-all-string-files strings output extra"
|
@@ -149,6 +164,11 @@ class CLITestCase < TwineTestCase
|
|
149
164
|
end
|
150
165
|
end
|
151
166
|
|
167
|
+
def test_validate
|
168
|
+
parse "generate-loc-drop #{@strings_file_path} #{@output_path} --format apple --validate"
|
169
|
+
assert @options[:validate]
|
170
|
+
end
|
171
|
+
|
152
172
|
def test_extra_parameter
|
153
173
|
assert_raises Twine::Error do
|
154
174
|
parse "generate-loc-drop strings output extra --format apple"
|
@@ -246,13 +266,13 @@ class CLITestCase < TwineTestCase
|
|
246
266
|
end
|
247
267
|
|
248
268
|
def test_format
|
249
|
-
random_format = Twine::Formatters.formatters.sample
|
269
|
+
random_format = Twine::Formatters.formatters.sample.format_name
|
250
270
|
parse_with "--format #{random_format}"
|
251
271
|
assert_equal random_format, @options[:format]
|
252
272
|
end
|
253
273
|
|
254
274
|
def test_format_ignores_case
|
255
|
-
random_format = Twine::Formatters.formatters.sample
|
275
|
+
random_format = Twine::Formatters.formatters.sample.format_name
|
256
276
|
parse_with "--format #{random_format.upcase}"
|
257
277
|
assert_equal random_format, @options[:format]
|
258
278
|
end
|
data/test/test_formatters.rb
CHANGED
@@ -17,7 +17,9 @@ class FormatterTest < TwineTestCase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
@strings = Twine::StringsFile.new
|
20
|
-
@formatter = formatter_class.new
|
20
|
+
@formatter = formatter_class.new
|
21
|
+
@formatter.strings = @strings
|
22
|
+
@formatter.options = { consume_all: true, consume_comments: true }
|
21
23
|
end
|
22
24
|
|
23
25
|
def assert_translations_read_correctly
|
@@ -66,7 +68,8 @@ class TestAndroidFormatter < FormatterTest
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def test_write_file_output_format
|
69
|
-
formatter = Twine::Formatters::Android.new
|
71
|
+
formatter = Twine::Formatters::Android.new
|
72
|
+
formatter.strings = @twine_file
|
70
73
|
formatter.write_file @output_path, 'en'
|
71
74
|
assert_equal content('formatter_android.xml'), output_content
|
72
75
|
end
|
@@ -111,7 +114,8 @@ class TestAppleFormatter < FormatterTest
|
|
111
114
|
end
|
112
115
|
|
113
116
|
def test_write_file_output_format
|
114
|
-
formatter = Twine::Formatters::Apple.new
|
117
|
+
formatter = Twine::Formatters::Apple.new
|
118
|
+
formatter.strings = @twine_file
|
115
119
|
formatter.write_file @output_path, 'en'
|
116
120
|
assert_equal content('formatter_apple.strings'), output_content
|
117
121
|
end
|
@@ -142,7 +146,8 @@ class TestJQueryFormatter < FormatterTest
|
|
142
146
|
end
|
143
147
|
|
144
148
|
def test_write_file_output_format
|
145
|
-
formatter = Twine::Formatters::JQuery.new
|
149
|
+
formatter = Twine::Formatters::JQuery.new
|
150
|
+
formatter.strings = @twine_file
|
146
151
|
formatter.write_file @output_path, 'en'
|
147
152
|
assert_equal content('formatter_jquery.json'), output_content
|
148
153
|
end
|
@@ -171,7 +176,8 @@ class TestGettextFormatter < FormatterTest
|
|
171
176
|
end
|
172
177
|
|
173
178
|
def test_write_file_output_format
|
174
|
-
formatter = Twine::Formatters::Gettext.new
|
179
|
+
formatter = Twine::Formatters::Gettext.new
|
180
|
+
formatter.strings = @twine_file
|
175
181
|
formatter.write_file @output_path, 'en'
|
176
182
|
assert_equal content('formatter_gettext.po'), output_content
|
177
183
|
end
|
@@ -192,7 +198,8 @@ class TestTizenFormatter < FormatterTest
|
|
192
198
|
end
|
193
199
|
|
194
200
|
def test_write_file_output_format
|
195
|
-
formatter = Twine::Formatters::Tizen.new
|
201
|
+
formatter = Twine::Formatters::Tizen.new
|
202
|
+
formatter.strings = @twine_file
|
196
203
|
formatter.write_file @output_path, 'en'
|
197
204
|
assert_equal content('formatter_tizen.xml'), output_content
|
198
205
|
end
|
@@ -211,7 +218,8 @@ class TestDjangoFormatter < FormatterTest
|
|
211
218
|
end
|
212
219
|
|
213
220
|
def test_write_file_output_format
|
214
|
-
formatter = Twine::Formatters::Django.new
|
221
|
+
formatter = Twine::Formatters::Django.new
|
222
|
+
formatter.strings = @twine_file
|
215
223
|
formatter.write_file @output_path, 'en'
|
216
224
|
assert_equal content('formatter_django.po'), output_content
|
217
225
|
end
|
@@ -229,7 +237,8 @@ class TestFlashFormatter < FormatterTest
|
|
229
237
|
end
|
230
238
|
|
231
239
|
def test_write_file_output_format
|
232
|
-
formatter = Twine::Formatters::Flash.new
|
240
|
+
formatter = Twine::Formatters::Flash.new
|
241
|
+
formatter.strings = @twine_file
|
233
242
|
formatter.write_file @output_path, 'en'
|
234
243
|
assert_equal content('formatter_flash.properties'), output_content
|
235
244
|
end
|
@@ -8,13 +8,13 @@ class TestGenerateAllStringFiles < CommandTestCase
|
|
8
8
|
options[:format] = 'apple'
|
9
9
|
options[:create_folders] = create_folders
|
10
10
|
|
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
16
|
|
17
|
-
Twine::Runner.new(options,
|
17
|
+
Twine::Runner.new(options, twine_file)
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_fails_if_output_folder_does_not_exist
|
@@ -41,4 +41,36 @@ class TestGenerateAllStringFiles < CommandTestCase
|
|
41
41
|
assert File.exists?(File.join(@output_dir, 'es.lproj')), "language folder 'es.lproj' should be created"
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
class TestDeliberate < CommandTestCase
|
46
|
+
def new_runner(validate)
|
47
|
+
Dir.mkdir File.join @output_dir, 'values-en'
|
48
|
+
|
49
|
+
options = {}
|
50
|
+
options[:output_path] = @output_dir
|
51
|
+
options[:format] = 'android'
|
52
|
+
options[:validate] = validate
|
53
|
+
|
54
|
+
twine_file = build_twine_file 'en' do
|
55
|
+
add_section 'Section' do
|
56
|
+
add_row key: 'value'
|
57
|
+
add_row key: 'value'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Twine::Runner.new(options, twine_file)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_does_not_validate_strings_file
|
65
|
+
prepare_mock_formatter Twine::Formatters::Android
|
66
|
+
|
67
|
+
new_runner(false).generate_all_string_files
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_validates_strings_file_if_validate
|
71
|
+
assert_raises Twine::Error do
|
72
|
+
new_runner(true).generate_all_string_files
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
44
76
|
end
|
@@ -41,4 +41,34 @@ class TestGenerateLocDrop < CommandTestCase
|
|
41
41
|
|
42
42
|
@runner.generate_loc_drop
|
43
43
|
end
|
44
|
+
|
45
|
+
class TestDeliberate < CommandTestCase
|
46
|
+
def new_runner(validate)
|
47
|
+
options = {}
|
48
|
+
options[:output_path] = @output_path
|
49
|
+
options[:format] = 'android'
|
50
|
+
options[:validate] = validate
|
51
|
+
|
52
|
+
twine_file = build_twine_file 'en' do
|
53
|
+
add_section 'Section' do
|
54
|
+
add_row key: 'value'
|
55
|
+
add_row key: 'value'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Twine::Runner.new(options, twine_file)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_does_not_validate_strings_file
|
63
|
+
prepare_mock_formatter Twine::Formatters::Android
|
64
|
+
|
65
|
+
new_runner(false).generate_loc_drop
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_validates_strings_file_if_validate
|
69
|
+
assert_raises Twine::Error do
|
70
|
+
new_runner(true).generate_loc_drop
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
44
74
|
end
|
@@ -6,10 +6,10 @@ class TestGenerateStringFile < CommandTestCase
|
|
6
6
|
options[:output_path] = File.join(@output_dir, file) if file
|
7
7
|
options[:languages] = language if language
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
strings = Twine::StringsFile.new
|
10
|
+
strings.language_codes.concat KNOWN_LANGUAGES
|
11
11
|
|
12
|
-
Twine::Runner.new(options,
|
12
|
+
Twine::Runner.new(options, strings)
|
13
13
|
end
|
14
14
|
|
15
15
|
def prepare_mock_write_file_formatter(formatter_class)
|
@@ -48,4 +48,35 @@ class TestGenerateStringFile < CommandTestCase
|
|
48
48
|
|
49
49
|
new_runner(nil, "#{random_language}.xml").generate_string_file
|
50
50
|
end
|
51
|
+
|
52
|
+
class TestDeliberate < CommandTestCase
|
53
|
+
def new_runner(validate)
|
54
|
+
options = {}
|
55
|
+
options[:output_path] = @output_path
|
56
|
+
options[:languages] = ['en']
|
57
|
+
options[:format] = 'android'
|
58
|
+
options[:validate] = validate
|
59
|
+
|
60
|
+
twine_file = build_twine_file 'en' do
|
61
|
+
add_section 'Section' do
|
62
|
+
add_row key: 'value'
|
63
|
+
add_row key: 'value'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Twine::Runner.new(options, twine_file)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_does_not_validate_strings_file
|
71
|
+
prepare_mock_formatter Twine::Formatters::Android
|
72
|
+
|
73
|
+
new_runner(false).generate_string_file
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_validates_strings_file_if_validate
|
77
|
+
assert_raises Twine::Error do
|
78
|
+
new_runner(true).generate_string_file
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
51
82
|
end
|
@@ -37,19 +37,25 @@ class TestValidateStringsFile < CommandTestCase
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
41
|
-
random_row.
|
40
|
+
def test_reports_invalid_characters_in_keys
|
41
|
+
random_row.key[0] = "!?;:,^`´'\"\\|/(){}[]~-+*=#$%".chars.to_a.sample
|
42
42
|
|
43
43
|
assert_raises Twine::Error do
|
44
44
|
Twine::Runner.new(@options, @twine_file).validate_strings_file
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
49
|
-
random_row.
|
48
|
+
def test_does_not_reports_missing_tags_by_default
|
49
|
+
random_row.tags.clear
|
50
|
+
|
51
|
+
Twine::Runner.new(@options, @twine_file).validate_strings_file
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_reports_missing_tags
|
55
|
+
random_row.tags.clear
|
50
56
|
|
51
57
|
assert_raises Twine::Error do
|
52
|
-
Twine::Runner.new(@options, @twine_file).validate_strings_file
|
58
|
+
Twine::Runner.new(@options.merge(pedantic: true), @twine_file).validate_strings_file
|
53
59
|
end
|
54
60
|
end
|
55
61
|
end
|
data/test/twine_test_case.rb
CHANGED
@@ -15,12 +15,17 @@ class TwineTestCase < Minitest::Test
|
|
15
15
|
super
|
16
16
|
Twine::stdout = StringIO.new
|
17
17
|
Twine::stderr = StringIO.new
|
18
|
+
|
19
|
+
@formatters = Twine::Formatters.formatters.dup
|
20
|
+
|
18
21
|
@output_dir = Dir.mktmpdir
|
19
22
|
@output_path = File.join @output_dir, SecureRandom.uuid
|
20
23
|
end
|
21
24
|
|
22
25
|
def teardown
|
23
26
|
FileUtils.remove_entry_secure @output_dir if File.exists? @output_dir
|
27
|
+
Twine::Formatters.formatters.clear
|
28
|
+
Twine::Formatters.formatters.concat @formatters
|
24
29
|
super
|
25
30
|
end
|
26
31
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -150,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
150
|
requirements:
|
151
151
|
- - ">="
|
152
152
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
153
|
+
version: '2.0'
|
154
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
155
|
requirements:
|
156
156
|
- - ">="
|