twine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,73 +29,41 @@ module Twine
29
29
  return
30
30
  end
31
31
 
32
- def read_file(path, lang)
32
+ def read(io, lang)
33
33
  comment_regex = /#\. *"?(.*)"?$/
34
34
  key_regex = /msgid *"(.*)"$/
35
35
  value_regex = /msgstr *"(.*)"$/m
36
36
 
37
- encoding = Twine::Encoding.encoding_for_path(path)
38
- sep = nil
39
- if !encoding.respond_to?(:encode)
40
- # This code is not necessary in 1.9.3 and does not work as it did in 1.8.7.
41
- if encoding.end_with? 'LE'
42
- sep = "\x0a\x00"
43
- elsif encoding.end_with? 'BE'
44
- sep = "\x00\x0a"
45
- else
46
- sep = "\n"
37
+ last_comment = nil
38
+ while line = io.gets
39
+ comment_match = comment_regex.match(line)
40
+ if comment_match
41
+ comment = comment_match[1]
47
42
  end
48
- end
49
-
50
- if encoding.index('UTF-16')
51
- mode = "rb:#{encoding}"
52
- else
53
- mode = "r:#{encoding}"
54
- end
55
-
56
- File.open(path, mode) do |f|
57
- last_comment = nil
58
- while line = (sep) ? f.gets(sep) : f.gets
59
- if encoding.index('UTF-16')
60
- if line.respond_to? :encode!
61
- line.encode!('UTF-8')
62
- else
63
- require 'iconv'
64
- line = Iconv.iconv('UTF-8', encoding, line).join
65
- end
66
- end
67
-
68
- comment_match = comment_regex.match(line)
69
- if comment_match
70
- comment = comment_match[1]
71
- end
72
-
73
- key_match = key_regex.match(line)
74
- if key_match
75
- key = key_match[1].gsub('\\"', '"')
76
- end
77
- value_match = value_regex.match(line)
78
- if value_match
79
- value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
80
- end
81
43
 
44
+ key_match = key_regex.match(line)
45
+ if key_match
46
+ key = key_match[1].gsub('\\"', '"')
47
+ end
48
+ value_match = value_regex.match(line)
49
+ if value_match
50
+ value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
51
+ end
82
52
 
83
- if key and key.length > 0 and value and value.length > 0
84
- set_translation_for_key(key, lang, value)
85
- if comment and comment.length > 0 and !comment.start_with?("--------- ")
86
- set_comment_for_key(key, comment)
87
- end
88
- key = nil
89
- value = nil
90
- comment = nil
53
+ if key and key.length > 0 and value and value.length > 0
54
+ set_translation_for_key(key, lang, value)
55
+ if comment and comment.length > 0 and !comment.start_with?("--------- ")
56
+ set_comment_for_key(key, comment)
91
57
  end
92
-
58
+ key = nil
59
+ value = nil
60
+ comment = nil
93
61
  end
94
62
  end
95
63
  end
96
64
 
97
- def format_file(strings, lang)
98
- @default_lang = strings.language_codes[0]
65
+ def format_file(lang)
66
+ @default_lang = @strings.language_codes[0]
99
67
  result = super
100
68
  @default_lang = nil
101
69
  result
@@ -21,57 +21,31 @@ module Twine
21
21
  return
22
22
  end
23
23
 
24
- def read_file(path, lang)
25
- encoding = Twine::Encoding.encoding_for_path(path)
26
- sep = nil
27
- if !encoding.respond_to?(:encode)
28
- # This code is not necessary in 1.9.3 and does not work as it did in 1.8.7.
29
- if encoding.end_with? 'LE'
30
- sep = "\x0a\x00"
31
- elsif encoding.end_with? 'BE'
32
- sep = "\x00\x0a"
24
+ def read(io, lang)
25
+ last_comment = nil
26
+ while line = io.gets
27
+ match = /((?:[^"\\]|\\.)+)\s*=\s*((?:[^"\\]|\\.)*)/.match(line)
28
+ if match
29
+ key = match[1]
30
+ value = match[2].strip
31
+ value.gsub!(/\{[0-9]\}/, '%@')
32
+ set_translation_for_key(key, lang, value)
33
+ if last_comment
34
+ set_comment_for_key(key, last_comment)
35
+ end
36
+ end
37
+
38
+ match = /# *(.*)/.match(line)
39
+ if match
40
+ last_comment = match[1]
33
41
  else
34
- sep = "\n"
42
+ last_comment = nil
35
43
  end
36
44
  end
45
+ end
37
46
 
38
- if encoding.index('UTF-16')
39
- mode = "rb:#{encoding}"
40
- else
41
- mode = "r:#{encoding}"
42
- end
43
-
44
- File.open(path, mode) do |f|
45
- last_comment = nil
46
- while line = (sep) ? f.gets(sep) : f.gets
47
- if encoding.index('UTF-16')
48
- if line.respond_to? :encode!
49
- line.encode!('UTF-8')
50
- else
51
- require 'iconv'
52
- line = Iconv.iconv('UTF-8', encoding, line).join
53
- end
54
- end
55
- match = /((?:[^"\\]|\\.)+)\s*=\s*((?:[^"\\]|\\.)*)/.match(line)
56
- if match
57
- key = match[1]
58
- value = match[2].strip
59
- value.gsub!(/\{[0-9]\}/, '%@')
60
- set_translation_for_key(key, lang, value)
61
- if last_comment
62
- set_comment_for_key(key, last_comment)
63
- end
64
- end
65
-
66
- match = /# *(.*)/.match(line)
67
- if match
68
- last_comment = match[1]
69
- else
70
- last_comment = nil
71
- end
72
-
73
- end
74
- end
47
+ def format_sections(strings, lang)
48
+ super + "\n"
75
49
  end
76
50
 
77
51
  def format_header(lang)
@@ -31,40 +31,39 @@ module Twine
31
31
  return
32
32
  end
33
33
 
34
- def read_file(path, lang)
34
+ def read(io, lang)
35
35
  comment_regex = /#.? *"(.*)"$/
36
36
  key_regex = /msgctxt *"(.*)"$/
37
37
  value_regex = /msgstr *"(.*)"$/m
38
- File.open(path, 'r:UTF-8') do |f|
39
- while item = f.gets("\n\n")
40
- key = nil
41
- value = nil
42
- comment = nil
43
-
44
- comment_match = comment_regex.match(item)
45
- if comment_match
46
- comment = comment_match[1]
47
- end
48
- key_match = key_regex.match(item)
49
- if key_match
50
- key = key_match[1].gsub('\\"', '"')
51
- end
52
- value_match = value_regex.match(item)
53
- if value_match
54
- value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
55
- end
56
- if key and key.length > 0 and value and value.length > 0
57
- set_translation_for_key(key, lang, value)
58
- if comment and comment.length > 0 and !comment.start_with?("SECTION:")
59
- set_comment_for_key(key, comment)
60
- end
61
- comment = nil
38
+
39
+ while item = io.gets("\n\n")
40
+ key = nil
41
+ value = nil
42
+ comment = nil
43
+
44
+ comment_match = comment_regex.match(item)
45
+ if comment_match
46
+ comment = comment_match[1]
47
+ end
48
+ key_match = key_regex.match(item)
49
+ if key_match
50
+ key = key_match[1].gsub('\\"', '"')
51
+ end
52
+ value_match = value_regex.match(item)
53
+ if value_match
54
+ value = value_match[1].gsub(/"\n"/, '').gsub('\\"', '"')
55
+ end
56
+ if key and key.length > 0 and value and value.length > 0
57
+ set_translation_for_key(key, lang, value)
58
+ if comment and comment.length > 0 and !comment.start_with?("SECTION:")
59
+ set_comment_for_key(key, comment)
62
60
  end
61
+ comment = nil
63
62
  end
64
63
  end
65
64
  end
66
65
 
67
- def format_file(strings, lang)
66
+ def format_file(lang)
68
67
  @default_lang = strings.language_codes[0]
69
68
  result = super
70
69
  @default_lang = nil
@@ -29,23 +29,23 @@ module Twine
29
29
  return
30
30
  end
31
31
 
32
- def read_file(path, lang)
32
+ def read(io, lang)
33
33
  begin
34
34
  require "json"
35
35
  rescue LoadError
36
36
  raise Twine::Error.new "You must run 'gem install json' in order to read or write jquery-localize files."
37
37
  end
38
38
 
39
- open(path) do |io|
40
- json = JSON.load(io)
41
- json.each do |key, value|
42
- set_translation_for_key(key, lang, value)
43
- end
39
+ json = JSON.load(io)
40
+ json.each do |key, value|
41
+ set_translation_for_key(key, lang, value)
44
42
  end
45
43
  end
46
44
 
47
- def format_file(strings, lang)
48
- "{\n#{super}\n}"
45
+ def format_file(lang)
46
+ result = super
47
+ return result unless result
48
+ "{\n#{super}\n}\n"
49
49
  end
50
50
 
51
51
  def format_sections(strings, lang)
@@ -49,7 +49,7 @@ module Twine
49
49
  return
50
50
  end
51
51
 
52
- def read_file(path, lang)
52
+ def read(io, lang)
53
53
  resources_regex = /<resources(?:[^>]*)>(.*)<\/resources>/m
54
54
  key_regex = /<string name="(\w+)">/
55
55
  comment_regex = /<!-- (.*) -->/
@@ -58,35 +58,33 @@ module Twine
58
58
  value = nil
59
59
  comment = nil
60
60
 
61
- File.open(path, 'r:UTF-8') do |f|
62
- content_match = resources_regex.match(f.read)
63
- if content_match
64
- for line in content_match[1].split(/\r?\n/)
65
- key_match = key_regex.match(line)
66
- if key_match
67
- key = key_match[1]
68
- value_match = value_regex.match(line)
69
- if value_match
70
- value = value_match[1]
71
- value = CGI.unescapeHTML(value)
72
- value.gsub!('\\\'', '\'')
73
- value.gsub!('\\"', '"')
74
- value = convert_placeholders_from_android_to_twine(value)
75
- value.gsub!(/(\\u0020)*|(\\u0020)*\z/) { |spaces| ' ' * (spaces.length / 6) }
76
- else
77
- value = ""
78
- end
79
- set_translation_for_key(key, lang, value)
80
- if comment and comment.length > 0 and !comment.start_with?("SECTION:")
81
- set_comment_for_key(key, comment)
82
- end
83
- comment = nil
61
+ content_match = resources_regex.match(io.read)
62
+ if content_match
63
+ for line in content_match[1].split(/\r?\n/)
64
+ key_match = key_regex.match(line)
65
+ if key_match
66
+ key = key_match[1]
67
+ value_match = value_regex.match(line)
68
+ if value_match
69
+ value = value_match[1]
70
+ value = CGI.unescapeHTML(value)
71
+ value.gsub!('\\\'', '\'')
72
+ value.gsub!('\\"', '"')
73
+ value = convert_placeholders_from_android_to_twine(value)
74
+ value.gsub!(/(\\u0020)*|(\\u0020)*\z/) { |spaces| ' ' * (spaces.length / 6) }
75
+ else
76
+ value = ""
84
77
  end
85
-
86
- comment_match = comment_regex.match(line)
87
- if comment_match
88
- comment = comment_match[1]
78
+ set_translation_for_key(key, lang, value)
79
+ if comment and comment.length > 0 and !comment.start_with?("SECTION:")
80
+ set_comment_for_key(key, comment)
89
81
  end
82
+ comment = nil
83
+ end
84
+
85
+ comment_match = comment_regex.match(line)
86
+ if comment_match
87
+ comment = comment_match[1]
90
88
  end
91
89
  end
92
90
  end
@@ -101,7 +99,7 @@ module Twine
101
99
 
102
100
  result += super + "\n"
103
101
 
104
- result += '</string_table>'
102
+ result += "</string_table>\n"
105
103
  end
106
104
 
107
105
  def format_section_header(section)
@@ -31,9 +31,9 @@ module Twine
31
31
 
32
32
  value = row.translated_string_for_lang(language)
33
33
 
34
- next if value && @options[:include] == 'untranslated'
34
+ next if value && @options[:include] == :untranslated
35
35
 
36
- if value.nil? && @options[:include] != 'translated'
36
+ if value.nil? && @options[:include] != :translated
37
37
  value = row.translated_string_for_lang(fallback_languages(language))
38
38
  end
39
39
 
data/lib/twine/runner.rb CHANGED
@@ -48,7 +48,12 @@ module Twine
48
48
  lang = nil
49
49
  lang = @options[:languages][0] if @options[:languages]
50
50
 
51
- write_string_file(@options[:output_path], lang)
51
+ formatter, lang = prepare_read_write(@options[:output_path], lang)
52
+ output = formatter.format_file(lang)
53
+
54
+ raise Twine::Error.new "Nothing to generate! The resulting file would not contain any strings." unless output
55
+
56
+ IO.write(@options[:output_path], output, encoding: encoding)
52
57
  end
53
58
 
54
59
  def generate_all_string_files
@@ -69,7 +74,51 @@ module Twine
69
74
  raise Twine::Error.new "Could not determine format given the contents of #{@options[:output_path]}"
70
75
  end
71
76
 
72
- formatter.write_all_files(@options[:output_path])
77
+ file_name = @options[:file_name] || formatter.default_file_name
78
+ if @options[:create_folders]
79
+ @strings.language_codes.each do |lang|
80
+ output_path = File.join(@options[:output_path], formatter.output_path_for_language(lang))
81
+
82
+ FileUtils.mkdir_p(output_path)
83
+
84
+ file_path = File.join(output_path, file_name)
85
+
86
+ output = formatter.format_file(lang)
87
+ unless output
88
+ Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any strings."
89
+ next
90
+ end
91
+
92
+ IO.write(file_path, output, encoding: encoding)
93
+ end
94
+ else
95
+ language_found = false
96
+ Dir.foreach(@options[:output_path]) do |item|
97
+ next if item == "." or item == ".."
98
+
99
+ output_path = File.join(@options[:output_path], item)
100
+ next unless File.directory?(output_path)
101
+
102
+ lang = formatter.determine_language_given_path(output_path)
103
+ next unless lang
104
+
105
+ language_found = true
106
+
107
+ file_path = File.join(output_path, file_name)
108
+ output = formatter.format_file(lang)
109
+ unless output
110
+ Twine::stderr.puts "Skipping file at path #{file_path} since it would not contain any strings."
111
+ next
112
+ end
113
+
114
+ IO.write(file_path, output, encoding: encoding)
115
+ end
116
+
117
+ unless language_found
118
+ raise Twine::Error.new("Failed to generate any files: No languages found at #{@options[:output_path]}")
119
+ end
120
+ end
121
+
73
122
  end
74
123
 
75
124
  def consume_string_file
@@ -111,7 +160,7 @@ module Twine
111
160
  File.delete(@options[:output_path])
112
161
  end
113
162
 
114
- Dir.mktmpdir do |dir|
163
+ Dir.mktmpdir do |temp_dir|
115
164
  Zip::File.open(@options[:output_path], Zip::File::CREATE) do |zipfile|
116
165
  zipfile.mkdir('Locales')
117
166
 
@@ -119,10 +168,17 @@ module Twine
119
168
  @strings.language_codes.each do |lang|
120
169
  if @options[:languages] == nil || @options[:languages].length == 0 || @options[:languages].include?(lang)
121
170
  file_name = lang + formatter.extension
122
- real_path = File.join(dir, file_name)
171
+ temp_path = File.join(temp_dir, file_name)
123
172
  zip_path = File.join('Locales', file_name)
124
- formatter.write_file(real_path, lang)
125
- zipfile.add(zip_path, real_path)
173
+
174
+ output = formatter.format_file(lang)
175
+ unless output
176
+ Twine::stderr.puts "Skipping file #{file_name} since it would not contain any strings."
177
+ next
178
+ end
179
+
180
+ IO.write(temp_path, output, encoding: encoding)
181
+ zipfile.add(zip_path, temp_path)
126
182
  end
127
183
  end
128
184
  end
@@ -136,18 +192,18 @@ module Twine
136
192
  raise Twine::Error.new("File does not exist: #{@options[:input_path]}")
137
193
  end
138
194
 
139
- Dir.mktmpdir do |dir|
195
+ Dir.mktmpdir do |temp_dir|
140
196
  Zip::File.open(@options[:input_path]) do |zipfile|
141
197
  zipfile.each do |entry|
142
- if !entry.name.end_with?'/' and !File.basename(entry.name).start_with?'.'
143
- real_path = File.join(dir, entry.name)
144
- FileUtils.mkdir_p(File.dirname(real_path))
145
- zipfile.extract(entry.name, real_path)
146
- begin
147
- read_string_file(real_path)
148
- rescue Twine::Error => e
149
- Twine::stderr.puts "#{e.message}"
150
- end
198
+ next if entry.name.end_with? '/' or File.basename(entry.name).start_with? '.'
199
+
200
+ real_path = File.join(temp_dir, entry.name)
201
+ FileUtils.mkdir_p(File.dirname(real_path))
202
+ zipfile.extract(entry.name, real_path)
203
+ begin
204
+ read_string_file(real_path)
205
+ rescue Twine::Error => e
206
+ Twine::stderr.puts "#{e.message}"
151
207
  end
152
208
  end
153
209
  end
@@ -204,6 +260,10 @@ module Twine
204
260
 
205
261
  private
206
262
 
263
+ def encoding
264
+ @options[:output_encoding] || 'UTF-8'
265
+ end
266
+
207
267
  def require_rubyzip
208
268
  begin
209
269
  require 'zip'
@@ -236,12 +296,12 @@ module Twine
236
296
 
237
297
  formatter, lang = prepare_read_write(path, lang)
238
298
 
239
- formatter.read_file(path, lang)
240
- end
299
+ encoding = @options[:encoding] || Twine::Encoding.encoding_for_path(path)
241
300
 
242
- def write_string_file(path, lang)
243
- formatter, lang = prepare_read_write(path, lang)
244
- formatter.write_file(path, lang)
301
+ IO.open(IO.sysopen(path, 'rb'), 'rb', external_encoding: encoding, internal_encoding: 'UTF-8') do |io|
302
+ io.read(2) if Twine::Encoding.has_bom?(path)
303
+ formatter.read(io, lang)
304
+ end
245
305
  end
246
306
 
247
307
  def prepare_read_write(path, lang)