translatomatic 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitattributes +1 -0
- data/.gitignore +15 -12
- data/.rspec +3 -3
- data/.travis.yml +32 -50
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +29 -5
- data/Guardfile +48 -0
- data/LICENSE.txt +21 -21
- data/README.de.md +92 -0
- data/README.es.md +92 -0
- data/README.fr.md +92 -0
- data/README.it.md +92 -0
- data/README.ja.md +92 -0
- data/README.md +96 -74
- data/Rakefile +6 -6
- data/bin/setup +8 -8
- data/bin/translatomatic +6 -6
- data/bin/travis +26 -0
- data/db/database.yml +9 -9
- data/db/migrate/201712170000_initial.rb +24 -23
- data/lib/translatomatic/cli.rb +204 -80
- data/lib/translatomatic/config.rb +12 -26
- data/lib/translatomatic/converter.rb +206 -142
- data/lib/translatomatic/converter_stats.rb +27 -27
- data/lib/translatomatic/database.rb +139 -99
- data/lib/translatomatic/escaped_unicode.rb +90 -90
- data/lib/translatomatic/extractor/base.rb +14 -0
- data/lib/translatomatic/extractor/ruby.rb +5 -0
- data/lib/translatomatic/extractor.rb +4 -0
- data/lib/translatomatic/http_request.rb +133 -0
- data/lib/translatomatic/locale.rb +52 -0
- data/lib/translatomatic/logger.rb +28 -0
- data/lib/translatomatic/model/locale.rb +21 -22
- data/lib/translatomatic/model/text.rb +17 -13
- data/lib/translatomatic/model.rb +4 -4
- data/lib/translatomatic/option.rb +24 -24
- data/lib/translatomatic/progress_updater.rb +15 -0
- data/lib/translatomatic/resource_file/base.rb +169 -137
- data/lib/translatomatic/resource_file/html.rb +46 -28
- data/lib/translatomatic/resource_file/markdown.rb +54 -0
- data/lib/translatomatic/resource_file/plist.rb +30 -29
- data/lib/translatomatic/resource_file/properties.rb +72 -60
- data/lib/translatomatic/resource_file/resw.rb +30 -0
- data/lib/translatomatic/resource_file/text.rb +29 -28
- data/lib/translatomatic/resource_file/xcode_strings.rb +71 -65
- data/lib/translatomatic/resource_file/xml.rb +79 -59
- data/lib/translatomatic/resource_file/yaml.rb +82 -80
- data/lib/translatomatic/resource_file.rb +76 -74
- data/lib/translatomatic/string.rb +160 -0
- data/lib/translatomatic/tmx/document.rb +100 -0
- data/lib/translatomatic/tmx/translation_unit.rb +19 -0
- data/lib/translatomatic/tmx.rb +4 -0
- data/lib/translatomatic/translation_result.rb +75 -57
- data/lib/translatomatic/translator/base.rb +83 -47
- data/lib/translatomatic/translator/frengly.rb +57 -64
- data/lib/translatomatic/translator/google.rb +31 -30
- data/lib/translatomatic/translator/microsoft.rb +33 -32
- data/lib/translatomatic/translator/my_memory.rb +64 -55
- data/lib/translatomatic/translator/yandex.rb +39 -37
- data/lib/translatomatic/translator.rb +63 -63
- data/lib/translatomatic/util.rb +15 -24
- data/lib/translatomatic/version.rb +4 -3
- data/lib/translatomatic.rb +32 -27
- data/translatomatic.gemspec +43 -45
- metadata +52 -18
- data/Gemfile.lock +0 -137
@@ -1,90 +1,90 @@
|
|
1
|
-
# Module to encode and decode unicode chars.
|
2
|
-
# This code is highly influced by Florian Frank's JSON gem
|
3
|
-
# @see https://github.com/jnbt/java-properties
|
4
|
-
# @see https://github.com/flori/json/
|
5
|
-
|
6
|
-
module Translatomatic::EscapedUnicode
|
7
|
-
|
8
|
-
# Decodes all unicode chars from escape sequences
|
9
|
-
# @param text [String]
|
10
|
-
# @return [String] The encoded text for chaining
|
11
|
-
def self.unescape(text)
|
12
|
-
string = text.dup
|
13
|
-
string = string.gsub(%r((?:\\[uU](?:[A-Fa-f\d]{4}))+)) do |c|
|
14
|
-
c.downcase!
|
15
|
-
bytes = EMPTY_8BIT_STRING.dup
|
16
|
-
i = 0
|
17
|
-
while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
|
18
|
-
bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
|
19
|
-
i += 1
|
20
|
-
end
|
21
|
-
bytes.encode("utf-8", "utf-16be")
|
22
|
-
end
|
23
|
-
string.force_encoding(::Encoding::UTF_8)
|
24
|
-
|
25
|
-
text.replace string
|
26
|
-
text
|
27
|
-
end
|
28
|
-
|
29
|
-
# Decodes all unicode chars into escape sequences
|
30
|
-
# @param text [String]
|
31
|
-
# @return [String] The decoded text for chaining
|
32
|
-
def self.escape(text)
|
33
|
-
string = text.dup
|
34
|
-
string.force_encoding(::Encoding::ASCII_8BIT)
|
35
|
-
string.gsub!(/["\\\x0-\x1f]/n) { |c| MAP[c] || c }
|
36
|
-
string.gsub!(/(
|
37
|
-
(?:
|
38
|
-
[\xc2-\xdf][\x80-\xbf] |
|
39
|
-
[\xe0-\xef][\x80-\xbf]{2} |
|
40
|
-
[\xf0-\xf4][\x80-\xbf]{3}
|
41
|
-
)+ |
|
42
|
-
[\x80-\xc1\xf5-\xff] # invalid
|
43
|
-
)/nx) { |c|
|
44
|
-
c.size == 1 and raise "Invalid utf8 byte: '#{c}'"
|
45
|
-
s = c.encode("utf-16be", "utf-8").unpack('H*')[0]
|
46
|
-
s.force_encoding(::Encoding::ASCII_8BIT)
|
47
|
-
s.gsub!(/.{4}/n, '\\\\u\&')
|
48
|
-
s.force_encoding(::Encoding::UTF_8)
|
49
|
-
}
|
50
|
-
string.force_encoding(::Encoding::UTF_8)
|
51
|
-
text.replace string
|
52
|
-
text
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
MAP = {
|
58
|
-
"\x0" => '\u0000',
|
59
|
-
"\x1" => '\u0001',
|
60
|
-
"\x2" => '\u0002',
|
61
|
-
"\x3" => '\u0003',
|
62
|
-
"\x4" => '\u0004',
|
63
|
-
"\x5" => '\u0005',
|
64
|
-
"\x6" => '\u0006',
|
65
|
-
"\x7" => '\u0007',
|
66
|
-
"\xb" => '\u000b',
|
67
|
-
"\xe" => '\u000e',
|
68
|
-
"\xf" => '\u000f',
|
69
|
-
"\x10" => '\u0010',
|
70
|
-
"\x11" => '\u0011',
|
71
|
-
"\x12" => '\u0012',
|
72
|
-
"\x13" => '\u0013',
|
73
|
-
"\x14" => '\u0014',
|
74
|
-
"\x15" => '\u0015',
|
75
|
-
"\x16" => '\u0016',
|
76
|
-
"\x17" => '\u0017',
|
77
|
-
"\x18" => '\u0018',
|
78
|
-
"\x19" => '\u0019',
|
79
|
-
"\x1a" => '\u001a',
|
80
|
-
"\x1b" => '\u001b',
|
81
|
-
"\x1c" => '\u001c',
|
82
|
-
"\x1d" => '\u001d',
|
83
|
-
"\x1e" => '\u001e',
|
84
|
-
"\x1f" => '\u001f',
|
85
|
-
}
|
86
|
-
|
87
|
-
EMPTY_8BIT_STRING = ''
|
88
|
-
EMPTY_8BIT_STRING.force_encoding(::Encoding::ASCII_8BIT)
|
89
|
-
|
90
|
-
end
|
1
|
+
# Module to encode and decode unicode chars.
|
2
|
+
# This code is highly influced by Florian Frank's JSON gem
|
3
|
+
# @see https://github.com/jnbt/java-properties
|
4
|
+
# @see https://github.com/flori/json/
|
5
|
+
|
6
|
+
module Translatomatic::EscapedUnicode
|
7
|
+
|
8
|
+
# Decodes all unicode chars from escape sequences
|
9
|
+
# @param text [String]
|
10
|
+
# @return [String] The encoded text for chaining
|
11
|
+
def self.unescape(text)
|
12
|
+
string = text.dup
|
13
|
+
string = string.gsub(%r((?:\\[uU](?:[A-Fa-f\d]{4}))+)) do |c|
|
14
|
+
c.downcase!
|
15
|
+
bytes = EMPTY_8BIT_STRING.dup
|
16
|
+
i = 0
|
17
|
+
while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
|
18
|
+
bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
|
19
|
+
i += 1
|
20
|
+
end
|
21
|
+
bytes.encode("utf-8", "utf-16be")
|
22
|
+
end
|
23
|
+
string.force_encoding(::Encoding::UTF_8)
|
24
|
+
|
25
|
+
text.replace string
|
26
|
+
text
|
27
|
+
end
|
28
|
+
|
29
|
+
# Decodes all unicode chars into escape sequences
|
30
|
+
# @param text [String]
|
31
|
+
# @return [String] The decoded text for chaining
|
32
|
+
def self.escape(text)
|
33
|
+
string = text.dup
|
34
|
+
string.force_encoding(::Encoding::ASCII_8BIT)
|
35
|
+
string.gsub!(/["\\\x0-\x1f]/n) { |c| MAP[c] || c }
|
36
|
+
string.gsub!(/(
|
37
|
+
(?:
|
38
|
+
[\xc2-\xdf][\x80-\xbf] |
|
39
|
+
[\xe0-\xef][\x80-\xbf]{2} |
|
40
|
+
[\xf0-\xf4][\x80-\xbf]{3}
|
41
|
+
)+ |
|
42
|
+
[\x80-\xc1\xf5-\xff] # invalid
|
43
|
+
)/nx) { |c|
|
44
|
+
c.size == 1 and raise "Invalid utf8 byte: '#{c}'"
|
45
|
+
s = c.encode("utf-16be", "utf-8").unpack('H*')[0]
|
46
|
+
s.force_encoding(::Encoding::ASCII_8BIT)
|
47
|
+
s.gsub!(/.{4}/n, '\\\\u\&')
|
48
|
+
s.force_encoding(::Encoding::UTF_8)
|
49
|
+
}
|
50
|
+
string.force_encoding(::Encoding::UTF_8)
|
51
|
+
text.replace string
|
52
|
+
text
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
MAP = {
|
58
|
+
"\x0" => '\u0000',
|
59
|
+
"\x1" => '\u0001',
|
60
|
+
"\x2" => '\u0002',
|
61
|
+
"\x3" => '\u0003',
|
62
|
+
"\x4" => '\u0004',
|
63
|
+
"\x5" => '\u0005',
|
64
|
+
"\x6" => '\u0006',
|
65
|
+
"\x7" => '\u0007',
|
66
|
+
"\xb" => '\u000b',
|
67
|
+
"\xe" => '\u000e',
|
68
|
+
"\xf" => '\u000f',
|
69
|
+
"\x10" => '\u0010',
|
70
|
+
"\x11" => '\u0011',
|
71
|
+
"\x12" => '\u0012',
|
72
|
+
"\x13" => '\u0013',
|
73
|
+
"\x14" => '\u0014',
|
74
|
+
"\x15" => '\u0015',
|
75
|
+
"\x16" => '\u0016',
|
76
|
+
"\x17" => '\u0017',
|
77
|
+
"\x18" => '\u0018',
|
78
|
+
"\x19" => '\u0019',
|
79
|
+
"\x1a" => '\u001a',
|
80
|
+
"\x1b" => '\u001b',
|
81
|
+
"\x1c" => '\u001c',
|
82
|
+
"\x1d" => '\u001d',
|
83
|
+
"\x1e" => '\u001e',
|
84
|
+
"\x1f" => '\u001f',
|
85
|
+
}
|
86
|
+
|
87
|
+
EMPTY_8BIT_STRING = ''
|
88
|
+
EMPTY_8BIT_STRING.force_encoding(::Encoding::ASCII_8BIT)
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Translatomatic::Extractor
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(path)
|
5
|
+
@path = path.kind_of?(Pathname) ? path : Pathname.new(path)
|
6
|
+
@contents = @path.read
|
7
|
+
end
|
8
|
+
|
9
|
+
def extract
|
10
|
+
@contents.scan(/\"(.*?[^\\])"|'(.*?[^\\])'/).flatten.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Translatomatic
|
5
|
+
class HTTPRequest
|
6
|
+
|
7
|
+
attr_accessor :multipart_boundary
|
8
|
+
|
9
|
+
def initialize(url)
|
10
|
+
@uri = url.respond_to?(:host) ? url : URI.parse(url)
|
11
|
+
@multipart_boundary = SecureRandom.hex(16)
|
12
|
+
end
|
13
|
+
|
14
|
+
def start(options = {})
|
15
|
+
options = options.merge(use_ssl: @uri.scheme == "https")
|
16
|
+
Net::HTTP.start(@uri.host, @uri.port, options) do |http|
|
17
|
+
@http = http
|
18
|
+
yield http
|
19
|
+
end
|
20
|
+
@http = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(query = nil)
|
24
|
+
uri = @uri
|
25
|
+
if query
|
26
|
+
uri = @uri.dup
|
27
|
+
uri.query = URI.encode_www_form(query)
|
28
|
+
end
|
29
|
+
request = Net::HTTP::Get.new(uri)
|
30
|
+
request['User-Agent'] = USER_AGENT
|
31
|
+
send_request(request)
|
32
|
+
end
|
33
|
+
|
34
|
+
def post(body, options = {})
|
35
|
+
request = Net::HTTP::Post.new(@uri)
|
36
|
+
request['User-Agent'] = USER_AGENT
|
37
|
+
content_type = options[:content_type]
|
38
|
+
|
39
|
+
if options[:multipart]
|
40
|
+
content_type = "multipart/form-data; boundary=#{@multipart_boundary}"
|
41
|
+
request.body = multipartify(body)
|
42
|
+
elsif body.kind_of?(Hash)
|
43
|
+
request.set_form_data(body)
|
44
|
+
else
|
45
|
+
request.body = body
|
46
|
+
end
|
47
|
+
request.content_type = content_type if content_type
|
48
|
+
|
49
|
+
send_request(request)
|
50
|
+
end
|
51
|
+
|
52
|
+
def file(*args)
|
53
|
+
FileParam.new(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def param(*args)
|
57
|
+
Param.new(*args)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
USER_AGENT = "Translatomatic #{VERSION} (+#{URL})"
|
63
|
+
|
64
|
+
# Formats a basic string key/value pair for a multipart post
|
65
|
+
class Param
|
66
|
+
attr_accessor :key, :value
|
67
|
+
|
68
|
+
def initialize(key:, value:)
|
69
|
+
@key = key
|
70
|
+
@value = value
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s
|
74
|
+
return header(header_data) + "\r\n#{value}\r\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def header_data
|
80
|
+
name = CGI::escape(key.to_s)
|
81
|
+
{ "Content-Disposition": "form-data", name: %Q("#{name}") }
|
82
|
+
end
|
83
|
+
|
84
|
+
def header(options)
|
85
|
+
out = []
|
86
|
+
idx = 0
|
87
|
+
options.each do |key, value|
|
88
|
+
separator = idx == 0 ? ": " : "="
|
89
|
+
out << "#{key}#{separator}#{value}"
|
90
|
+
idx += 1
|
91
|
+
end
|
92
|
+
out.join("; ") + "\r\n"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Formats the contents of a file or string for a multipart post
|
97
|
+
class FileParam < Param
|
98
|
+
attr_accessor :filename, :content, :mime_type
|
99
|
+
|
100
|
+
def initialize(key:, filename:, content:, mime_type:)
|
101
|
+
@key = key
|
102
|
+
@filename = filename
|
103
|
+
@content = content
|
104
|
+
@mime_type = mime_type
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_s
|
108
|
+
return header(header_data) +
|
109
|
+
header("Content-Type": mime_type) + "\r\n#{content}\r\n"
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def header_data
|
115
|
+
super.merge({ filename: %Q("#{filename}") })
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def multipartify(parts)
|
120
|
+
string_parts = parts.collect do |p|
|
121
|
+
"--" + @multipart_boundary + "\r\n" + p.to_s
|
122
|
+
end
|
123
|
+
string_parts.join("") + "--" + @multipart_boundary + "--\r\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_request(req)
|
127
|
+
response = @http.request(req)
|
128
|
+
raise response.body unless response.kind_of? Net::HTTPSuccess
|
129
|
+
response
|
130
|
+
end
|
131
|
+
|
132
|
+
end # class
|
133
|
+
end # module
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Translatomatic::Locale
|
2
|
+
|
3
|
+
attr_reader :language
|
4
|
+
attr_reader :script
|
5
|
+
attr_reader :region
|
6
|
+
|
7
|
+
def self.parse(tag, validate = true)
|
8
|
+
locale = tag.kind_of?(Translatomatic::Locale) ? tag : new(tag)
|
9
|
+
validate && !locale.valid? ? nil : locale
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.default
|
13
|
+
DEFAULT_LOCALE
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(tag)
|
17
|
+
data = I18n::Locale::Tag::Rfc4646.tag(tag)
|
18
|
+
if data
|
19
|
+
@language = data.language
|
20
|
+
@script = data.script
|
21
|
+
@region = data.region
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
# test if lang is a valid ISO 639-1 language
|
27
|
+
VALID_LANGUAGES.include?(language)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
[language, script, region].compact.join("-")
|
32
|
+
end
|
33
|
+
|
34
|
+
def eql?(other)
|
35
|
+
other.kind_of?(Translatomatic::Locale) && other.hash == hash
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
eql?(other)
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash
|
43
|
+
[language, script, region].hash
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# list of 2 letter country codes
|
49
|
+
VALID_LANGUAGES = ::I18nData.languages.keys.collect { |i| i.downcase }.sort
|
50
|
+
DEFAULT_LOCALE = parse(I18n.default_locale)
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Translatomatic::Logger
|
2
|
+
attr_accessor :progressbar
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@logger = Logger.new(STDOUT)
|
6
|
+
@logger.level = ENV['DEBUG'] ? Logger::DEBUG : Logger::INFO
|
7
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
8
|
+
"#{msg}\n"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(name, *args)
|
13
|
+
handle_logger_method(name, args) if @logger.respond_to?(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def finish
|
17
|
+
@progressbar.finish if @progressbar
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def handle_logger_method(name, args)
|
23
|
+
@progressbar.clear if @progressbar
|
24
|
+
@logger.send(name, *args)
|
25
|
+
@progressbar.refresh(force: true) if @progressbar && !@progressbar.stopped?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -1,22 +1,21 @@
|
|
1
|
-
module Translatomatic
|
2
|
-
module Model
|
3
|
-
class Locale < ActiveRecord::Base
|
4
|
-
has_many :texts, class_name: "Translatomatic::Model::Text"
|
5
|
-
validates_presence_of :language
|
6
|
-
validates_uniqueness_of :language, scope: [:script, :region]
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
1
|
+
module Translatomatic
|
2
|
+
module Model
|
3
|
+
class Locale < ActiveRecord::Base
|
4
|
+
has_many :texts, class_name: "Translatomatic::Model::Text"
|
5
|
+
validates_presence_of :language
|
6
|
+
validates_uniqueness_of :language, scope: [:script, :region]
|
7
|
+
|
8
|
+
# create a locale record from an I18n::Locale::Tag object or string
|
9
|
+
def self.from_tag(tag)
|
10
|
+
tag = Translatomatic::Locale.parse(tag)
|
11
|
+
find_or_create_by!({
|
12
|
+
language: tag.language, script: tag.script, region: tag.region
|
13
|
+
})
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
[language, script, region].compact.join("-")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,13 +1,17 @@
|
|
1
|
-
module Translatomatic
|
2
|
-
module Model
|
3
|
-
class Text < ActiveRecord::Base
|
4
|
-
belongs_to :locale, class_name: "Translatomatic::Model::Locale"
|
5
|
-
belongs_to :from_text, class_name: "Translatomatic::Model::Text"
|
6
|
-
has_many :translations, class_name: "Translatomatic::Model::Text",
|
7
|
-
foreign_key: :from_text_id, dependent: :delete_all
|
8
|
-
|
9
|
-
validates_presence_of :value
|
10
|
-
validates_presence_of :locale
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
module Translatomatic
|
2
|
+
module Model
|
3
|
+
class Text < ActiveRecord::Base
|
4
|
+
belongs_to :locale, class_name: "Translatomatic::Model::Locale"
|
5
|
+
belongs_to :from_text, class_name: "Translatomatic::Model::Text"
|
6
|
+
has_many :translations, class_name: "Translatomatic::Model::Text",
|
7
|
+
foreign_key: :from_text_id, dependent: :delete_all
|
8
|
+
|
9
|
+
validates_presence_of :value
|
10
|
+
validates_presence_of :locale
|
11
|
+
|
12
|
+
def is_translated?
|
13
|
+
!from_text_id.nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/translatomatic/model.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
module Translatomatic::Model; end
|
2
|
-
|
3
|
-
require 'translatomatic/model/locale'
|
4
|
-
require 'translatomatic/model/text'
|
1
|
+
module Translatomatic::Model; end
|
2
|
+
|
3
|
+
require 'translatomatic/model/locale'
|
4
|
+
require 'translatomatic/model/text'
|
@@ -1,24 +1,24 @@
|
|
1
|
-
module Translatomatic
|
2
|
-
class Option
|
3
|
-
attr_reader :name, :required, :use_env, :description
|
4
|
-
|
5
|
-
def initialize(data = {})
|
6
|
-
@name = data[:name]
|
7
|
-
@required = data[:required]
|
8
|
-
@use_env = data[:use_env]
|
9
|
-
@description = data[:desc]
|
10
|
-
@data = data
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_hash
|
14
|
-
@data
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module DefineOptions
|
19
|
-
private
|
20
|
-
def define_options(*options)
|
21
|
-
@options = options.collect { |i| Translatomatic::Option.new(i) }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
1
|
+
module Translatomatic
|
2
|
+
class Option
|
3
|
+
attr_reader :name, :required, :use_env, :description
|
4
|
+
|
5
|
+
def initialize(data = {})
|
6
|
+
@name = data[:name]
|
7
|
+
@required = data[:required]
|
8
|
+
@use_env = data[:use_env]
|
9
|
+
@description = data[:desc]
|
10
|
+
@data = data
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
@data
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module DefineOptions
|
19
|
+
private
|
20
|
+
def define_options(*options)
|
21
|
+
@options = options.collect { |i| Translatomatic::Option.new(i) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# implements Converter listener
|
2
|
+
class Translatomatic::ProgressUpdater
|
3
|
+
def initialize(progressbar)
|
4
|
+
@progressbar = progressbar
|
5
|
+
end
|
6
|
+
|
7
|
+
def translated_texts(texts)
|
8
|
+
@progressbar.progress += texts.length
|
9
|
+
end
|
10
|
+
|
11
|
+
def untranslated_texts(texts)
|
12
|
+
@progressbar.total -= texts.length
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|