translatomatic 0.1.0 → 0.1.1

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.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +1 -0
  3. data/.gitignore +15 -12
  4. data/.rspec +3 -3
  5. data/.travis.yml +32 -50
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/Gemfile +29 -5
  8. data/Guardfile +48 -0
  9. data/LICENSE.txt +21 -21
  10. data/README.de.md +92 -0
  11. data/README.es.md +92 -0
  12. data/README.fr.md +92 -0
  13. data/README.it.md +92 -0
  14. data/README.ja.md +92 -0
  15. data/README.md +96 -74
  16. data/Rakefile +6 -6
  17. data/bin/setup +8 -8
  18. data/bin/translatomatic +6 -6
  19. data/bin/travis +26 -0
  20. data/db/database.yml +9 -9
  21. data/db/migrate/201712170000_initial.rb +24 -23
  22. data/lib/translatomatic/cli.rb +204 -80
  23. data/lib/translatomatic/config.rb +12 -26
  24. data/lib/translatomatic/converter.rb +206 -142
  25. data/lib/translatomatic/converter_stats.rb +27 -27
  26. data/lib/translatomatic/database.rb +139 -99
  27. data/lib/translatomatic/escaped_unicode.rb +90 -90
  28. data/lib/translatomatic/extractor/base.rb +14 -0
  29. data/lib/translatomatic/extractor/ruby.rb +5 -0
  30. data/lib/translatomatic/extractor.rb +4 -0
  31. data/lib/translatomatic/http_request.rb +133 -0
  32. data/lib/translatomatic/locale.rb +52 -0
  33. data/lib/translatomatic/logger.rb +28 -0
  34. data/lib/translatomatic/model/locale.rb +21 -22
  35. data/lib/translatomatic/model/text.rb +17 -13
  36. data/lib/translatomatic/model.rb +4 -4
  37. data/lib/translatomatic/option.rb +24 -24
  38. data/lib/translatomatic/progress_updater.rb +15 -0
  39. data/lib/translatomatic/resource_file/base.rb +169 -137
  40. data/lib/translatomatic/resource_file/html.rb +46 -28
  41. data/lib/translatomatic/resource_file/markdown.rb +54 -0
  42. data/lib/translatomatic/resource_file/plist.rb +30 -29
  43. data/lib/translatomatic/resource_file/properties.rb +72 -60
  44. data/lib/translatomatic/resource_file/resw.rb +30 -0
  45. data/lib/translatomatic/resource_file/text.rb +29 -28
  46. data/lib/translatomatic/resource_file/xcode_strings.rb +71 -65
  47. data/lib/translatomatic/resource_file/xml.rb +79 -59
  48. data/lib/translatomatic/resource_file/yaml.rb +82 -80
  49. data/lib/translatomatic/resource_file.rb +76 -74
  50. data/lib/translatomatic/string.rb +160 -0
  51. data/lib/translatomatic/tmx/document.rb +100 -0
  52. data/lib/translatomatic/tmx/translation_unit.rb +19 -0
  53. data/lib/translatomatic/tmx.rb +4 -0
  54. data/lib/translatomatic/translation_result.rb +75 -57
  55. data/lib/translatomatic/translator/base.rb +83 -47
  56. data/lib/translatomatic/translator/frengly.rb +57 -64
  57. data/lib/translatomatic/translator/google.rb +31 -30
  58. data/lib/translatomatic/translator/microsoft.rb +33 -32
  59. data/lib/translatomatic/translator/my_memory.rb +64 -55
  60. data/lib/translatomatic/translator/yandex.rb +39 -37
  61. data/lib/translatomatic/translator.rb +63 -63
  62. data/lib/translatomatic/util.rb +15 -24
  63. data/lib/translatomatic/version.rb +4 -3
  64. data/lib/translatomatic.rb +32 -27
  65. data/translatomatic.gemspec +43 -45
  66. metadata +52 -18
  67. data/Gemfile.lock +0 -137
@@ -1,92 +1,216 @@
1
- require "thor"
1
+ require "thor"
2
+
3
+ class Translatomatic::CLI < Thor
4
+ include Translatomatic::Util
5
+
6
+ package_name "Translatomatic"
7
+ map %W[-v --version] => :version
8
+ map %W[-L --list] => :translators
9
+
10
+ desc "translate file locale...", "Translate files to target locales"
11
+ method_option :translator, enum: Translatomatic::Translator.names
12
+ method_option :source_locale, desc: "The locale of the source file"
13
+ method_option :debug, type: :boolean, desc: "Enable debugging output"
14
+ method_option :wank, type: :boolean, default: true, desc: "Enable Progress bar"
15
+ method_option :share, type: :boolean, default: false, desc:
16
+ "Share translations with translators that support upload"
17
+ Translatomatic::Converter.options.each do |option|
18
+ method_option option.name, option.to_hash
19
+ end
20
+ Translatomatic::Database.options.each do |option|
21
+ method_option option.name, option.to_hash
22
+ end
23
+ Translatomatic::Translator.modules.each do |mod|
24
+ mod.options.each do |option|
25
+ method_option option.name, option.to_hash
26
+ end
27
+ end
28
+ def translate(file, *locales)
29
+ run do
30
+ log.info("Dry run: files will not be translated or written") if options[:dry_run]
31
+ raise "One or more locales required" if locales.empty?
32
+
33
+ config.logger.level = Logger::DEBUG if options[:debug]
34
+
35
+ # load source file
36
+ raise "File not found: #{file}" unless File.exist?(file)
37
+ source = Translatomatic::ResourceFile.load(file, options[:source_locale])
38
+ raise "Unsupported file type #{file}" unless source
39
+
40
+ # set up database
41
+ Translatomatic::Database.new(options)
42
+
43
+ # select translator
44
+ translator = select_translator(options)
45
+ log.info("Using translator #{translator.name}")
46
+ log.debug("Locales: #{locales}, Properties: #{source.properties.length}")
47
+
48
+ # set up converter
49
+ translation_count = calculate_translation_count(source, locales)
50
+ converter_options = options.merge(
51
+ translator: translator, listener: progress_updater(translation_count)
52
+ )
53
+ converter = Translatomatic::Converter.new(converter_options)
54
+
55
+ # convert source to locale(s)
56
+ locales.each { |i| converter.translate(source, i) }
57
+
58
+ log.info converter.stats
59
+ config.logger.finish
2
60
 
3
- class Translatomatic::CLI < Thor
4
- include Translatomatic::Util
5
- package_name "Translatomatic"
6
- map %W[-v --version] => :version
7
- map %W[-L --list] => :translators
61
+ share_translations(converter) if options[:share]
62
+ end
63
+ end
64
+
65
+ desc "display file [key...]", "Display values from a resource bundle"
66
+ method_option :locales, type: :string, desc: "Locales to display"
67
+ method_option :sentences, type: :boolean, desc: "Display sentences"
68
+ def display(file, *keys)
69
+ run do
70
+ source = Translatomatic::ResourceFile.load(file)
71
+ keys = source.properties.keys if keys.empty?
72
+ display_keys(source, keys)
8
73
 
9
- desc "translate file locale...", "translate files to target locale(s)"
10
- method_option :translator, enum: Translatomatic::Translator.names
11
- method_option :source_locale, desc: "The locale of the source file, default is autodetermined"
12
- method_option :debug, type: :boolean, desc: "Turn on debugging output"
13
- Translatomatic::Converter.options.each do |option|
14
- method_option option.name, option.to_hash
15
- end
16
- Translatomatic::Database.options.each do |option|
17
- method_option option.name, option.to_hash
18
- end
19
- Translatomatic::Translator.modules.each do |mod|
20
- mod.options.each do |option|
21
- method_option option.name, option.to_hash
22
- end
23
- end
24
- def translate(file, locale, *locales)
25
- begin
26
- log.info("dry run: files will not be translated or written") if options[:dry_run]
27
-
28
- Translatomatic::Config.instance.debug = options[:debug] if options[:debug]
29
- Translatomatic::Database.new(options)
30
-
31
- translator = select_translator
32
- log.info("Using translator #{translator.name}")
33
-
34
- converter_options = options.merge(translator: translator)
35
- converter = Translatomatic::Converter.new(converter_options)
36
- source = Translatomatic::ResourceFile.load(file, options[:source_locale])
37
-
38
- raise "Unsupported file type #{file}" unless source
39
- target_locales = [locale]
40
- target_locales += locales
41
- target_locales.each { |i| converter.translate(source, i) }
42
-
43
- log.info converter.stats
44
- true
45
- rescue Interrupt
46
- puts "\nAborted"
47
- false
48
- rescue Exception => e
49
- log.error("Error translating #{file}")
50
- log.error(e.message)
51
- log.debug(e.backtrace.join("\n"))
52
- false
53
- end
54
- end
55
-
56
- desc "translators", "list available translation backends"
57
- def translators
58
- puts Translatomatic::Translator.list
59
- end
74
+ # TODO: if locales not specified, determine the list of locales from
75
+ # all the files in the resource bundle.
76
+ locales = (options[:locales] || "").split(',').flatten.compact
77
+ locales << Translatomatic::Locale.default.to_s if locales.empty?
78
+ locales.each do |locale|
79
+ display_properties(source, locale)
80
+ end
81
+ end
82
+ end
83
+
84
+ desc "strings file [file...]", "Extract strings from non-resource files"
85
+ def strings(*files)
86
+ run do
87
+ strings = []
88
+ files.each do |file|
89
+ extractor = Translatomatic::Extractor::Base.new(file)
90
+ strings << extractor.extract
91
+ end
92
+ puts strings.join("\n")
93
+ end
94
+ end
95
+
96
+ desc "list", "List available translation backends"
97
+ def list
98
+ run { puts Translatomatic::Translator.list }
99
+ end
100
+
101
+ desc 'version', 'Display version'
102
+ def version
103
+ puts "Translatomatic version #{Translatomatic::VERSION}"
104
+ end
105
+
106
+ private
60
107
 
61
- desc 'version', 'Display version'
62
- def version
63
- puts "Translatomatic version #{Translatomatic::VERSION}"
108
+ def calculate_translation_count(source, locales)
109
+ source.sentences.length * locales.length
64
110
  end
65
111
 
66
- private
67
-
68
- def select_translator
69
- # use options translator if specified
70
- if options[:translator]
71
- klass = Translatomatic::Translator.find(options[:translator])
72
- return klass.new(options)
73
- end
112
+ def share_translations(converter)
113
+ return if converter.db_translations.empty?
74
114
 
75
- # find all available translators that work with the given options
115
+ tmx = Translatomatic::TMX::Document.from_texts(converter.db_translations)
76
116
  available = Translatomatic::Translator.available(options)
77
- if available.empty?
78
- raise "No translators configured. Use the translators command to see options"
117
+ available.each do |translator|
118
+ if translator.respond_to?(:upload)
119
+ log.debug("Uploading tmx to #{translator.name}")
120
+ translator.upload(tmx)
121
+ end
79
122
  end
80
123
 
81
- return available[0] if available.length == 1
124
+ ActiveRecord::Base.transaction do
125
+ converter.db_translations.each do |text|
126
+ text.update(shared: true) if text.is_translated?
127
+ end
128
+ end
129
+ end
130
+
131
+ # create a progress bar and progress updater
132
+ def progress_updater(translation_count)
133
+ return nil unless options[:wank]
134
+ # set up progress bar
135
+ progressbar = ProgressBar.create(
136
+ title: "Translating",
137
+ format: "%t: |%B| %E ",
138
+ autofinish: false,
139
+ total: translation_count
140
+ )
141
+ config.logger.progressbar = progressbar
142
+ Translatomatic::ProgressUpdater.new(progressbar)
143
+ end
144
+
145
+ # run the give code block, display exceptions.
146
+ # return true if the code ran without exceptions
147
+ def run
148
+ begin
149
+ yield
150
+ true
151
+ rescue Interrupt
152
+ puts "\nAborted"
153
+ false
154
+ rescue Exception => e
155
+ log.error(e.message)
156
+ log.debug(e.backtrace.join("\n"))
157
+ false
158
+ end
159
+ end
82
160
 
83
- # prompt user for which translator to use
84
- say("Multiple translators available:")
85
- available.each_with_index { |mod, i| say(" #{i + 1}) #{mod.name}") }
86
- loop do
87
- idx = ask("Select translator (1-#{available.length}): ")
88
- idx = idx.to_i
89
- return available[idx - 1] if (1..available.length).include?(idx)
161
+ def display_properties(source, locale)
162
+ path = source.locale_path(locale)
163
+ if path.exist?
164
+ resource = Translatomatic::ResourceFile.load(path)
165
+ display_keys(resource, keys)
90
166
  end
91
167
  end
92
- end
168
+
169
+ def display_keys(source, keys)
170
+ puts "File: #{source}"
171
+ table = []
172
+ keys.each do |key|
173
+ value = source.get(key)
174
+ table << [key + ":", value]
175
+ end
176
+ print_table(table, indent: 2)
177
+
178
+ if options[:sentences]
179
+ puts "Sentences:"
180
+ source.sentences.each do |sentence|
181
+ puts "- " + sentence.to_s
182
+ end
183
+ end
184
+
185
+ puts
186
+ end
187
+
188
+ def config
189
+ Translatomatic::Config.instance
190
+ end
191
+
192
+ def select_translator(options)
193
+ # use options translator if specified
194
+ if options[:translator]
195
+ klass = Translatomatic::Translator.find(options[:translator])
196
+ return klass.new(options)
197
+ end
198
+
199
+ # find all available translators that work with the given options
200
+ available = Translatomatic::Translator.available(options)
201
+ if available.empty?
202
+ raise "No translators configured. Use the translators command to see options"
203
+ end
204
+
205
+ return available[0] if available.length == 1
206
+
207
+ # prompt user for which translator to use
208
+ say("Multiple translators available:")
209
+ available.each_with_index { |mod, i| say(" #{i + 1}) #{mod.name}") }
210
+ loop do
211
+ idx = ask("Select translator (1-#{available.length}): ")
212
+ idx = idx.to_i
213
+ return available[idx - 1] if (1..available.length).include?(idx)
214
+ end
215
+ end
216
+ end
@@ -1,26 +1,12 @@
1
- require 'singleton'
2
- class Translatomatic::Config
3
- include Singleton
4
-
5
- attr_accessor :logger
6
- attr_accessor :debug
7
-
8
- def debug=(value)
9
- @debug = value ? true : false
10
- @logger.level = @debug ? Logger::DEBUG : Logger::INFO
11
- end
12
-
13
- private
14
-
15
- def initialize
16
- @logger = Logger.new(STDOUT)
17
- @logger.formatter = proc do |severity, datetime, progname, msg|
18
- "#{msg}\n"
19
- end
20
- self.debug = ENV['DEBUG'] ? true : false
21
- end
22
-
23
- def debug?
24
- @debug
25
- end
26
- end
1
+ require 'singleton'
2
+ class Translatomatic::Config
3
+ include Singleton
4
+
5
+ attr_accessor :logger
6
+
7
+ private
8
+
9
+ def initialize
10
+ @logger = Translatomatic::Logger.new
11
+ end
12
+ end