idiom 0.0.5 → 0.0.6
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.
- data/History.txt +9 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/bin/idiom +9 -1
- data/idiom.gemspec +6 -3
- data/lib/idiom.rb +6 -358
- data/lib/idiom/base.rb +339 -0
- data/lib/idiom/yaml.rb +28 -0
- data/lib/idiom/yrb.rb +29 -0
- metadata +6 -3
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.0.6 (in Git)
|
2
|
+
* minor enhancements
|
3
|
+
* some internal refactoring
|
4
|
+
* added destination option to command-line interface
|
5
|
+
|
6
|
+
== 0.0.5.1 2010-01-22
|
7
|
+
* bug fixes
|
8
|
+
* correct command-line file
|
9
|
+
|
1
10
|
== 0.0.5 2010-01-22
|
2
11
|
* major enhancements
|
3
12
|
* command-line file doesn't require parameters
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "idiom"
|
8
|
-
gem.summary = %Q{Translate
|
8
|
+
gem.summary = %Q{Translate all your application's international keys in Google Translate}
|
9
9
|
gem.description = %Q{Takes a set of keys in Yaml format and translates them through Google Translate.}
|
10
10
|
gem.email = "progressions@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/progressions/idiom"
|
@@ -49,7 +49,7 @@ Rake::RDocTask.new do |rdoc|
|
|
49
49
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
50
|
|
51
51
|
rdoc.rdoc_dir = 'rdoc'
|
52
|
-
rdoc.title = "
|
52
|
+
rdoc.title = "idiom #{version}"
|
53
53
|
rdoc.rdoc_files.include('README*')
|
54
54
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
55
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/bin/idiom
CHANGED
@@ -5,4 +5,12 @@ $LOAD_PATH.unshift(idiom_dir) unless $LOAD_PATH.include?(idiom_dir)
|
|
5
5
|
|
6
6
|
require 'idiom'
|
7
7
|
|
8
|
-
|
8
|
+
options = {}
|
9
|
+
|
10
|
+
options[:source] = ARGV[0] || "./"
|
11
|
+
|
12
|
+
if ARGV[1]
|
13
|
+
options[:destination] = ARGV[1]
|
14
|
+
end
|
15
|
+
|
16
|
+
Idiom::Base.translate(options)
|
data/idiom.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{idiom}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jeff Coleman"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-30}
|
13
13
|
s.default_executable = %q{idiom}
|
14
14
|
s.description = %q{Takes a set of keys in Yaml format and translates them through Google Translate.}
|
15
15
|
s.email = %q{progressions@gmail.com}
|
@@ -30,6 +30,9 @@ Gem::Specification.new do |s|
|
|
30
30
|
"bin/idiom",
|
31
31
|
"idiom.gemspec",
|
32
32
|
"lib/idiom.rb",
|
33
|
+
"lib/idiom/base.rb",
|
34
|
+
"lib/idiom/yaml.rb",
|
35
|
+
"lib/idiom/yrb.rb",
|
33
36
|
"spec/idiom_spec.rb",
|
34
37
|
"spec/spec.opts",
|
35
38
|
"spec/spec_helper.rb",
|
@@ -39,7 +42,7 @@ Gem::Specification.new do |s|
|
|
39
42
|
s.rdoc_options = ["--charset=UTF-8"]
|
40
43
|
s.require_paths = ["lib"]
|
41
44
|
s.rubygems_version = %q{1.3.5}
|
42
|
-
s.summary = %q{Translate
|
45
|
+
s.summary = %q{Translate all your application's international keys in Google Translate}
|
43
46
|
s.test_files = [
|
44
47
|
"spec/idiom_spec.rb",
|
45
48
|
"spec/spec_helper.rb",
|
data/lib/idiom.rb
CHANGED
@@ -1,364 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
3
|
+
|
1
4
|
require 'rubygems'
|
2
5
|
require 'active_support'
|
3
6
|
require 'rtranslate'
|
4
7
|
require 'timer'
|
5
8
|
require 'yrb'
|
6
|
-
require 'yaml'
|
7
|
-
|
8
|
-
module Idiom #:nodoc:
|
9
|
-
# Finds English language translation keys which have not been translated
|
10
|
-
# and translates them through Google Translate.
|
11
|
-
#
|
12
|
-
class Base
|
13
|
-
# Mapping of the way I18n country codes with the Google Translate codes.
|
14
|
-
#
|
15
|
-
# The key is the I18n representation, and the value is the code Google Translate would expect.
|
16
|
-
#
|
17
|
-
LOCALES = {
|
18
|
-
"de-DE" => "de",
|
19
|
-
"en-MY" => "en",
|
20
|
-
"en-SG" => "en",
|
21
|
-
"es-MX" => "es",
|
22
|
-
"it-IT" => "it",
|
23
|
-
"vi-VN" => "vi",
|
24
|
-
"zh-Hant-TW" => "zh-TW",
|
25
|
-
"en-AA" => "en",
|
26
|
-
"en-NZ" => "en",
|
27
|
-
"en-US" => "en",
|
28
|
-
"fr-FR" => "fr",
|
29
|
-
"ko-KR" => "ko",
|
30
|
-
"zh-Hans-CN" => "zh-CN",
|
31
|
-
"en-AU" => "en",
|
32
|
-
"en-PH" => "en",
|
33
|
-
"es-ES" => "es",
|
34
|
-
"id-ID" => "id",
|
35
|
-
"pt-BR" => "PORTUGUESE",
|
36
|
-
"zh-Hant-HK" => "zh-CN",
|
37
|
-
}
|
38
|
-
|
39
|
-
# Original filename to translate.
|
40
|
-
#
|
41
|
-
attr_accessor :source
|
42
|
-
|
43
|
-
# Destination directory to output the translated files to.
|
44
|
-
#
|
45
|
-
attr_accessor :destination
|
46
|
-
|
47
|
-
# Write the translated strings into a directory for each language?
|
48
|
-
#
|
49
|
-
attr_accessor :use_dirs
|
50
|
-
|
51
|
-
# Array of languages to translate into.
|
52
|
-
#
|
53
|
-
attr_accessor :languages
|
54
|
-
|
55
|
-
class << self
|
56
|
-
|
57
|
-
def translate(options={})
|
58
|
-
@source = options[:source]
|
59
|
-
@destination = options[:destination]
|
60
|
-
@use_dirs = options[:use_dirs]
|
61
|
-
Timer.new.time do
|
62
|
-
Dir[@source].each do |path|
|
63
|
-
$stdout.puts "Processing #{path}"
|
64
|
-
if path =~ /\.yml$/i
|
65
|
-
Idiom::Yaml.new({:source => path}.merge(options)).generate
|
66
|
-
end
|
67
|
-
if path =~ /\.pres$/i
|
68
|
-
Idiom::Yrb.new({:source => path}.merge(options)).generate
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def initialize(options={})
|
77
|
-
@source = File.expand_path(options[:source])
|
78
|
-
@overwrite = options[:overwrite]
|
79
|
-
@languages = options[:languages]
|
80
|
-
|
81
|
-
@base_source = @source.gsub(/_en-US/, "")
|
82
|
-
|
83
|
-
# base directory of the source file
|
84
|
-
#
|
85
|
-
@source_dir = File.dirname(@source)
|
86
|
-
|
87
|
-
# if they specify the :use_dirs option, use that
|
88
|
-
# if not, detect whether the source path uses directories for each language
|
89
|
-
#
|
90
|
-
if options.has_key?(:use_dirs)
|
91
|
-
@use_dirs = options[:use_dirs]
|
92
|
-
else
|
93
|
-
@use_dirs = @source_dir =~ /\/en-US$/
|
94
|
-
end
|
95
|
-
|
96
|
-
if @use_dirs
|
97
|
-
@source_dir = File.dirname(@source).gsub(/\/en-US$/, "")
|
98
|
-
end
|
99
|
-
@destination = options[:destination] || @source_dir
|
100
|
-
end
|
101
|
-
|
102
|
-
def generate
|
103
|
-
copy_lines_to_all_locales
|
104
|
-
end
|
105
|
-
|
106
|
-
def locales
|
107
|
-
@languages || LOCALES.keys
|
108
|
-
end
|
109
|
-
|
110
|
-
def use_directories?
|
111
|
-
use_dirs
|
112
|
-
end
|
113
|
-
|
114
|
-
def destination_path(lang)
|
115
|
-
output_path = File.basename(@base_source).split(".").first
|
116
|
-
if use_directories?
|
117
|
-
"#{destination}/#{lang}/#{output_path}_#{lang}.#{extension}"
|
118
|
-
else
|
119
|
-
"#{destination}/#{output_path}_#{lang}.#{extension}"
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def non_us_locales
|
124
|
-
@non_us_locales ||= locales.select do |lang|
|
125
|
-
lang != "en-US"
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def copy_lines_to_all_locales
|
130
|
-
non_us_locales.each do |lang|
|
131
|
-
code = LOCALES[lang]
|
132
|
-
destination = ensure_destination_path_exists(lang)
|
133
|
-
new_content = each_line do |line|
|
134
|
-
copy_and_translate_line(line, lang)
|
135
|
-
end
|
136
|
-
write_content(destination, new_content)
|
137
|
-
clear_all_keys
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def ensure_destination_path_exists(lang)
|
142
|
-
dest = destination_path(lang)
|
143
|
-
dir = File.dirname(dest)
|
144
|
-
FileUtils.mkdir_p(dir)
|
145
|
-
|
146
|
-
dest
|
147
|
-
end
|
148
|
-
|
149
|
-
def write_content(destination, content)
|
150
|
-
unless content.blank?
|
151
|
-
$stdout.puts "Writing to #{destination}"
|
152
|
-
$stdout.puts content
|
153
|
-
$stdout.puts
|
154
|
-
File.open(destination, "a") do |f|
|
155
|
-
f.puts
|
156
|
-
f.puts new_translation_message
|
157
|
-
f.puts content
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def new_translation_message
|
163
|
-
now = Time.now
|
164
|
-
|
165
|
-
date = now.day
|
166
|
-
month = now.month
|
167
|
-
year = now.year
|
168
|
-
|
169
|
-
timestamp = "#{month}/#{date}/#{year}"
|
170
|
-
output = []
|
171
|
-
output << "# "
|
172
|
-
output << "# Keys translated automatically on #{timestamp}."
|
173
|
-
output << "# "
|
174
|
-
|
175
|
-
output.join("\n")
|
176
|
-
end
|
177
|
-
|
178
|
-
def each_line
|
179
|
-
output = []
|
180
|
-
@lines ||= File.readlines(source)
|
181
|
-
|
182
|
-
@lines.each do |line|
|
183
|
-
new_line = yield line
|
184
|
-
output << new_line
|
185
|
-
end
|
186
|
-
output.compact.join("\n")
|
187
|
-
end
|
188
|
-
|
189
|
-
def parse(p)
|
190
|
-
raise "Define in child"
|
191
|
-
end
|
192
|
-
|
193
|
-
def all_keys(lang)
|
194
|
-
unless @all_keys
|
195
|
-
@all_keys = {}
|
196
|
-
Dir[destination_file_or_directory(lang)].each do |path|
|
197
|
-
if File.exists?(path)
|
198
|
-
keys = parse(path)
|
199
|
-
@all_keys = @all_keys.merge(keys)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
@all_keys
|
204
|
-
end
|
205
|
-
|
206
|
-
def destination_file_or_directory(lang)
|
207
|
-
if use_directories?
|
208
|
-
dir = File.dirname(destination_path(lang))
|
209
|
-
"#{dir}/*.#{extension}"
|
210
|
-
else
|
211
|
-
destination_path(lang)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
def clear_all_keys
|
216
|
-
@all_keys = nil
|
217
|
-
end
|
218
|
-
|
219
|
-
def copy_and_translate_line(line, lang)
|
220
|
-
line = line.split("\n").first
|
221
|
-
if comment?(line) || line.blank?
|
222
|
-
nil
|
223
|
-
else
|
224
|
-
translate_new_key(line, lang)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def key_is_new?(k, lang)
|
229
|
-
k && !all_keys(lang).has_key?(k)
|
230
|
-
end
|
231
|
-
|
232
|
-
def translate_new_key(line, lang)
|
233
|
-
k, v = key_and_value_from_line(line)
|
234
|
-
if @overwrite || key_is_new?(k, lang)
|
235
|
-
format(k, translate(v, lang))
|
236
|
-
else
|
237
|
-
nil
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
def translate(value, lang)
|
242
|
-
code = LOCALES[lang]
|
243
|
-
value = pre_process(value, lang)
|
244
|
-
translation = Translate.t(value, "ENGLISH", code)
|
245
|
-
post_process(translation, lang)
|
246
|
-
end
|
247
|
-
|
248
|
-
def pre_process(value, lang)
|
249
|
-
vars = []
|
250
|
-
index = 0
|
251
|
-
while value =~ /(\{\d+\})/
|
252
|
-
vars << $1
|
253
|
-
value.sub!(/(\{\d+\})/, "[#{index}]")
|
254
|
-
index += 1
|
255
|
-
end
|
256
|
-
|
257
|
-
if lang !~ /^en/ && value != value.downcase
|
258
|
-
value = value.capitalize
|
259
|
-
end
|
260
|
-
|
261
|
-
value
|
262
|
-
end
|
263
|
-
|
264
|
-
def post_process(value, lang)
|
265
|
-
if lang =~ /zh/
|
266
|
-
value.gsub!("<strong>", "")
|
267
|
-
value.gsub!("</strong>", "")
|
268
|
-
end
|
269
|
-
|
270
|
-
value.gsub!(/^#{194.chr}#{160.chr}/, "")
|
271
|
-
|
272
|
-
value.gsub!(" ]", "]")
|
273
|
-
value.gsub!("«", "\"")
|
274
|
-
value.gsub!("»", "\"")
|
275
|
-
value.gsub!(/\"\.$/, ".\"")
|
276
|
-
value.gsub!(/\\ \"/, "\\\"")
|
277
|
-
value.gsub!(/<\/ /, "<\/")
|
278
|
-
value.gsub!(/(“|”)/, "\"")
|
279
|
-
value.gsub!("<strong> ", "<strong>")
|
280
|
-
value.gsub!(" </strong>", "</strong>")
|
281
|
-
value.gsub!(""", "\"")
|
282
|
-
value.gsub!("'", "\"")
|
283
|
-
value.gsub!("> ", ">")
|
284
|
-
|
285
|
-
value.gsub!("\"", "'")
|
286
|
-
value.gsub!(" \"O", " \\\"O")
|
287
|
-
|
288
|
-
while value =~ /\[(\d)\]/
|
289
|
-
index = $1.to_i
|
290
|
-
value.sub!(/\[#{index}\]/, "{#{index}}")
|
291
|
-
end
|
292
|
-
|
293
|
-
value.gsub!(/\((0)\)/, "{0}")
|
294
|
-
value.gsub!(/\((1)\)/, "{1}")
|
295
|
-
value.gsub!(/\((2)\)/, "{2}")
|
296
|
-
value.gsub!("(0)", "{0}")
|
297
9
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
def format(key, value)
|
302
|
-
raise "Define in child"
|
303
|
-
end
|
304
|
-
|
305
|
-
def key_and_value_from_line(line)
|
306
|
-
raise "Define in child"
|
307
|
-
end
|
308
|
-
|
309
|
-
def comment?(line)
|
310
|
-
line =~ /^[\s]*#/
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
# Usage:
|
315
|
-
# Translator::Yaml.new().copy
|
316
|
-
#
|
317
|
-
class Yaml < Base
|
318
|
-
def extension
|
319
|
-
"yml"
|
320
|
-
end
|
321
|
-
|
322
|
-
def parse(path)
|
323
|
-
YAML.load_file(path)
|
324
|
-
end
|
325
|
-
|
326
|
-
def format(key, value)
|
327
|
-
"#{key}: #{value}"
|
328
|
-
end
|
329
|
-
|
330
|
-
def key_and_value_from_line(line)
|
331
|
-
if line =~ /^([^\:]+):(.*)/
|
332
|
-
return $1, $2.strip
|
333
|
-
else
|
334
|
-
return nil, nil
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
# Usage:
|
340
|
-
# Translator::Yrb.new(:source => "./translations/en-US.pres", :destination => "./translations",
|
341
|
-
# :use_dirs => false).translate
|
342
|
-
#
|
343
|
-
class Yrb < Base
|
344
|
-
def extension
|
345
|
-
"pres"
|
346
|
-
end
|
347
|
-
|
348
|
-
def parse(p)
|
349
|
-
YRB.load_file(p)
|
350
|
-
end
|
351
|
-
|
352
|
-
def format(key, value)
|
353
|
-
"#{key}=#{value}"
|
354
|
-
end
|
355
|
-
|
356
|
-
def key_and_value_from_line(line)
|
357
|
-
if line =~ /^([^\=]+)=(.+)/
|
358
|
-
return $1, $2
|
359
|
-
else
|
360
|
-
return nil, nil
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
10
|
+
require 'idiom/base'
|
11
|
+
require 'idiom/yrb'
|
12
|
+
require 'idiom/yaml'
|
data/lib/idiom/base.rb
ADDED
@@ -0,0 +1,339 @@
|
|
1
|
+
module Idiom #:nodoc:
|
2
|
+
# Finds English language translation keys which have not been translated
|
3
|
+
# and translates them through Google Translate.
|
4
|
+
#
|
5
|
+
module Directories #:nodoc:
|
6
|
+
def use_directories?
|
7
|
+
use_dirs
|
8
|
+
end
|
9
|
+
|
10
|
+
def destination_path(lang)
|
11
|
+
output_path = File.basename(@base_source).split(".").first
|
12
|
+
if use_directories?
|
13
|
+
"#{destination}/#{lang}/#{output_path}_#{lang}.#{extension}"
|
14
|
+
else
|
15
|
+
"#{destination}/#{output_path}_#{lang}.#{extension}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def ensure_destination_path_exists(lang)
|
20
|
+
dest = destination_path(lang)
|
21
|
+
dir = File.dirname(dest)
|
22
|
+
FileUtils.mkdir_p(dir)
|
23
|
+
|
24
|
+
dest
|
25
|
+
end
|
26
|
+
|
27
|
+
def destination_file_or_directory(lang)
|
28
|
+
if use_directories?
|
29
|
+
dir = File.dirname(destination_path(lang))
|
30
|
+
"#{dir}/*.#{extension}"
|
31
|
+
else
|
32
|
+
destination_path(lang)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Locales #:nodoc:
|
38
|
+
# Mapping of the way I18n country codes with the Google Translate codes.
|
39
|
+
#
|
40
|
+
# The key is the I18n representation, and the value is the code Google Translate would expect.
|
41
|
+
#
|
42
|
+
LOCALES = {
|
43
|
+
"de-DE" => "de",
|
44
|
+
"en-MY" => "en",
|
45
|
+
"en-SG" => "en",
|
46
|
+
"es-MX" => "es",
|
47
|
+
"it-IT" => "it",
|
48
|
+
"vi-VN" => "vi",
|
49
|
+
"zh-Hant-TW" => "zh-TW",
|
50
|
+
"en-AA" => "en",
|
51
|
+
"en-NZ" => "en",
|
52
|
+
"en-US" => "en",
|
53
|
+
"fr-FR" => "fr",
|
54
|
+
"ko-KR" => "ko",
|
55
|
+
"zh-Hans-CN" => "zh-CN",
|
56
|
+
"en-AU" => "en",
|
57
|
+
"en-PH" => "en",
|
58
|
+
"es-ES" => "es",
|
59
|
+
"id-ID" => "id",
|
60
|
+
"pt-BR" => "PORTUGUESE",
|
61
|
+
"zh-Hant-HK" => "zh-CN",
|
62
|
+
}
|
63
|
+
|
64
|
+
# locales
|
65
|
+
|
66
|
+
def non_us_locales
|
67
|
+
@non_us_locales ||= locales.select do |lang|
|
68
|
+
lang != "en-US"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def locales
|
73
|
+
@languages || LOCALES.keys
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Processing #:nodoc:
|
78
|
+
def pre_process(value, lang)
|
79
|
+
vars = []
|
80
|
+
index = 0
|
81
|
+
while value =~ /(\{\d+\})/
|
82
|
+
vars << $1
|
83
|
+
value.sub!(/(\{\d+\})/, "[#{index}]")
|
84
|
+
index += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
if lang !~ /^en/ && value != value.downcase
|
88
|
+
value = value.capitalize
|
89
|
+
end
|
90
|
+
|
91
|
+
value
|
92
|
+
end
|
93
|
+
|
94
|
+
def post_process(value, lang)
|
95
|
+
if lang =~ /zh/
|
96
|
+
value.gsub!("<strong>", "")
|
97
|
+
value.gsub!("</strong>", "")
|
98
|
+
end
|
99
|
+
|
100
|
+
value.gsub!(/^#{194.chr}#{160.chr}/, "")
|
101
|
+
|
102
|
+
value.gsub!(" ]", "]")
|
103
|
+
value.gsub!("«", "\"")
|
104
|
+
value.gsub!("»", "\"")
|
105
|
+
value.gsub!(/\"\.$/, ".\"")
|
106
|
+
value.gsub!(/\\ \"/, "\\\"")
|
107
|
+
value.gsub!(/<\/ /, "<\/")
|
108
|
+
value.gsub!(/(“|”)/, "\"")
|
109
|
+
value.gsub!("<strong> ", "<strong>")
|
110
|
+
value.gsub!(" </strong>", "</strong>")
|
111
|
+
value.gsub!(""", "\"")
|
112
|
+
value.gsub!("'", "\"")
|
113
|
+
value.gsub!("> ", ">")
|
114
|
+
|
115
|
+
value.gsub!("\"", "'")
|
116
|
+
value.gsub!(" \"O", " \\\"O")
|
117
|
+
|
118
|
+
while value =~ /\[(\d)\]/
|
119
|
+
index = $1.to_i
|
120
|
+
value.sub!(/\[#{index}\]/, "{#{index}}")
|
121
|
+
end
|
122
|
+
|
123
|
+
value.gsub!(/\((0)\)/, "{0}")
|
124
|
+
value.gsub!(/\((1)\)/, "{1}")
|
125
|
+
value.gsub!(/\((2)\)/, "{2}")
|
126
|
+
value.gsub!("(0)", "{0}")
|
127
|
+
|
128
|
+
value.strip
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module ClassMethods #:nodoc:
|
133
|
+
def translate(options={})
|
134
|
+
options.stringify_keys!
|
135
|
+
|
136
|
+
@source = options["source"]
|
137
|
+
@destination = options["destination"]
|
138
|
+
@use_dirs = options["use_dirs"]
|
139
|
+
|
140
|
+
Timer.new.time do
|
141
|
+
find_and_translate_all(options)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def source_files
|
146
|
+
if @source =~ /\.(yml|pres)$/
|
147
|
+
source_files = Dir[@source]
|
148
|
+
else
|
149
|
+
dir = File.expand_path(@source)
|
150
|
+
source_files = Dir["#{dir}/**/*_en-US.pres"] + Dir["#{dir}/**/*_en-US.yml"]
|
151
|
+
source_files.flatten!
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def find_and_translate_all(options={})
|
156
|
+
options.stringify_keys!
|
157
|
+
|
158
|
+
source_files.each do |path|
|
159
|
+
$stdout.puts "Processing #{path}"
|
160
|
+
translate_file(path, options)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def translate_file(path, options={})
|
165
|
+
options.stringify_keys!
|
166
|
+
if path =~ /\.yml$/i
|
167
|
+
Idiom::Yaml.new(options.merge({"source" => path})).generate
|
168
|
+
end
|
169
|
+
if path =~ /\.pres$/i
|
170
|
+
Idiom::Yrb.new(options.merge({"source" => path})).generate
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class Base
|
176
|
+
extend Idiom::ClassMethods
|
177
|
+
include Idiom::Directories
|
178
|
+
include Idiom::Locales
|
179
|
+
include Idiom::Processing
|
180
|
+
|
181
|
+
# Original filename to translate.
|
182
|
+
#
|
183
|
+
attr_accessor :source
|
184
|
+
|
185
|
+
# Destination directory to output the translated files to.
|
186
|
+
#
|
187
|
+
attr_accessor :destination
|
188
|
+
|
189
|
+
# Write the translated strings into a directory for each language?
|
190
|
+
#
|
191
|
+
attr_accessor :use_dirs
|
192
|
+
|
193
|
+
# Array of languages to translate into.
|
194
|
+
#
|
195
|
+
attr_accessor :languages
|
196
|
+
|
197
|
+
def initialize(options={})
|
198
|
+
options.stringify_keys!
|
199
|
+
|
200
|
+
@source = File.expand_path(options["source"])
|
201
|
+
@overwrite = options["overwrite"]
|
202
|
+
@languages = options["languages"]
|
203
|
+
|
204
|
+
@base_source = @source.gsub(/_en-US/, "")
|
205
|
+
|
206
|
+
# base directory of the source file
|
207
|
+
#
|
208
|
+
@source_dir = File.dirname(@source)
|
209
|
+
|
210
|
+
# if they specify the :use_dirs option, use that
|
211
|
+
# if not, detect whether the source path uses directories for each language
|
212
|
+
#
|
213
|
+
if options.has_key?("use_dirs")
|
214
|
+
@use_dirs = options["use_dirs"]
|
215
|
+
else
|
216
|
+
@use_dirs = @source_dir =~ /\/en-US$/
|
217
|
+
end
|
218
|
+
|
219
|
+
if @use_dirs
|
220
|
+
@source_dir = File.dirname(@source).gsub(/\/en-US$/, "")
|
221
|
+
end
|
222
|
+
@destination = options["destination"] || @source_dir
|
223
|
+
end
|
224
|
+
|
225
|
+
def generate
|
226
|
+
non_us_locales.each do |lang|
|
227
|
+
code = LOCALES[lang]
|
228
|
+
destination = ensure_destination_path_exists(lang)
|
229
|
+
new_content = each_line do |line|
|
230
|
+
copy_and_translate_line(line, lang)
|
231
|
+
end
|
232
|
+
write_content(destination, new_content)
|
233
|
+
clear_all_keys
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def new_translation_message
|
238
|
+
now = Time.now
|
239
|
+
|
240
|
+
date = now.day
|
241
|
+
month = now.month
|
242
|
+
year = now.year
|
243
|
+
|
244
|
+
timestamp = "#{month}/#{date}/#{year}"
|
245
|
+
output = []
|
246
|
+
output << "# "
|
247
|
+
output << "# Keys translated automatically on #{timestamp}."
|
248
|
+
output << "# "
|
249
|
+
|
250
|
+
output.join("\n")
|
251
|
+
end
|
252
|
+
|
253
|
+
def each_line
|
254
|
+
output = []
|
255
|
+
@lines ||= File.readlines(source)
|
256
|
+
|
257
|
+
@lines.each do |line|
|
258
|
+
new_line = yield line
|
259
|
+
output << new_line
|
260
|
+
end
|
261
|
+
output.compact.join("\n")
|
262
|
+
end
|
263
|
+
|
264
|
+
def parse(p)
|
265
|
+
raise "Define in child"
|
266
|
+
end
|
267
|
+
|
268
|
+
def all_keys(lang)
|
269
|
+
unless @all_keys
|
270
|
+
@all_keys = {}
|
271
|
+
Dir[destination_file_or_directory(lang)].each do |path|
|
272
|
+
if File.exists?(path)
|
273
|
+
keys = parse(path)
|
274
|
+
@all_keys = @all_keys.merge(keys)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
@all_keys
|
279
|
+
end
|
280
|
+
|
281
|
+
def clear_all_keys
|
282
|
+
@all_keys = nil
|
283
|
+
end
|
284
|
+
|
285
|
+
def write_content(destination, content)
|
286
|
+
unless content.blank?
|
287
|
+
$stdout.puts "Writing to #{destination}"
|
288
|
+
$stdout.puts content
|
289
|
+
$stdout.puts
|
290
|
+
File.open(destination, "a") do |f|
|
291
|
+
f.puts
|
292
|
+
f.puts new_translation_message
|
293
|
+
f.puts content
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def copy_and_translate_line(line, lang)
|
299
|
+
line = line.split("\n").first
|
300
|
+
if comment?(line) || line.blank?
|
301
|
+
nil
|
302
|
+
else
|
303
|
+
translate_new_key(line, lang)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def key_is_new?(k, lang)
|
308
|
+
k && !all_keys(lang).has_key?(k)
|
309
|
+
end
|
310
|
+
|
311
|
+
def translate_new_key(line, lang)
|
312
|
+
k, v = key_and_value_from_line(line)
|
313
|
+
if @overwrite || key_is_new?(k, lang)
|
314
|
+
format(k, translate(v, lang))
|
315
|
+
else
|
316
|
+
nil
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def translate(value, lang)
|
321
|
+
code = LOCALES[lang]
|
322
|
+
value = pre_process(value, lang)
|
323
|
+
translation = Translate.t(value, "ENGLISH", code)
|
324
|
+
post_process(translation, lang)
|
325
|
+
end
|
326
|
+
|
327
|
+
def format(key, value)
|
328
|
+
raise "Define in child"
|
329
|
+
end
|
330
|
+
|
331
|
+
def key_and_value_from_line(line)
|
332
|
+
raise "Define in child"
|
333
|
+
end
|
334
|
+
|
335
|
+
def comment?(line)
|
336
|
+
line =~ /^[\s]*#/
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
data/lib/idiom/yaml.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'idiom/base'
|
2
|
+
|
3
|
+
module Idiom #:nodoc:
|
4
|
+
# Usage:
|
5
|
+
# Translator::Yaml.new().copy
|
6
|
+
#
|
7
|
+
class Yaml < Base
|
8
|
+
def extension
|
9
|
+
"yml"
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse(path)
|
13
|
+
YAML.load_file(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(key, value)
|
17
|
+
"#{key}: #{value}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def key_and_value_from_line(line)
|
21
|
+
if line =~ /^([^\:]+):(.*)/
|
22
|
+
return $1, $2.strip
|
23
|
+
else
|
24
|
+
return nil, nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/idiom/yrb.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'idiom/base'
|
2
|
+
|
3
|
+
module Idiom #:nodoc
|
4
|
+
# Usage:
|
5
|
+
# Translator::Yrb.new(:source => "./translations/en-US.pres", :destination => "./translations",
|
6
|
+
# :use_dirs => false).translate
|
7
|
+
#
|
8
|
+
class Yrb < Base
|
9
|
+
def extension
|
10
|
+
"pres"
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(p)
|
14
|
+
YRB.load_file(p)
|
15
|
+
end
|
16
|
+
|
17
|
+
def format(key, value)
|
18
|
+
"#{key}=#{value}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def key_and_value_from_line(line)
|
22
|
+
if line =~ /^([^\=]+)=(.+)/
|
23
|
+
return $1, $2
|
24
|
+
else
|
25
|
+
return nil, nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: idiom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Coleman
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-30 00:00:00 -06:00
|
13
13
|
default_executable: idiom
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -73,6 +73,9 @@ files:
|
|
73
73
|
- bin/idiom
|
74
74
|
- idiom.gemspec
|
75
75
|
- lib/idiom.rb
|
76
|
+
- lib/idiom/base.rb
|
77
|
+
- lib/idiom/yaml.rb
|
78
|
+
- lib/idiom/yrb.rb
|
76
79
|
- spec/idiom_spec.rb
|
77
80
|
- spec/spec.opts
|
78
81
|
- spec/spec_helper.rb
|
@@ -104,7 +107,7 @@ rubyforge_project:
|
|
104
107
|
rubygems_version: 1.3.5
|
105
108
|
signing_key:
|
106
109
|
specification_version: 3
|
107
|
-
summary: Translate
|
110
|
+
summary: Translate all your application's international keys in Google Translate
|
108
111
|
test_files:
|
109
112
|
- spec/idiom_spec.rb
|
110
113
|
- spec/spec_helper.rb
|