twine 0.9.1 → 0.10.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 +56 -69
- data/lib/twine.rb +11 -3
- data/lib/twine/cli.rb +375 -155
- data/lib/twine/formatters.rb +0 -5
- data/lib/twine/formatters/abstract.rb +43 -43
- data/lib/twine/formatters/android.rb +58 -59
- data/lib/twine/formatters/apple.rb +3 -3
- data/lib/twine/formatters/django.rb +15 -21
- data/lib/twine/formatters/flash.rb +17 -20
- data/lib/twine/formatters/gettext.rb +11 -15
- data/lib/twine/formatters/jquery.rb +8 -11
- data/lib/twine/formatters/tizen.rb +4 -4
- data/lib/twine/output_processor.rb +15 -15
- data/lib/twine/placeholders.rb +26 -6
- data/lib/twine/runner.rb +95 -95
- data/lib/twine/{stringsfile.rb → twine_file.rb} +53 -48
- data/lib/twine/version.rb +1 -1
- data/test/{command_test_case.rb → command_test.rb} +5 -5
- data/test/fixtures/{consume_loc_drop.zip → consume_localization_archive.zip} +0 -0
- data/test/fixtures/formatter_django.po +3 -1
- data/test/test_abstract_formatter.rb +40 -40
- data/test/test_cli.rb +313 -211
- data/test/test_consume_localization_archive.rb +27 -0
- data/test/{test_consume_string_file.rb → test_consume_localization_file.rb} +19 -19
- data/test/test_formatters.rb +108 -43
- data/test/{test_generate_all_string_files.rb → test_generate_all_localization_files.rb} +18 -18
- data/test/{test_generate_loc_drop.rb → test_generate_localization_archive.rb} +14 -14
- data/test/{test_generate_string_file.rb → test_generate_localization_file.rb} +18 -18
- data/test/test_output_processor.rb +26 -26
- data/test/test_placeholders.rb +44 -9
- data/test/test_twine_definition.rb +111 -0
- data/test/test_twine_file.rb +58 -0
- data/test/test_validate_twine_file.rb +61 -0
- data/test/twine_file_dsl.rb +12 -12
- data/test/{twine_test_case.rb → twine_test.rb} +1 -1
- metadata +23 -23
- data/test/test_consume_loc_drop.rb +0 -27
- data/test/test_strings_file.rb +0 -58
- data/test/test_strings_row.rb +0 -47
- data/test/test_validate_strings_file.rb +0 -61
@@ -11,12 +11,8 @@ module Twine
|
|
11
11
|
'.po'
|
12
12
|
end
|
13
13
|
|
14
|
-
def can_handle_directory?(path)
|
15
|
-
Dir.entries(path).any? { |item| /^.+\.po$/.match(item) }
|
16
|
-
end
|
17
|
-
|
18
14
|
def default_file_name
|
19
|
-
|
15
|
+
'strings.po'
|
20
16
|
end
|
21
17
|
|
22
18
|
def determine_language_given_path(path)
|
@@ -64,7 +60,7 @@ module Twine
|
|
64
60
|
end
|
65
61
|
|
66
62
|
def format_file(lang)
|
67
|
-
@default_lang =
|
63
|
+
@default_lang = twine_file.language_codes[0]
|
68
64
|
result = super
|
69
65
|
@default_lang = nil
|
70
66
|
result
|
@@ -78,25 +74,25 @@ module Twine
|
|
78
74
|
"# SECTION: #{section.name}"
|
79
75
|
end
|
80
76
|
|
81
|
-
def
|
82
|
-
super and
|
77
|
+
def should_include_definition(definition, lang)
|
78
|
+
super and !definition.translation_for_lang(@default_lang).nil?
|
83
79
|
end
|
84
80
|
|
85
|
-
def format_comment(
|
86
|
-
"#. \"#{escape_quotes(
|
81
|
+
def format_comment(definition, lang)
|
82
|
+
"#. \"#{escape_quotes(definition.comment)}\"\n" if definition.comment
|
87
83
|
end
|
88
84
|
|
89
|
-
def format_key_value(
|
90
|
-
value =
|
91
|
-
[format_key(
|
85
|
+
def format_key_value(definition, lang)
|
86
|
+
value = definition.translation_for_lang(lang)
|
87
|
+
[format_key(definition.key.dup), format_base_translation(definition), format_value(value.dup)].compact.join
|
92
88
|
end
|
93
89
|
|
94
90
|
def format_key(key)
|
95
91
|
"msgctxt \"#{key}\"\n"
|
96
92
|
end
|
97
93
|
|
98
|
-
def format_base_translation(
|
99
|
-
"msgid \"#{
|
94
|
+
def format_base_translation(definition)
|
95
|
+
"msgid \"#{definition.translations[@default_lang]}\"\n"
|
100
96
|
end
|
101
97
|
|
102
98
|
def format_value(value)
|
@@ -9,12 +9,8 @@ module Twine
|
|
9
9
|
'.json'
|
10
10
|
end
|
11
11
|
|
12
|
-
def can_handle_directory?(path)
|
13
|
-
Dir.entries(path).any? { |item| /^.+\.json$/.match(item) }
|
14
|
-
end
|
15
|
-
|
16
12
|
def default_file_name
|
17
|
-
|
13
|
+
'localize.json'
|
18
14
|
end
|
19
15
|
|
20
16
|
def determine_language_given_path(path)
|
@@ -48,8 +44,9 @@ module Twine
|
|
48
44
|
"{\n#{super}\n}\n"
|
49
45
|
end
|
50
46
|
|
51
|
-
def format_sections(
|
52
|
-
sections =
|
47
|
+
def format_sections(twine_file, lang)
|
48
|
+
sections = twine_file.sections.map { |section| format_section(section, lang) }
|
49
|
+
sections.delete_if &:empty?
|
53
50
|
sections.join(",\n\n")
|
54
51
|
end
|
55
52
|
|
@@ -57,11 +54,11 @@ module Twine
|
|
57
54
|
end
|
58
55
|
|
59
56
|
def format_section(section, lang)
|
60
|
-
|
57
|
+
definitions = section.definitions.dup
|
61
58
|
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
definitions.map! { |definition| format_definition(definition, lang) }
|
60
|
+
definitions.compact! # remove nil definitions
|
61
|
+
definitions.join(",\n")
|
65
62
|
end
|
66
63
|
|
67
64
|
def key_value_pattern
|
@@ -33,7 +33,7 @@ module Twine
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def default_file_name
|
36
|
-
|
36
|
+
'strings.xml'
|
37
37
|
end
|
38
38
|
|
39
39
|
def determine_language_given_path(path)
|
@@ -94,7 +94,7 @@ module Twine
|
|
94
94
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Tizen Strings File -->\n<!-- Generated by Twine #{Twine::VERSION} -->\n<!-- Language: #{lang} -->"
|
95
95
|
end
|
96
96
|
|
97
|
-
def format_sections(
|
97
|
+
def format_sections(twine_file, lang)
|
98
98
|
result = '<string_table Bversion="2.0.0.201311071819" Dversion="20120315">'
|
99
99
|
|
100
100
|
result += super + "\n"
|
@@ -106,8 +106,8 @@ module Twine
|
|
106
106
|
"\t<!-- SECTION: #{section.name} -->"
|
107
107
|
end
|
108
108
|
|
109
|
-
def format_comment(
|
110
|
-
"\t<!-- #{
|
109
|
+
def format_comment(definition, lang)
|
110
|
+
"\t<!-- #{definition.comment.gsub('--', '—')} -->\n" if definition.comment
|
111
111
|
end
|
112
112
|
|
113
113
|
def key_value_pattern
|
@@ -2,13 +2,13 @@ module Twine
|
|
2
2
|
module Processors
|
3
3
|
|
4
4
|
class OutputProcessor
|
5
|
-
def initialize(
|
6
|
-
@
|
5
|
+
def initialize(twine_file, options)
|
6
|
+
@twine_file = twine_file
|
7
7
|
@options = options
|
8
8
|
end
|
9
9
|
|
10
10
|
def default_language
|
11
|
-
@options[:developer_language] || @
|
11
|
+
@options[:developer_language] || @twine_file.language_codes[0]
|
12
12
|
end
|
13
13
|
|
14
14
|
def fallback_languages(language)
|
@@ -20,30 +20,30 @@ module Twine
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def process(language)
|
23
|
-
result =
|
23
|
+
result = TwineFile.new
|
24
24
|
|
25
|
-
result.language_codes.concat @
|
26
|
-
@
|
27
|
-
new_section =
|
25
|
+
result.language_codes.concat @twine_file.language_codes
|
26
|
+
@twine_file.sections.each do |section|
|
27
|
+
new_section = TwineSection.new section.name
|
28
28
|
|
29
|
-
section.
|
30
|
-
next unless
|
29
|
+
section.definitions.each do |definition|
|
30
|
+
next unless definition.matches_tags?(@options[:tags], @options[:untagged])
|
31
31
|
|
32
|
-
value =
|
32
|
+
value = definition.translation_for_lang(language)
|
33
33
|
|
34
34
|
next if value && @options[:include] == :untranslated
|
35
35
|
|
36
36
|
if value.nil? && @options[:include] != :translated
|
37
|
-
value =
|
37
|
+
value = definition.translation_for_lang(fallback_languages(language))
|
38
38
|
end
|
39
39
|
|
40
40
|
next unless value
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
new_definition = definition.dup
|
43
|
+
new_definition.translations[language] = value
|
44
44
|
|
45
|
-
new_section.
|
46
|
-
result.
|
45
|
+
new_section.definitions << new_definition
|
46
|
+
result.definitions_by_key[new_definition.key] = new_definition
|
47
47
|
end
|
48
48
|
|
49
49
|
result.sections << new_section
|
data/lib/twine/placeholders.rb
CHANGED
@@ -2,19 +2,24 @@ module Twine
|
|
2
2
|
module Placeholders
|
3
3
|
extend self
|
4
4
|
|
5
|
-
|
5
|
+
# Note: the ` ` (single space) flag is NOT supported
|
6
|
+
PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH = '([-+0#])?(\d+|\*)?(\.(\d+|\*))?(hh?|ll?|L|z|j|t)?'
|
6
7
|
PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH = '(\d+\$)?' + PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH
|
8
|
+
PLACEHOLDER_TYPES = '[diufFeEgGxXoscpaA]'
|
9
|
+
|
10
|
+
def convert_twine_string_placeholder(input)
|
11
|
+
# %@ -> %s
|
12
|
+
input.gsub(/(%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH})@/, '\1s')
|
13
|
+
end
|
7
14
|
|
8
15
|
# http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
|
9
16
|
# http://stackoverflow.com/questions/4414389/android-xml-percent-symbol
|
10
17
|
# https://github.com/mobiata/twine/pull/106
|
11
18
|
def convert_placeholders_from_twine_to_android(input)
|
12
|
-
placeholder_types = '[diufFeEgGxXoscpaA]'
|
13
|
-
|
14
19
|
# %@ -> %s
|
15
|
-
value = input
|
20
|
+
value = convert_twine_string_placeholder(input)
|
16
21
|
|
17
|
-
placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH +
|
22
|
+
placeholder_syntax = PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH + PLACEHOLDER_TYPES
|
18
23
|
placeholder_regex = /%#{placeholder_syntax}/
|
19
24
|
|
20
25
|
number_of_placeholders = value.scan(placeholder_regex).size
|
@@ -29,7 +34,7 @@ module Twine
|
|
29
34
|
return value if number_of_placeholders < 2
|
30
35
|
|
31
36
|
# number placeholders
|
32
|
-
non_numbered_placeholder_regex = /%(#{PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH}#{
|
37
|
+
non_numbered_placeholder_regex = /%(#{PLACEHOLDER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES})/
|
33
38
|
|
34
39
|
number_of_non_numbered_placeholders = value.scan(non_numbered_placeholder_regex).size
|
35
40
|
|
@@ -50,5 +55,20 @@ module Twine
|
|
50
55
|
# %s -> %@
|
51
56
|
input.gsub(placeholder_regex, '\1@')
|
52
57
|
end
|
58
|
+
|
59
|
+
# http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#getString()
|
60
|
+
# http://soenkerohde.com/2008/07/flex-localization/comment-page-1/
|
61
|
+
def convert_placeholders_from_twine_to_flash(input)
|
62
|
+
value = convert_twine_string_placeholder(input)
|
63
|
+
|
64
|
+
placeholder_regex = /%#{PLACEHOLDER_PARAMETER_FLAGS_WIDTH_PRECISION_LENGTH}#{PLACEHOLDER_TYPES}/
|
65
|
+
value.gsub(placeholder_regex).each_with_index do |match, index|
|
66
|
+
"{#{index}}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def convert_placeholders_from_flash_to_twine(input)
|
71
|
+
input.gsub /\{\d+\}/, '%@'
|
72
|
+
end
|
53
73
|
end
|
54
74
|
end
|
data/lib/twine/runner.rb
CHANGED
@@ -8,42 +8,42 @@ module Twine
|
|
8
8
|
def self.run(args)
|
9
9
|
options = CLI.parse(args)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
runner = new(options,
|
11
|
+
twine_file = TwineFile.new
|
12
|
+
twine_file.read options[:twine_file]
|
13
|
+
runner = new(options, twine_file)
|
14
14
|
|
15
15
|
case options[:command]
|
16
|
-
when 'generate-
|
17
|
-
runner.
|
18
|
-
when 'generate-all-
|
19
|
-
runner.
|
20
|
-
when 'consume-
|
21
|
-
runner.
|
22
|
-
when 'consume-all-
|
23
|
-
runner.
|
24
|
-
when 'generate-
|
25
|
-
runner.
|
26
|
-
when 'consume-
|
27
|
-
runner.
|
28
|
-
when 'validate-
|
29
|
-
runner.
|
16
|
+
when 'generate-localization-file'
|
17
|
+
runner.generate_localization_file
|
18
|
+
when 'generate-all-localization-files'
|
19
|
+
runner.generate_all_localization_files
|
20
|
+
when 'consume-localization-file'
|
21
|
+
runner.consume_localization_file
|
22
|
+
when 'consume-all-localization-files'
|
23
|
+
runner.consume_all_localization_files
|
24
|
+
when 'generate-localization-archive'
|
25
|
+
runner.generate_localization_archive
|
26
|
+
when 'consume-localization-archive'
|
27
|
+
runner.consume_localization_archive
|
28
|
+
when 'validate-twine-file'
|
29
|
+
runner.validate_twine_file
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def initialize(options = {},
|
33
|
+
def initialize(options = {}, twine_file = TwineFile.new)
|
34
34
|
@options = options
|
35
|
-
@
|
35
|
+
@twine_file = twine_file
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def write_twine_data(path)
|
39
39
|
if @options[:developer_language]
|
40
|
-
@
|
40
|
+
@twine_file.set_developer_language_code(@options[:developer_language])
|
41
41
|
end
|
42
|
-
@
|
42
|
+
@twine_file.write(path)
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
|
45
|
+
def generate_localization_file
|
46
|
+
validate_twine_file if @options[:validate]
|
47
47
|
|
48
48
|
lang = nil
|
49
49
|
lang = @options[:languages][0] if @options[:languages]
|
@@ -51,13 +51,13 @@ module Twine
|
|
51
51
|
formatter, lang = prepare_read_write(@options[:output_path], lang)
|
52
52
|
output = formatter.format_file(lang)
|
53
53
|
|
54
|
-
raise Twine::Error.new "Nothing to generate! The resulting file would not contain any
|
54
|
+
raise Twine::Error.new "Nothing to generate! The resulting file would not contain any translations." unless output
|
55
55
|
|
56
|
-
IO.write(@options[:output_path], output, encoding:
|
56
|
+
IO.write(@options[:output_path], output, encoding: output_encoding)
|
57
57
|
end
|
58
58
|
|
59
|
-
def
|
60
|
-
|
59
|
+
def generate_all_localization_files
|
60
|
+
validate_twine_file if @options[:validate]
|
61
61
|
|
62
62
|
if !File.directory?(@options[:output_path])
|
63
63
|
if @options[:create_folders]
|
@@ -76,7 +76,7 @@ module Twine
|
|
76
76
|
|
77
77
|
file_name = @options[:file_name] || formatter.default_file_name
|
78
78
|
if @options[:create_folders]
|
79
|
-
@
|
79
|
+
@twine_file.language_codes.each do |lang|
|
80
80
|
output_path = File.join(@options[:output_path], formatter.output_path_for_language(lang))
|
81
81
|
|
82
82
|
FileUtils.mkdir_p(output_path)
|
@@ -85,11 +85,11 @@ module Twine
|
|
85
85
|
|
86
86
|
output = formatter.format_file(lang)
|
87
87
|
unless output
|
88
|
-
Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any
|
88
|
+
Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any translations."
|
89
89
|
next
|
90
90
|
end
|
91
91
|
|
92
|
-
IO.write(file_path, output, encoding:
|
92
|
+
IO.write(file_path, output, encoding: output_encoding)
|
93
93
|
end
|
94
94
|
else
|
95
95
|
language_found = false
|
@@ -107,11 +107,11 @@ module Twine
|
|
107
107
|
file_path = File.join(output_path, file_name)
|
108
108
|
output = formatter.format_file(lang)
|
109
109
|
unless output
|
110
|
-
Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any
|
110
|
+
Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any translations."
|
111
111
|
next
|
112
112
|
end
|
113
113
|
|
114
|
-
IO.write(file_path, output, encoding:
|
114
|
+
IO.write(file_path, output, encoding: output_encoding)
|
115
115
|
end
|
116
116
|
|
117
117
|
unless language_found
|
@@ -121,38 +121,8 @@ module Twine
|
|
121
121
|
|
122
122
|
end
|
123
123
|
|
124
|
-
def
|
125
|
-
|
126
|
-
if @options[:languages]
|
127
|
-
lang = @options[:languages][0]
|
128
|
-
end
|
129
|
-
|
130
|
-
read_string_file(@options[:input_path], lang)
|
131
|
-
output_path = @options[:output_path] || @options[:strings_file]
|
132
|
-
write_strings_data(output_path)
|
133
|
-
end
|
134
|
-
|
135
|
-
def consume_all_string_files
|
136
|
-
if !File.directory?(@options[:input_path])
|
137
|
-
raise Twine::Error.new("Directory does not exist: #{@options[:output_path]}")
|
138
|
-
end
|
139
|
-
|
140
|
-
Dir.glob(File.join(@options[:input_path], "**/*")) do |item|
|
141
|
-
if File.file?(item)
|
142
|
-
begin
|
143
|
-
read_string_file(item)
|
144
|
-
rescue Twine::Error => e
|
145
|
-
Twine::stderr.puts "#{e.message}"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
output_path = @options[:output_path] || @options[:strings_file]
|
151
|
-
write_strings_data(output_path)
|
152
|
-
end
|
153
|
-
|
154
|
-
def generate_loc_drop
|
155
|
-
validate_strings_file if @options[:validate]
|
124
|
+
def generate_localization_archive
|
125
|
+
validate_twine_file if @options[:validate]
|
156
126
|
|
157
127
|
require_rubyzip
|
158
128
|
|
@@ -165,7 +135,7 @@ module Twine
|
|
165
135
|
zipfile.mkdir('Locales')
|
166
136
|
|
167
137
|
formatter = formatter_for_format(@options[:format])
|
168
|
-
@
|
138
|
+
@twine_file.language_codes.each do |lang|
|
169
139
|
if @options[:languages] == nil || @options[:languages].length == 0 || @options[:languages].include?(lang)
|
170
140
|
file_name = lang + formatter.extension
|
171
141
|
temp_path = File.join(temp_dir, file_name)
|
@@ -173,11 +143,11 @@ module Twine
|
|
173
143
|
|
174
144
|
output = formatter.format_file(lang)
|
175
145
|
unless output
|
176
|
-
Twine::stderr.puts "Skipping file #{file_name} since it would not contain any
|
146
|
+
Twine::stderr.puts "Skipping file #{file_name} since it would not contain any translations."
|
177
147
|
next
|
178
148
|
end
|
179
149
|
|
180
|
-
IO.write(temp_path, output, encoding:
|
150
|
+
IO.write(temp_path, output, encoding: output_encoding)
|
181
151
|
zipfile.add(zip_path, temp_path)
|
182
152
|
end
|
183
153
|
end
|
@@ -185,7 +155,37 @@ module Twine
|
|
185
155
|
end
|
186
156
|
end
|
187
157
|
|
188
|
-
def
|
158
|
+
def consume_localization_file
|
159
|
+
lang = nil
|
160
|
+
if @options[:languages]
|
161
|
+
lang = @options[:languages][0]
|
162
|
+
end
|
163
|
+
|
164
|
+
read_localization_file(@options[:input_path], lang)
|
165
|
+
output_path = @options[:output_path] || @options[:twine_file]
|
166
|
+
write_twine_data(output_path)
|
167
|
+
end
|
168
|
+
|
169
|
+
def consume_all_localization_files
|
170
|
+
if !File.directory?(@options[:input_path])
|
171
|
+
raise Twine::Error.new("Directory does not exist: #{@options[:input_path]}")
|
172
|
+
end
|
173
|
+
|
174
|
+
Dir.glob(File.join(@options[:input_path], "**/*")) do |item|
|
175
|
+
if File.file?(item)
|
176
|
+
begin
|
177
|
+
read_localization_file(item)
|
178
|
+
rescue Twine::Error => e
|
179
|
+
Twine::stderr.puts "#{e.message}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
output_path = @options[:output_path] || @options[:twine_file]
|
185
|
+
write_twine_data(output_path)
|
186
|
+
end
|
187
|
+
|
188
|
+
def consume_localization_archive
|
189
189
|
require_rubyzip
|
190
190
|
|
191
191
|
if !File.file?(@options[:input_path])
|
@@ -201,7 +201,7 @@ module Twine
|
|
201
201
|
FileUtils.mkdir_p(File.dirname(real_path))
|
202
202
|
zipfile.extract(entry.name, real_path)
|
203
203
|
begin
|
204
|
-
|
204
|
+
read_localization_file(real_path)
|
205
205
|
rescue Twine::Error => e
|
206
206
|
Twine::stderr.puts "#{e.message}"
|
207
207
|
end
|
@@ -209,28 +209,28 @@ module Twine
|
|
209
209
|
end
|
210
210
|
end
|
211
211
|
|
212
|
-
output_path = @options[:output_path] || @options[:
|
213
|
-
|
212
|
+
output_path = @options[:output_path] || @options[:twine_file]
|
213
|
+
write_twine_data(output_path)
|
214
214
|
end
|
215
215
|
|
216
|
-
def
|
217
|
-
|
216
|
+
def validate_twine_file
|
217
|
+
total_definitions = 0
|
218
218
|
all_keys = Set.new
|
219
219
|
duplicate_keys = Set.new
|
220
220
|
keys_without_tags = Set.new
|
221
221
|
invalid_keys = Set.new
|
222
222
|
valid_key_regex = /^[A-Za-z0-9_]+$/
|
223
223
|
|
224
|
-
@
|
225
|
-
section.
|
226
|
-
|
224
|
+
@twine_file.sections.each do |section|
|
225
|
+
section.definitions.each do |definition|
|
226
|
+
total_definitions += 1
|
227
227
|
|
228
|
-
duplicate_keys.add(
|
229
|
-
all_keys.add(
|
228
|
+
duplicate_keys.add(definition.key) if all_keys.include? definition.key
|
229
|
+
all_keys.add(definition.key)
|
230
230
|
|
231
|
-
keys_without_tags.add(
|
231
|
+
keys_without_tags.add(definition.key) if definition.tags == nil or definition.tags.length == 0
|
232
232
|
|
233
|
-
invalid_keys <<
|
233
|
+
invalid_keys << definition.key unless definition.key =~ valid_key_regex
|
234
234
|
end
|
235
235
|
end
|
236
236
|
|
@@ -238,14 +238,14 @@ module Twine
|
|
238
238
|
join_keys = lambda { |set| set.map { |k| " " + k }.join("\n") }
|
239
239
|
|
240
240
|
unless duplicate_keys.empty?
|
241
|
-
errors << "Found duplicate
|
241
|
+
errors << "Found duplicate key(s):\n#{join_keys.call(duplicate_keys)}"
|
242
242
|
end
|
243
243
|
|
244
244
|
if @options[:pedantic]
|
245
|
-
if keys_without_tags.length ==
|
246
|
-
errors << "None of your
|
245
|
+
if keys_without_tags.length == total_definitions
|
246
|
+
errors << "None of your definitions have tags."
|
247
247
|
elsif keys_without_tags.length > 0
|
248
|
-
errors << "Found
|
248
|
+
errors << "Found definitions without tags:\n#{join_keys.call(keys_without_tags)}"
|
249
249
|
end
|
250
250
|
end
|
251
251
|
|
@@ -255,26 +255,26 @@ module Twine
|
|
255
255
|
|
256
256
|
raise Twine::Error.new errors.join("\n\n") unless errors.empty?
|
257
257
|
|
258
|
-
Twine::stdout.puts "#{@options[:
|
258
|
+
Twine::stdout.puts "#{@options[:twine_file]} is valid."
|
259
259
|
end
|
260
260
|
|
261
261
|
private
|
262
262
|
|
263
|
-
def
|
264
|
-
@options[:
|
263
|
+
def output_encoding
|
264
|
+
@options[:encoding] || 'UTF-8'
|
265
265
|
end
|
266
266
|
|
267
267
|
def require_rubyzip
|
268
268
|
begin
|
269
269
|
require 'zip'
|
270
270
|
rescue LoadError
|
271
|
-
raise Twine::Error.new "You must run 'gem install rubyzip' in order to create or consume localization
|
271
|
+
raise Twine::Error.new "You must run 'gem install rubyzip' in order to create or consume localization archives."
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
275
275
|
def determine_language_given_path(path)
|
276
276
|
code = File.basename(path, File.extname(path))
|
277
|
-
return code if @
|
277
|
+
return code if @twine_file.language_codes.include? code
|
278
278
|
end
|
279
279
|
|
280
280
|
def formatter_for_format(format)
|
@@ -284,21 +284,21 @@ module Twine
|
|
284
284
|
def find_formatter(&block)
|
285
285
|
formatter = Formatters.formatters.find &block
|
286
286
|
return nil unless formatter
|
287
|
-
formatter.
|
287
|
+
formatter.twine_file = @twine_file
|
288
288
|
formatter.options = @options
|
289
289
|
formatter
|
290
290
|
end
|
291
291
|
|
292
|
-
def
|
292
|
+
def read_localization_file(path, lang = nil)
|
293
293
|
unless File.file?(path)
|
294
294
|
raise Twine::Error.new("File does not exist: #{path}")
|
295
295
|
end
|
296
296
|
|
297
297
|
formatter, lang = prepare_read_write(path, lang)
|
298
298
|
|
299
|
-
|
299
|
+
external_encoding = @options[:encoding] || Twine::Encoding.encoding_for_path(path)
|
300
300
|
|
301
|
-
IO.open(IO.sysopen(path, 'rb'), 'rb', external_encoding:
|
301
|
+
IO.open(IO.sysopen(path, 'rb'), 'rb', external_encoding: external_encoding, internal_encoding: 'UTF-8') do |io|
|
302
302
|
io.read(2) if Twine::Encoding.has_bom?(path)
|
303
303
|
formatter.read(io, lang)
|
304
304
|
end
|
@@ -317,7 +317,7 @@ module Twine
|
|
317
317
|
raise Twine::Error.new "Unable to determine language for #{path}"
|
318
318
|
end
|
319
319
|
|
320
|
-
@
|
320
|
+
@twine_file.language_codes << lang unless @twine_file.language_codes.include? lang
|
321
321
|
|
322
322
|
return formatter, lang
|
323
323
|
end
|