translatomatic 0.1.3 → 0.2.0

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 (139) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +20 -20
  3. data/.gitignore +19 -15
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +28 -0
  6. data/.translatomatic/config.yml +4 -0
  7. data/.travis.yml +4 -6
  8. data/.yardopts +9 -9
  9. data/Gemfile +8 -4
  10. data/Guardfile +4 -5
  11. data/README.de.md +55 -50
  12. data/README.en.md +177 -0
  13. data/README.es.md +53 -48
  14. data/README.fr.md +53 -48
  15. data/README.it.md +54 -49
  16. data/README.ja.md +63 -58
  17. data/README.ko.md +59 -54
  18. data/README.md +17 -13
  19. data/README.ms.md +50 -45
  20. data/README.pt.md +54 -49
  21. data/README.ru.md +57 -52
  22. data/README.sv.md +51 -46
  23. data/README.zh.md +60 -55
  24. data/Rakefile +3 -3
  25. data/TODO.txt +6 -0
  26. data/bin/console +3 -3
  27. data/bin/translatomatic +4 -2
  28. data/config/i18n-tasks.yml +130 -0
  29. data/config/locales/translatomatic/de.yml +141 -99
  30. data/config/locales/translatomatic/en.yml +129 -89
  31. data/config/locales/translatomatic/es.yml +136 -99
  32. data/config/locales/translatomatic/fr.yml +139 -100
  33. data/config/locales/translatomatic/it.yml +135 -97
  34. data/config/locales/translatomatic/ja.yml +137 -98
  35. data/config/locales/translatomatic/ko.yml +138 -98
  36. data/config/locales/translatomatic/ms.yml +138 -100
  37. data/config/locales/translatomatic/pt.yml +137 -101
  38. data/config/locales/translatomatic/ru.yml +136 -98
  39. data/config/locales/translatomatic/sv.yml +134 -96
  40. data/config/locales/translatomatic/zh.yml +136 -97
  41. data/db/migrate/201712170000_initial.rb +2 -3
  42. data/lib/translatomatic.rb +40 -25
  43. data/lib/translatomatic/cli.rb +5 -1
  44. data/lib/translatomatic/cli/base.rb +61 -58
  45. data/lib/translatomatic/cli/common_options.rb +14 -11
  46. data/lib/translatomatic/cli/config.rb +96 -91
  47. data/lib/translatomatic/cli/database.rb +85 -23
  48. data/lib/translatomatic/cli/main.rb +158 -104
  49. data/lib/translatomatic/cli/thor.rb +29 -0
  50. data/lib/translatomatic/cli/translate.rb +134 -157
  51. data/lib/translatomatic/config.rb +10 -301
  52. data/lib/translatomatic/config/display.rb +78 -0
  53. data/lib/translatomatic/config/files.rb +60 -0
  54. data/lib/translatomatic/config/location_settings.rb +133 -0
  55. data/lib/translatomatic/config/options.rb +68 -0
  56. data/lib/translatomatic/config/selector.rb +127 -0
  57. data/lib/translatomatic/config/settings.rb +148 -0
  58. data/lib/translatomatic/converter.rb +40 -28
  59. data/lib/translatomatic/database.rb +127 -110
  60. data/lib/translatomatic/define_options.rb +4 -5
  61. data/lib/translatomatic/escaped_unicode.rb +86 -76
  62. data/lib/translatomatic/extractor.rb +5 -2
  63. data/lib/translatomatic/extractor/base.rb +12 -12
  64. data/lib/translatomatic/extractor/ruby.rb +7 -6
  65. data/lib/translatomatic/file_translator.rb +101 -244
  66. data/lib/translatomatic/flattenation.rb +39 -0
  67. data/lib/translatomatic/http.rb +13 -0
  68. data/lib/translatomatic/http/client.rb +144 -0
  69. data/lib/translatomatic/http/exception.rb +43 -0
  70. data/lib/translatomatic/http/file_param.rb +27 -0
  71. data/lib/translatomatic/http/param.rb +37 -0
  72. data/lib/translatomatic/http/request.rb +91 -0
  73. data/lib/translatomatic/i18n.rb +43 -0
  74. data/lib/translatomatic/locale.rb +71 -59
  75. data/lib/translatomatic/logger.rb +43 -28
  76. data/lib/translatomatic/metadata.rb +58 -0
  77. data/lib/translatomatic/model.rb +4 -2
  78. data/lib/translatomatic/model/locale.rb +5 -5
  79. data/lib/translatomatic/model/text.rb +5 -5
  80. data/lib/translatomatic/option.rb +57 -34
  81. data/lib/translatomatic/path_utils.rb +126 -0
  82. data/lib/translatomatic/progress_updater.rb +13 -16
  83. data/lib/translatomatic/provider.rb +101 -0
  84. data/lib/translatomatic/provider/base.rb +136 -0
  85. data/lib/translatomatic/provider/frengly.rb +55 -0
  86. data/lib/translatomatic/provider/google.rb +78 -0
  87. data/lib/translatomatic/provider/google_web.rb +50 -0
  88. data/lib/translatomatic/provider/microsoft.rb +144 -0
  89. data/lib/translatomatic/provider/my_memory.rb +75 -0
  90. data/lib/translatomatic/provider/yandex.rb +61 -0
  91. data/lib/translatomatic/resource_file.rb +59 -53
  92. data/lib/translatomatic/resource_file/base.rb +171 -237
  93. data/lib/translatomatic/resource_file/csv.rb +176 -24
  94. data/lib/translatomatic/resource_file/html.rb +21 -42
  95. data/lib/translatomatic/resource_file/key_value_support.rb +117 -0
  96. data/lib/translatomatic/resource_file/markdown.rb +36 -38
  97. data/lib/translatomatic/resource_file/plist.rb +121 -126
  98. data/lib/translatomatic/resource_file/po.rb +104 -82
  99. data/lib/translatomatic/resource_file/properties.rb +48 -77
  100. data/lib/translatomatic/resource_file/properties.treetop +87 -0
  101. data/lib/translatomatic/resource_file/resw.rb +56 -41
  102. data/lib/translatomatic/resource_file/subtitle.rb +86 -54
  103. data/lib/translatomatic/resource_file/text.rb +18 -18
  104. data/lib/translatomatic/resource_file/xcode_strings.rb +32 -63
  105. data/lib/translatomatic/resource_file/xcode_strings.treetop +85 -0
  106. data/lib/translatomatic/resource_file/xml.rb +94 -81
  107. data/lib/translatomatic/resource_file/yaml.rb +54 -68
  108. data/lib/translatomatic/retry_executor.rb +37 -0
  109. data/lib/translatomatic/slurp.rb +32 -0
  110. data/lib/translatomatic/string_batcher.rb +50 -0
  111. data/lib/translatomatic/string_escaping.rb +61 -0
  112. data/lib/translatomatic/text.rb +263 -0
  113. data/lib/translatomatic/text_collection.rb +66 -0
  114. data/lib/translatomatic/tmx.rb +5 -3
  115. data/lib/translatomatic/tmx/document.rb +107 -82
  116. data/lib/translatomatic/tmx/translation_unit.rb +19 -18
  117. data/lib/translatomatic/translation.rb +8 -28
  118. data/lib/translatomatic/translation/collection.rb +199 -0
  119. data/lib/translatomatic/translation/fetcher.rb +123 -0
  120. data/lib/translatomatic/translation/munging.rb +112 -0
  121. data/lib/translatomatic/translation/result.rb +50 -0
  122. data/lib/translatomatic/translation/sharer.rb +32 -0
  123. data/lib/translatomatic/translation/stats.rb +44 -0
  124. data/lib/translatomatic/translator.rb +91 -88
  125. data/lib/translatomatic/type_cast.rb +63 -0
  126. data/lib/translatomatic/util.rb +37 -33
  127. data/lib/translatomatic/version.rb +2 -2
  128. data/translatomatic.gemspec +57 -46
  129. metadata +136 -59
  130. data/lib/translatomatic/http_request.rb +0 -162
  131. data/lib/translatomatic/string.rb +0 -188
  132. data/lib/translatomatic/translation_result.rb +0 -86
  133. data/lib/translatomatic/translation_stats.rb +0 -31
  134. data/lib/translatomatic/translator/base.rb +0 -128
  135. data/lib/translatomatic/translator/frengly.rb +0 -62
  136. data/lib/translatomatic/translator/google.rb +0 -37
  137. data/lib/translatomatic/translator/microsoft.rb +0 -41
  138. data/lib/translatomatic/translator/my_memory.rb +0 -68
  139. data/lib/translatomatic/translator/yandex.rb +0 -56
@@ -1,162 +0,0 @@
1
- require 'securerandom'
2
- require 'net/http'
3
-
4
- module Translatomatic
5
- # HTTP request
6
- # wrapper for Net::HTTP functionality
7
- class HTTPRequest
8
-
9
- # @return [String] the text to use to denote multipart boundaries. By
10
- # default, a random hexadecimal string is used.
11
- attr_accessor :multipart_boundary
12
-
13
- # @param url [String,URI] URL of the request
14
- # @return [Translatomatic::HTTPRequest] Create a new request
15
- def initialize(url)
16
- @uri = url.respond_to?(:host) ? url : URI.parse(url)
17
- @multipart_boundary = SecureRandom.hex(16)
18
- end
19
-
20
- # Start the HTTP request. Yields a http object.
21
- # @param options [Hash<Symbol,Object>] Request options
22
- # @return [Object] Result of the block
23
- def start(options = {})
24
- options = options.merge(use_ssl: @uri.scheme == "https")
25
- result = nil
26
- Net::HTTP.start(@uri.host, @uri.port, options) do |http|
27
- @http = http
28
- result = yield http
29
- end
30
- @http = nil
31
- result
32
- end
33
-
34
- # Send a HTTP GET request
35
- # @param query [Hash<String,String>] Optional query parameters
36
- # @return [Net::HTTP::Response]
37
- def get(query = nil)
38
- uri = @uri
39
- if query
40
- uri = @uri.dup
41
- uri.query = URI.encode_www_form(query)
42
- end
43
- request = Net::HTTP::Get.new(uri)
44
- request['User-Agent'] = USER_AGENT
45
- send_request(request)
46
- end
47
-
48
- # Send an HTTP POST request
49
- # @param body [String,Hash] Body of the request
50
- # @return [Net::HTTP::Response]
51
- def post(body, options = {})
52
- request = Net::HTTP::Post.new(@uri)
53
- request['User-Agent'] = USER_AGENT
54
- content_type = options[:content_type]
55
-
56
- if options[:multipart]
57
- content_type = "multipart/form-data; boundary=#{@multipart_boundary}"
58
- request.body = multipartify(body)
59
- elsif body.kind_of?(Hash)
60
- # set_form_data does url encoding
61
- request.set_form_data(body)
62
- else
63
- request.body = body
64
- end
65
- request.content_type = content_type if content_type
66
-
67
- send_request(request)
68
- end
69
-
70
- # Create a file parameter for a multipart POST request
71
- # @return [FileParam] A new file parameter
72
- def file(*args)
73
- FileParam.new(*args)
74
- end
75
-
76
- # Create a parameter for a multipart POST request
77
- # @return [Param] A new parameter
78
- def param(*args)
79
- Param.new(*args)
80
- end
81
-
82
- private
83
-
84
- USER_AGENT = "Translatomatic #{VERSION} (+#{URL})"
85
-
86
- # Formats a basic string key/value pair for a multipart post
87
- class Param
88
- attr_accessor :key, :value
89
-
90
- # @return [String] Representation of this parameter as it appears
91
- # within a multipart post request.
92
- def to_s
93
- return header(header_data) + "\r\n#{value}\r\n"
94
- end
95
-
96
- private
97
-
98
- def initialize(key:, value:)
99
- @key = key
100
- @value = value
101
- end
102
-
103
- def header_data
104
- name = CGI::escape(key.to_s)
105
- { "Content-Disposition": "form-data", name: %Q("#{name}") }
106
- end
107
-
108
- def header(options)
109
- out = []
110
- idx = 0
111
- options.each do |key, value|
112
- separator = idx == 0 ? ": " : "="
113
- out << "#{key}#{separator}#{value}"
114
- idx += 1
115
- end
116
- out.join("; ") + "\r\n"
117
- end
118
- end
119
-
120
- # Formats the contents of a file or string for a multipart post
121
- class FileParam < Param
122
- attr_accessor :filename, :content, :mime_type
123
-
124
- # (see Param#to_s)
125
- def to_s
126
- return header(header_data) +
127
- header("Content-Type": mime_type) + "\r\n#{content}\r\n"
128
- end
129
-
130
- private
131
-
132
- def initialize(key:, filename:, content:, mime_type:)
133
- @key = key
134
- @filename = filename
135
- @content = content
136
- @mime_type = mime_type
137
- end
138
-
139
- def header_data
140
- super.merge({ filename: %Q("#{filename}") })
141
- end
142
- end
143
-
144
- def multipartify(parts)
145
- string_parts = parts.collect do |p|
146
- "--" + @multipart_boundary + "\r\n" + p.to_s
147
- end
148
- string_parts.join("") + "--" + @multipart_boundary + "--\r\n"
149
- end
150
-
151
- def send_request(req)
152
- if @http
153
- response = @http.request(req)
154
- else
155
- response = start { |http| http.request(req) }
156
- end
157
- raise response.body unless response.kind_of? Net::HTTPSuccess
158
- response
159
- end
160
-
161
- end # class
162
- end # module
@@ -1,188 +0,0 @@
1
- module Translatomatic
2
- # A string object with an associated locale.
3
- class String
4
-
5
- # @return [String] The string
6
- attr_reader :value
7
-
8
- # @return [Translatomatic::Locale] The string's locale
9
- attr_reader :locale
10
-
11
- # @return [Translatomatic::String] If this string is a substring of
12
- # another string, returns the original string. Otherwise, returns nil.
13
- attr_reader :parent
14
-
15
- # @return [Number] If this string is a substring of another string,
16
- # returns the starting offset of this string in the original.
17
- attr_reader :offset
18
-
19
- def initialize(value, locale, options = {})
20
- @value = value.to_s || ''
21
- @locale = Translatomatic::Locale.parse(locale)
22
- @offset = options[:offset] || 0
23
- @parent = options[:parent]
24
- end
25
-
26
- # @return [String] The value of the string
27
- def to_s
28
- @value
29
- end
30
-
31
- # @return [Number] The length of the string
32
- def length
33
- @value.length
34
- end
35
-
36
- # @return [boolean] True if the string is empty
37
- def empty?
38
- @value.empty?
39
- end
40
-
41
- # Invokes value.match
42
- # @param pattern [Regexp,String] The regex pattern to match
43
- # @return [MatchData] Object describing the match, or nil if no match
44
- def match(pattern)
45
- @value.match(pattern)
46
- end
47
-
48
- # @return [boolean] true if this string is a substring of another string
49
- def substring?
50
- @parent ? true : false
51
- end
52
-
53
- # @return [Symbol] The type of string, corresponding to TMX segtype.
54
- # @see http://xml.coverpages.org/tmxSpec971212.html#SEGTYPE
55
- def type
56
- if sentences.length >= 2
57
- :paragraph
58
- else
59
- script = script_data
60
- @value.strip.match(/#{script.delimiter}\s*$/) ? :sentence : :phrase
61
- end
62
- end
63
-
64
- # Find all sentences in the string
65
- # @return [Array<Translatomatic::String] List of sentences
66
- def sentences
67
- substrings(sentence_regex)
68
- end
69
-
70
- # Find all substrings matching the given regex
71
- # @return [Array<Translatomatic::String] List of substrings
72
- def substrings(regex)
73
- matches = matches(@value, regex)
74
- strings = []
75
- matches.each do |match|
76
- substring = match.to_s
77
- # find leading and trailing whitespace
78
- next if substring.length == 0
79
-
80
- parts = substring.match(/\A(\s*)(.*?)(\s*)\z/m).to_a
81
- value = parts[2]
82
- offset = match.offset(0)[0]
83
- offset += parts[1].length # leading whitespace
84
- strings << self.class.new(value, locale, offset: offset, parent: self)
85
- end
86
-
87
- # return [self] if there's only one substring and it's equal to self
88
- strings.length == 1 && strings[0].eql?(self) ? [self] : strings
89
- end
90
-
91
- # @return [boolean] true if other is a {Translatomatic::String} with
92
- # the same value and locale.
93
- def eql?(other)
94
- other.kind_of?(Translatomatic::String) && other.hash == hash
95
- end
96
-
97
- # (see #eql?)
98
- def ==(other)
99
- eql?(other)
100
- end
101
-
102
- # @!visibility private
103
- def hash
104
- [value, locale].hash
105
- end
106
-
107
- private
108
-
109
- # @!visibility private
110
- class Script
111
- attr_reader :language
112
- attr_reader :delimiter # sentence delimiter
113
- attr_reader :trailing_space # delimiter requires trailing space or eol
114
- attr_reader :left_to_right # script direction
115
-
116
- def initialize(language:, delimiter:, trailing_space:, direction:)
117
- @language = language
118
- @delimiter = delimiter
119
- @trailing_space = trailing_space
120
- @left_to_right = direction == :ltr
121
- raise "invalid direction" unless [:ltr, :rtl].include?(direction)
122
- end
123
- end
124
-
125
- SCRIPT_DATA = [
126
- # [language, delimiter, trailing space, direction]
127
- # japanese, no space after
128
- ["ja", "\u3002", false, :ltr],
129
- # chinese, no space after
130
- ["zh", "\u3002", false, :ltr], # can be written any direction
131
- # armenian, space after
132
- ["hy", ":", true, :ltr],
133
- # hindi, space after
134
- ["hi", "।", true, :ltr],
135
- # urdu, space after, right to left
136
- ["ur", "\u06d4", true, :rtl],
137
- # thai, spaces used to separate sentences
138
- ["th", "\\s", false, :ltr],
139
- # arabic, right to left
140
- ["ar", "\\.", true, :rtl],
141
- # hebrew, right to left
142
- ["he", "\\.", true, :rtl],
143
- # all other languages
144
- ["default", "\\.", true, :ltr],
145
- ]
146
-
147
- class << self
148
- attr_reader :script_data
149
- end
150
-
151
- begin
152
- script_data = {}
153
- SCRIPT_DATA.each do |lang, delimiter, trailing, ltr|
154
- script = Script.new(language: lang, delimiter: delimiter,
155
- trailing_space: trailing, direction: ltr)
156
- script_data[lang] = script
157
- end
158
- @script_data = script_data
159
- end
160
-
161
- def matches(s, re)
162
- start_at = 0
163
- matches = []
164
- while(m = s.match(re, start_at))
165
- break if m.to_s.empty?
166
- matches.push(m)
167
- start_at = m.end(0)
168
- end
169
- matches
170
- end
171
-
172
- def sentence_regex
173
- script = script_data
174
- if script.trailing_space
175
- regex = /.*?(?:#{script.delimiter}\s+|\z)/m
176
- else
177
- # no trailing space after delimiter
178
- regex = /.*?(?:#{script.delimiter}|\z)/m
179
- end
180
- end
181
-
182
- def script_data
183
- data = self.class.script_data
184
- data[locale.language] || data["default"]
185
- end
186
-
187
- end
188
- end
@@ -1,86 +0,0 @@
1
- require 'set'
2
-
3
- module Translatomatic
4
- # Stores results of a translation
5
- class TranslationResult
6
-
7
- # @return [Translatomatic::ResourceFile::Base] The resource file
8
- attr_reader :file
9
-
10
- # @return [Hash<String,String>] Translation results
11
- attr_reader :properties
12
-
13
- # @return [Locale] The locale of the original strings
14
- attr_reader :from_locale
15
-
16
- # @return [Locale] The target locale
17
- attr_reader :to_locale
18
-
19
- # @return [Set<String>] Untranslated strings
20
- attr_reader :untranslated
21
-
22
- # Create a translation result
23
- # @param file [Translatomatic::ResourceFile::Base] A resource file
24
- # @param to_locale [Locale] The target locale
25
- def initialize(file, to_locale)
26
- @file = file
27
- @value_to_keys = {}
28
- @untranslated = Set.new
29
- @from_locale = file.locale
30
- @to_locale = to_locale
31
-
32
- # duplicate strings
33
- @properties = file.properties.transform_values { |i| i.dup }
34
-
35
- @properties.each do |key, value|
36
- # split property value into sentences
37
- string = string(value, from_locale)
38
- string.sentences.each do |sentence|
39
- @untranslated << sentence
40
- keylist = (@value_to_keys[sentence.to_s] ||= [])
41
- keylist << key
42
- end
43
- end
44
- end
45
-
46
- # Update result with a list of translated strings.
47
- # @param translations [Array<Translatomatic::Translation>] Translations
48
- # @return [void]
49
- def update_strings(translations)
50
- # sort translation list by largest offset first so that we replace
51
- # from the end of the string to the front, so substring offsets
52
- # are correct in the target string.
53
-
54
- #translations.sort_by! do |translation|
55
- # t1 = translation.original
56
- # t1.respond_to?(:offset) ? -t1.offset : 0
57
- #end
58
- translations.sort_by! { |t| -t.original.offset }
59
-
60
- translations.each do |translation|
61
- update(translation.original, translation.result)
62
- end
63
- end
64
-
65
- private
66
-
67
- include Translatomatic::Util
68
-
69
- def update(original, translated)
70
- keys = @value_to_keys[original.to_s]
71
- raise "no key mapping for text '#{original}'" unless keys
72
- keys.each do |key|
73
- #value = @properties[key]
74
- if original.kind_of?(Translatomatic::String) && original.substring?
75
- #log.debug("#{value[original.offset, original.length]} -> #{translated}")
76
- @properties[key][original.offset, original.length] = translated
77
- else
78
- #log.debug("#{key} -> #{translated}")
79
- @properties[key] = translated
80
- end
81
- end
82
-
83
- @untranslated.delete(original) unless translated.nil?
84
- end
85
- end
86
- end
@@ -1,31 +0,0 @@
1
- # Translation statistics
2
- class Translatomatic::TranslationStats
3
- include Translatomatic::Util
4
-
5
- # @return [Array<Translatomatic::Translation>] A list of all translations
6
- attr_reader :translations
7
-
8
- # @return [Number] The number of translations that came from the database.
9
- attr_reader :from_db
10
-
11
- # @return [Number] The number of translations that came from the translator.
12
- attr_reader :from_translator
13
-
14
- # @return [Number] The number of untranslated strings
15
- attr_reader :untranslated
16
-
17
- private
18
-
19
- def initialize(translations)
20
- @translations = translations.values
21
- @from_db = @translations.count { |i| i.from_database && i.result }
22
- @from_translator = @translations.count { |i| !i.from_database && i.result }
23
- @untranslated = @translations.count { |i| i.result == nil }
24
- end
25
-
26
- def to_s
27
- t("file_translator.total_translations", total: @translations.length,
28
- from_db: @from_db, from_translator: @from_translator,
29
- untranslated: @untranslated)
30
- end
31
- end