twine 0.9.1 → 0.10.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 +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
|