traduco 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,301 @@
1
+ require 'tmpdir'
2
+
3
+ module Traduco
4
+ VALID_COMMANDS = ['generate-string-file', 'generate-all-string-files', 'consume-string-file', 'consume-all-string-files', 'generate-loc-drop', 'consume-loc-drop', 'generate-report']
5
+
6
+ class Runner
7
+ def initialize(args)
8
+ @options = {}
9
+ @args = args
10
+ end
11
+
12
+ def self.run(args)
13
+ new(args).run
14
+ end
15
+
16
+ def run
17
+ # Parse all CLI arguments.
18
+ CLI::parse_args(@args, @options)
19
+ read_strings_data
20
+ execute_command
21
+ end
22
+
23
+ def read_strings_data
24
+ @strings = StringsFile.new
25
+ @strings.read @options[:strings_file]
26
+ end
27
+
28
+ def write_strings_data(path)
29
+ if @options[:developer_language]
30
+ @strings.set_developer_language_code(@options[:developer_language])
31
+ end
32
+ @strings.write(path)
33
+ end
34
+
35
+ def execute_command
36
+ case @options[:command]
37
+ when 'generate-string-file'
38
+ generate_string_file
39
+ when 'generate-all-string-files'
40
+ generate_all_string_files
41
+ when 'consume-string-file'
42
+ consume_string_file
43
+ when 'consume-all-string-files'
44
+ consume_all_string_files
45
+ when 'generate-loc-drop'
46
+ generate_loc_drop
47
+ when 'consume-loc-drop'
48
+ consume_loc_drop
49
+ when 'generate-report'
50
+ generate_report
51
+ end
52
+ end
53
+
54
+ def generate_string_file
55
+ lang = nil
56
+ if @options[:languages]
57
+ lang = @options[:languages][0]
58
+ end
59
+
60
+ read_write_string_file(@options[:output_path], false, lang)
61
+ end
62
+
63
+ def generate_all_string_files
64
+ if !File.directory?(@options[:output_path])
65
+ raise Traduco::Error.new("Directory does not exist: #{@options[:output_path]}")
66
+ end
67
+
68
+ format = @options[:format]
69
+ if !format
70
+ format = determine_format_given_directory(@options[:output_path])
71
+ end
72
+ if !format
73
+ raise Traduco::Error.new "Could not determine format given the contents of #{@options[:output_path]}"
74
+ end
75
+
76
+ formatter = formatter_for_format(format)
77
+
78
+ formatter.write_all_files(@options[:output_path])
79
+ end
80
+
81
+ def consume_string_file
82
+ lang = nil
83
+ if @options[:languages]
84
+ lang = @options[:languages][0]
85
+ end
86
+
87
+ read_write_string_file(@options[:input_path], true, lang)
88
+ output_path = @options[:output_path] || @options[:strings_file]
89
+ write_strings_data(output_path)
90
+ end
91
+
92
+ def consume_all_string_files
93
+ if !File.directory?(@options[:input_path])
94
+ raise Traduco::Error.new("Directory does not exist: #{@options[:output_path]}")
95
+ end
96
+
97
+ Dir.glob(File.join(@options[:input_path], "**/*")) do |item|
98
+ if File.file?(item)
99
+ begin
100
+ read_write_string_file(item, true, nil)
101
+ rescue Traduco::Error => e
102
+ STDERR.puts "#{e.message}"
103
+ end
104
+ end
105
+ end
106
+
107
+ output_path = @options[:output_path] || @options[:strings_file]
108
+ write_strings_data(output_path)
109
+ end
110
+
111
+ def read_write_string_file(path, is_read, lang)
112
+ if is_read && !File.file?(path)
113
+ raise Traduco::Error.new("File does not exist: #{path}")
114
+ end
115
+
116
+ format = @options[:format]
117
+ if !format
118
+ format = determine_format_given_path(path)
119
+ end
120
+ if !format
121
+ raise Traduco::Error.new "Unable to determine format of #{path}"
122
+ end
123
+
124
+ formatter = formatter_for_format(format)
125
+
126
+ if !lang
127
+ lang = determine_language_given_path(path)
128
+ end
129
+ if !lang
130
+ lang = formatter.determine_language_given_path(path)
131
+ end
132
+ if !lang
133
+ raise Traduco::Error.new "Unable to determine language for #{path}"
134
+ end
135
+
136
+ if !@strings.language_codes.include? lang
137
+ @strings.language_codes << lang
138
+ end
139
+
140
+ if is_read
141
+ formatter.read_file(path, lang)
142
+ else
143
+ formatter.write_file(path, lang)
144
+ end
145
+ end
146
+
147
+ def generate_loc_drop
148
+ begin
149
+ require 'zip/zip'
150
+ rescue LoadError
151
+ raise Traduco::Error.new "You must run 'gem install rubyzip' in order to create or consume localization drops."
152
+ end
153
+
154
+ if File.file?(@options[:output_path])
155
+ File.delete(@options[:output_path])
156
+ end
157
+
158
+ Dir.mktmpdir do |dir|
159
+ Zip::ZipFile.open(@options[:output_path], Zip::ZipFile::CREATE) do |zipfile|
160
+ zipfile.mkdir('Locales')
161
+
162
+ formatter = formatter_for_format(@options[:format])
163
+ @strings.language_codes.each do |lang|
164
+ if @options[:languages] == nil || @options[:languages].length == 0 || @options[:languages].include?(lang)
165
+ file_name = lang + formatter.class::EXTENSION
166
+ real_path = File.join(dir, file_name)
167
+ zip_path = File.join('Locales', file_name)
168
+ formatter.write_file(real_path, lang)
169
+ zipfile.add(zip_path, real_path)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ def consume_loc_drop
177
+ if !File.file?(@options[:input_path])
178
+ raise Traduco::Error.new("File does not exist: #{@options[:input_path]}")
179
+ end
180
+
181
+ begin
182
+ require 'zip/zip'
183
+ rescue LoadError
184
+ raise Traduco::Error.new "You must run 'gem install rubyzip' in order to create or consume localization drops."
185
+ end
186
+
187
+ Dir.mktmpdir do |dir|
188
+ Zip::ZipFile.open(@options[:input_path]) do |zipfile|
189
+ zipfile.each do |entry|
190
+ if !entry.name.end_with?'/' and !File.basename(entry.name).start_with?'.'
191
+ real_path = File.join(dir, entry.name)
192
+ FileUtils.mkdir_p(File.dirname(real_path))
193
+ zipfile.extract(entry.name, real_path)
194
+ begin
195
+ read_write_string_file(real_path, true, nil)
196
+ rescue Traduco::Error => e
197
+ STDERR.puts "#{e.message}"
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ output_path = @options[:output_path] || @options[:strings_file]
205
+ write_strings_data(output_path)
206
+ end
207
+
208
+ def generate_report
209
+ total_strings = 0
210
+ strings_per_lang = {}
211
+ all_keys = Set.new
212
+ duplicate_keys = Set.new
213
+ keys_without_tags = Set.new
214
+ @strings.language_codes.each do |code|
215
+ strings_per_lang[code] = 0
216
+ end
217
+
218
+ @strings.sections.each do |section|
219
+ section.rows.each do |row|
220
+ total_strings += 1
221
+
222
+ if all_keys.include? row.key
223
+ duplicate_keys.add(row.key)
224
+ else
225
+ all_keys.add(row.key)
226
+ end
227
+
228
+ row.translations.each_key do |code|
229
+ strings_per_lang[code] += 1
230
+ end
231
+
232
+ if row.tags == nil || row.tags.length == 0
233
+ keys_without_tags.add(row.key)
234
+ end
235
+ end
236
+ end
237
+
238
+ # Print the report.
239
+ puts "Total number of strings = #{total_strings}"
240
+ @strings.language_codes.each do |code|
241
+ puts "#{code}: #{strings_per_lang[code]}"
242
+ end
243
+
244
+ if duplicate_keys.length > 0
245
+ puts "\nDuplicate string keys:"
246
+ duplicate_keys.each do |key|
247
+ puts key
248
+ end
249
+ end
250
+
251
+ if keys_without_tags.length == total_strings
252
+ puts "\nNone of your strings have tags."
253
+ elsif keys_without_tags.length > 0
254
+ puts "\nStrings without tags:"
255
+ keys_without_tags.each do |key|
256
+ puts key
257
+ end
258
+ end
259
+ end
260
+
261
+ def determine_language_given_path(path)
262
+ code = File.basename(path, File.extname(path))
263
+ if !@strings.language_codes.include? code
264
+ code = nil
265
+ end
266
+
267
+ code
268
+ end
269
+
270
+ def determine_format_given_path(path)
271
+ ext = File.extname(path)
272
+ Formatters::FORMATTERS.each do |formatter|
273
+ if formatter::EXTENSION == ext
274
+ return formatter::FORMAT_NAME
275
+ end
276
+ end
277
+
278
+ return
279
+ end
280
+
281
+ def determine_format_given_directory(directory)
282
+ Formatters::FORMATTERS.each do |formatter|
283
+ if formatter.can_handle_directory?(directory)
284
+ return formatter::FORMAT_NAME
285
+ end
286
+ end
287
+
288
+ return
289
+ end
290
+
291
+ def formatter_for_format(format)
292
+ Formatters::FORMATTERS.each do |formatter|
293
+ if formatter::FORMAT_NAME == format
294
+ return formatter.new(@strings, @options)
295
+ end
296
+ end
297
+
298
+ return
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,12 @@
1
+ /**
2
+ * JQuery Language File
3
+ * Generated by Twine
4
+ * Language: en
5
+ */
6
+ {
7
+
8
+ /* My Strings */
9
+ "key1":"key1-english",
10
+ "key3":"key3-english",
11
+ "key5":"A new string"
12
+ }
@@ -0,0 +1,16 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Language: en\n"
4
+ "X-Generator: Twine\n"
5
+
6
+ msgctxt "key1"
7
+ msgid "key1-english"
8
+ msgstr "key1-english"
9
+
10
+ msgctxt "key3"
11
+ msgid "key3-english"
12
+ msgstr ""
13
+
14
+ msgctxt "key5"
15
+ msgid "A new string"
16
+ msgstr "A new string"
@@ -0,0 +1,10 @@
1
+ /**
2
+ * iOS Strings File
3
+ * Generated by Twine
4
+ * Language: en
5
+ */
6
+
7
+ /* My Strings */
8
+ "key1" = "key1-english";
9
+ "key3" = "key3-english";
10
+ "key5" = "A new string";
@@ -0,0 +1,23 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Language: en\n"
4
+ "X-Generator: Twine\n"
5
+
6
+ msgctxt "key1"
7
+ msgid "key1-english"
8
+ msgstr "key1-english"
9
+
10
+ msgctxt "key3"
11
+ msgid "key3-english"
12
+ msgstr ""
13
+
14
+ msgctxt "key4"
15
+ msgid "key4"
16
+ "multiline"
17
+ msgstr "A multi"
18
+ "line string\n"
19
+ "can occur"
20
+
21
+ msgctxt "key5"
22
+ msgid "A new string"
23
+ msgstr "A new string"
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Android Strings File -->
3
+ <!-- Generated by Twine -->
4
+ <!-- Language: fr -->
5
+ <resources>
6
+ <!-- This is a comment -->
7
+ <string name="key1">key1-french</string>
8
+ <string name="key2">key2-french</string>
9
+ <string name="key3">key3-french</string>
10
+ </resources>
@@ -0,0 +1,17 @@
1
+ [[My Strings]]
2
+ [key1]
3
+ en = key1-english
4
+ tags = tag1
5
+ comment = This is a comment
6
+ es = key1-spanish
7
+ fr = key1-french
8
+ [key2]
9
+ en = key2-english
10
+ tags = tag2
11
+ fr = key2-french
12
+ [key3]
13
+ en = key3-english
14
+ tags = tag1,tag2
15
+ es = key3-spanish
16
+ [key4]
17
+ en = key4-english
@@ -0,0 +1,5 @@
1
+ [[My Strings]]
2
+ [key with space ]
3
+ en = `string with space `
4
+ tags = tag1
5
+ comment = String ends with space
@@ -0,0 +1,5 @@
1
+ [[My Strings]]
2
+ [parameterized_string]
3
+ en = The %@ brown fox jumps over the %@ dog %d times.
4
+ [percentage_string]
5
+ en = This product is %d%% off.
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Android Strings File -->
3
+ <!-- Generated by Twine <%= Twine::VERSION %> -->
4
+ <!-- Language: fr -->
5
+ <resources>
6
+ <!-- SECTION: My Strings -->
7
+ <!-- This is a comment -->
8
+ <string name="key1">key1-french</string>
9
+ <string name="key2">key2-french</string>
10
+ <string name="key3">key3-english</string>
11
+ <string name="key4">key4-english</string>
12
+ </resources>
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Apple Strings File
3
+ * Generated by Twine <%= Twine::VERSION %>
4
+ * Language: en
5
+ */
6
+
7
+ /********** My Strings **********/
8
+
9
+ /* This is a comment */
10
+ "key1" = "key1-english";
11
+
12
+ "key3" = "key3-english";
@@ -0,0 +1,18 @@
1
+ [[My Strings]]
2
+ [key1]
3
+ en = key1-english
4
+ tags = tag1
5
+ comment = This is a comment
6
+ es = key1-spanish
7
+ fr = key1-french
8
+ [key2]
9
+ en = key2-english
10
+ tags = tag2
11
+ fr = key2-french
12
+ [key3]
13
+ en = key3-english
14
+ tags = tag1,tag2
15
+ es = key3-spanish
16
+ fr = key3-french
17
+ [key4]
18
+ en = key4-english