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.
- checksums.yaml +5 -5
- data/.gitattributes +20 -20
- data/.gitignore +19 -15
- data/.rspec +3 -3
- data/.rubocop.yml +28 -0
- data/.translatomatic/config.yml +4 -0
- data/.travis.yml +4 -6
- data/.yardopts +9 -9
- data/Gemfile +8 -4
- data/Guardfile +4 -5
- data/README.de.md +55 -50
- data/README.en.md +177 -0
- data/README.es.md +53 -48
- data/README.fr.md +53 -48
- data/README.it.md +54 -49
- data/README.ja.md +63 -58
- data/README.ko.md +59 -54
- data/README.md +17 -13
- data/README.ms.md +50 -45
- data/README.pt.md +54 -49
- data/README.ru.md +57 -52
- data/README.sv.md +51 -46
- data/README.zh.md +60 -55
- data/Rakefile +3 -3
- data/TODO.txt +6 -0
- data/bin/console +3 -3
- data/bin/translatomatic +4 -2
- data/config/i18n-tasks.yml +130 -0
- data/config/locales/translatomatic/de.yml +141 -99
- data/config/locales/translatomatic/en.yml +129 -89
- data/config/locales/translatomatic/es.yml +136 -99
- data/config/locales/translatomatic/fr.yml +139 -100
- data/config/locales/translatomatic/it.yml +135 -97
- data/config/locales/translatomatic/ja.yml +137 -98
- data/config/locales/translatomatic/ko.yml +138 -98
- data/config/locales/translatomatic/ms.yml +138 -100
- data/config/locales/translatomatic/pt.yml +137 -101
- data/config/locales/translatomatic/ru.yml +136 -98
- data/config/locales/translatomatic/sv.yml +134 -96
- data/config/locales/translatomatic/zh.yml +136 -97
- data/db/migrate/201712170000_initial.rb +2 -3
- data/lib/translatomatic.rb +40 -25
- data/lib/translatomatic/cli.rb +5 -1
- data/lib/translatomatic/cli/base.rb +61 -58
- data/lib/translatomatic/cli/common_options.rb +14 -11
- data/lib/translatomatic/cli/config.rb +96 -91
- data/lib/translatomatic/cli/database.rb +85 -23
- data/lib/translatomatic/cli/main.rb +158 -104
- data/lib/translatomatic/cli/thor.rb +29 -0
- data/lib/translatomatic/cli/translate.rb +134 -157
- data/lib/translatomatic/config.rb +10 -301
- data/lib/translatomatic/config/display.rb +78 -0
- data/lib/translatomatic/config/files.rb +60 -0
- data/lib/translatomatic/config/location_settings.rb +133 -0
- data/lib/translatomatic/config/options.rb +68 -0
- data/lib/translatomatic/config/selector.rb +127 -0
- data/lib/translatomatic/config/settings.rb +148 -0
- data/lib/translatomatic/converter.rb +40 -28
- data/lib/translatomatic/database.rb +127 -110
- data/lib/translatomatic/define_options.rb +4 -5
- data/lib/translatomatic/escaped_unicode.rb +86 -76
- data/lib/translatomatic/extractor.rb +5 -2
- data/lib/translatomatic/extractor/base.rb +12 -12
- data/lib/translatomatic/extractor/ruby.rb +7 -6
- data/lib/translatomatic/file_translator.rb +101 -244
- data/lib/translatomatic/flattenation.rb +39 -0
- data/lib/translatomatic/http.rb +13 -0
- data/lib/translatomatic/http/client.rb +144 -0
- data/lib/translatomatic/http/exception.rb +43 -0
- data/lib/translatomatic/http/file_param.rb +27 -0
- data/lib/translatomatic/http/param.rb +37 -0
- data/lib/translatomatic/http/request.rb +91 -0
- data/lib/translatomatic/i18n.rb +43 -0
- data/lib/translatomatic/locale.rb +71 -59
- data/lib/translatomatic/logger.rb +43 -28
- data/lib/translatomatic/metadata.rb +58 -0
- data/lib/translatomatic/model.rb +4 -2
- data/lib/translatomatic/model/locale.rb +5 -5
- data/lib/translatomatic/model/text.rb +5 -5
- data/lib/translatomatic/option.rb +57 -34
- data/lib/translatomatic/path_utils.rb +126 -0
- data/lib/translatomatic/progress_updater.rb +13 -16
- data/lib/translatomatic/provider.rb +101 -0
- data/lib/translatomatic/provider/base.rb +136 -0
- data/lib/translatomatic/provider/frengly.rb +55 -0
- data/lib/translatomatic/provider/google.rb +78 -0
- data/lib/translatomatic/provider/google_web.rb +50 -0
- data/lib/translatomatic/provider/microsoft.rb +144 -0
- data/lib/translatomatic/provider/my_memory.rb +75 -0
- data/lib/translatomatic/provider/yandex.rb +61 -0
- data/lib/translatomatic/resource_file.rb +59 -53
- data/lib/translatomatic/resource_file/base.rb +171 -237
- data/lib/translatomatic/resource_file/csv.rb +176 -24
- data/lib/translatomatic/resource_file/html.rb +21 -42
- data/lib/translatomatic/resource_file/key_value_support.rb +117 -0
- data/lib/translatomatic/resource_file/markdown.rb +36 -38
- data/lib/translatomatic/resource_file/plist.rb +121 -126
- data/lib/translatomatic/resource_file/po.rb +104 -82
- data/lib/translatomatic/resource_file/properties.rb +48 -77
- data/lib/translatomatic/resource_file/properties.treetop +87 -0
- data/lib/translatomatic/resource_file/resw.rb +56 -41
- data/lib/translatomatic/resource_file/subtitle.rb +86 -54
- data/lib/translatomatic/resource_file/text.rb +18 -18
- data/lib/translatomatic/resource_file/xcode_strings.rb +32 -63
- data/lib/translatomatic/resource_file/xcode_strings.treetop +85 -0
- data/lib/translatomatic/resource_file/xml.rb +94 -81
- data/lib/translatomatic/resource_file/yaml.rb +54 -68
- data/lib/translatomatic/retry_executor.rb +37 -0
- data/lib/translatomatic/slurp.rb +32 -0
- data/lib/translatomatic/string_batcher.rb +50 -0
- data/lib/translatomatic/string_escaping.rb +61 -0
- data/lib/translatomatic/text.rb +263 -0
- data/lib/translatomatic/text_collection.rb +66 -0
- data/lib/translatomatic/tmx.rb +5 -3
- data/lib/translatomatic/tmx/document.rb +107 -82
- data/lib/translatomatic/tmx/translation_unit.rb +19 -18
- data/lib/translatomatic/translation.rb +8 -28
- data/lib/translatomatic/translation/collection.rb +199 -0
- data/lib/translatomatic/translation/fetcher.rb +123 -0
- data/lib/translatomatic/translation/munging.rb +112 -0
- data/lib/translatomatic/translation/result.rb +50 -0
- data/lib/translatomatic/translation/sharer.rb +32 -0
- data/lib/translatomatic/translation/stats.rb +44 -0
- data/lib/translatomatic/translator.rb +91 -88
- data/lib/translatomatic/type_cast.rb +63 -0
- data/lib/translatomatic/util.rb +37 -33
- data/lib/translatomatic/version.rb +2 -2
- data/translatomatic.gemspec +57 -46
- metadata +136 -59
- data/lib/translatomatic/http_request.rb +0 -162
- data/lib/translatomatic/string.rb +0 -188
- data/lib/translatomatic/translation_result.rb +0 -86
- data/lib/translatomatic/translation_stats.rb +0 -31
- data/lib/translatomatic/translator/base.rb +0 -128
- data/lib/translatomatic/translator/frengly.rb +0 -62
- data/lib/translatomatic/translator/google.rb +0 -37
- data/lib/translatomatic/translator/microsoft.rb +0 -41
- data/lib/translatomatic/translator/my_memory.rb +0 -68
- data/lib/translatomatic/translator/yandex.rb +0 -56
@@ -1,36 +1,48 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Translatomatic
|
2
|
+
# Converts files from one format to another
|
3
|
+
class Converter
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = options
|
6
|
+
end
|
3
7
|
|
4
|
-
|
5
|
-
@
|
6
|
-
|
8
|
+
# Convert a resource file from one format to another.
|
9
|
+
# @param source [String] Path to source file. File must exist
|
10
|
+
# @param target [String] Path to target file. File will be created
|
11
|
+
# or overwritten if it already exists.
|
12
|
+
# @return [Translatomatic::ResourceFile] The converted file.
|
13
|
+
def convert(source, target)
|
14
|
+
source_file = load_file(source)
|
15
|
+
target_file = load_file(target)
|
16
|
+
raise t('file.not_found', file: source) unless source_file.path.file?
|
7
17
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
raise t("file.not_found", file: source.to_s) unless source_path.file?
|
17
|
-
raise t("file.directory", file: target.to_s) if target_path.directory?
|
18
|
+
if source_file.type == target_file.type
|
19
|
+
# if same file type, modify source.
|
20
|
+
# this retains internal structure
|
21
|
+
target_file = source_file
|
22
|
+
else
|
23
|
+
# different file type, copy properties from source file to target
|
24
|
+
target_file.properties = source_file.properties
|
25
|
+
end
|
18
26
|
|
19
|
-
|
20
|
-
|
27
|
+
target_file.save(Pathname.new(target), @options)
|
28
|
+
target_file
|
29
|
+
end
|
21
30
|
|
22
|
-
|
23
|
-
target_file.properties = source_file.properties
|
24
|
-
target_file.save(target_path, @options)
|
25
|
-
target_file
|
26
|
-
end
|
31
|
+
private
|
27
32
|
|
28
|
-
|
33
|
+
include Translatomatic::Util
|
29
34
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
file
|
34
|
-
end
|
35
|
+
def load_file(path)
|
36
|
+
path = Pathname.new(path.to_s)
|
37
|
+
raise t('file.directory', file: path) if path.directory?
|
35
38
|
|
39
|
+
file = if path.exist?
|
40
|
+
Translatomatic::ResourceFile.load(path)
|
41
|
+
else
|
42
|
+
Translatomatic::ResourceFile.create(path)
|
43
|
+
end
|
44
|
+
raise t('file.unsupported', file: path) unless file
|
45
|
+
file
|
46
|
+
end
|
47
|
+
end
|
36
48
|
end
|
@@ -1,143 +1,160 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module Translatomatic
|
4
|
+
# Database functions
|
5
|
+
class Database
|
6
|
+
class << self
|
7
|
+
# @param options [Hash<Symbol,Object>] Database options
|
8
|
+
# @return [boolean] True if we can connect to the database
|
9
|
+
def enabled?(options = {})
|
10
|
+
new(options).connect
|
11
|
+
end
|
11
12
|
end
|
12
|
-
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
ActiveRecord::Tasks::DatabaseTasks.root = DB_PATH
|
26
|
-
ActiveRecord::Tasks::DatabaseTasks.database_configuration = @db_config
|
27
|
-
create unless exists?
|
28
|
-
migrate
|
29
|
-
end
|
14
|
+
def initialize(options = {})
|
15
|
+
@env = options[:database_env] || DEFAULT_ENV
|
16
|
+
@db_config = database_config(@env, options)
|
17
|
+
env_config = @db_config
|
18
|
+
unless env_config[@env]
|
19
|
+
raise t('database.no_environment', env: @env, file: db_config_path)
|
20
|
+
end
|
21
|
+
@env_config = env_config[@env] || {}
|
22
|
+
init_active_record
|
23
|
+
create unless exists?
|
24
|
+
end
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
begin
|
26
|
+
# Connect to the database
|
27
|
+
# @return [boolean] True if the connection was established
|
28
|
+
def connect
|
35
29
|
ActiveRecord::Base.establish_connection(@env_config)
|
30
|
+
migrate
|
36
31
|
true
|
37
32
|
rescue LoadError
|
38
33
|
false
|
39
34
|
end
|
40
|
-
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
# Disconnect from the database
|
37
|
+
# @return [void]
|
38
|
+
def disconnect
|
39
|
+
ActiveRecord::Base.remove_connection
|
40
|
+
end
|
47
41
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
42
|
+
# Test if the database exists
|
43
|
+
# @return [Boolean] true if the database exists
|
44
|
+
def exists?
|
45
|
+
begin
|
46
|
+
return true if sqlite_database_exists?
|
47
|
+
return false unless connect
|
48
|
+
ActiveRecord::Base.connection.tables
|
49
|
+
rescue StandardError
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
true
|
57
53
|
end
|
58
|
-
true
|
59
|
-
end
|
60
54
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
55
|
+
# Run outstanding migrations against the database
|
56
|
+
# @return [void]
|
57
|
+
def migrate
|
58
|
+
return if @migrated
|
59
|
+
ActiveRecord::Migrator.migrate(MIGRATIONS_PATH)
|
60
|
+
ActiveRecord::Base.clear_cache!
|
61
|
+
log.debug t('database.migrated')
|
62
|
+
@migrated = true
|
63
|
+
end
|
69
64
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
begin
|
65
|
+
# Create the database
|
66
|
+
# @return [boolean] True if the database was created
|
67
|
+
def create
|
74
68
|
ActiveRecord::Tasks::DatabaseTasks.create(@env_config)
|
75
|
-
log.debug t(
|
69
|
+
log.debug t('database.created')
|
76
70
|
true
|
77
71
|
rescue LoadError => e
|
78
|
-
log.debug t(
|
72
|
+
log.debug t('database.could_not_create')
|
79
73
|
log.error e.message
|
80
74
|
false
|
81
75
|
end
|
82
|
-
end
|
83
76
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
77
|
+
# Drop the database
|
78
|
+
# @return [void]
|
79
|
+
def drop
|
80
|
+
disconnect
|
81
|
+
ActiveRecord::Tasks::DatabaseTasks.drop(@env_config)
|
82
|
+
log.debug t('database.deleted')
|
83
|
+
end
|
91
84
|
|
92
|
-
|
85
|
+
# Shortcut to text model class
|
86
|
+
# @return [Class] Translatomatic::Model::Text
|
87
|
+
def text
|
88
|
+
Translatomatic::Model::Text
|
89
|
+
end
|
93
90
|
|
94
|
-
|
95
|
-
|
91
|
+
# Shortcut to locale model class
|
92
|
+
# @return [Class] Translatomatic::Model::Locale
|
93
|
+
def locale
|
94
|
+
Translatomatic::Model::Locale
|
95
|
+
end
|
96
96
|
|
97
|
-
|
98
|
-
@env_config['adapter'] == 'sqlite3' && File.exist?(@env_config['database'])
|
99
|
-
end
|
97
|
+
private
|
100
98
|
|
101
|
-
|
102
|
-
|
103
|
-
|
99
|
+
include Translatomatic::Util
|
100
|
+
include Translatomatic::DefineOptions
|
101
|
+
|
102
|
+
class << self
|
103
|
+
private
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
DEFAULT_CONFIG = File.exist?(CUSTOM_CONFIG) ? CUSTOM_CONFIG : INTERNAL_CONFIG
|
109
|
-
MIGRATIONS_PATH = File.join(DB_PATH, "migrate")
|
110
|
-
GEM_ROOT = join_path(File.dirname(__FILE__), "..", "..")
|
111
|
-
DEFAULT_ENV = "production"
|
112
|
-
|
113
|
-
define_options(
|
114
|
-
{ name: :database_config, desc: t("database.config_file"),
|
115
|
-
default: DEFAULT_CONFIG },
|
116
|
-
{ name: :database_env, desc: t("database.env"),
|
117
|
-
default: DEFAULT_ENV })
|
118
|
-
|
119
|
-
# return path to database config
|
120
|
-
def database_config_path(options)
|
121
|
-
if options[:database_env] == "test"
|
122
|
-
INTERNAL_CONFIG # rspec
|
123
|
-
elsif options[:database_config]
|
124
|
-
return options[:database_config]
|
125
|
-
else
|
126
|
-
DEFAULT_CONFIG
|
105
|
+
def join_path(*parts)
|
106
|
+
File.realpath(File.join(*parts))
|
107
|
+
end
|
127
108
|
end
|
128
|
-
end
|
129
109
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
110
|
+
def init_active_record
|
111
|
+
ActiveRecord::Base.configurations = @db_config
|
112
|
+
ActiveRecord::Tasks::DatabaseTasks.env = @env
|
113
|
+
ActiveRecord::Tasks::DatabaseTasks.db_dir = DB_PATH
|
114
|
+
ActiveRecord::Tasks::DatabaseTasks.root = DB_PATH
|
115
|
+
ActiveRecord::Tasks::DatabaseTasks.database_configuration = @db_config
|
134
116
|
end
|
135
117
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
118
|
+
def sqlite_database_exists?
|
119
|
+
@env_config['adapter'] == 'sqlite3' &&
|
120
|
+
File.exist?(@env_config['database'])
|
121
|
+
end
|
122
|
+
|
123
|
+
DB_PATH = join_path(File.dirname(__FILE__), '..', '..', 'db')
|
124
|
+
INTERNAL_CONF = File.join(DB_PATH, 'database.yml')
|
125
|
+
CUSTOM_CONF = File.join(Dir.home, '.translatomatic', 'database.yml')
|
126
|
+
DEFAULT_CONF = File.exist?(CUSTOM_CONF) ? CUSTOM_CONF : INTERNAL_CONF
|
127
|
+
MIGRATIONS_PATH = File.join(DB_PATH, 'migrate')
|
128
|
+
GEM_ROOT = join_path(File.dirname(__FILE__), '..', '..')
|
129
|
+
DEFAULT_ENV = 'production'.freeze
|
130
|
+
|
131
|
+
define_option :database_config, desc: t('database.config_file'),
|
132
|
+
default: DEFAULT_CONF, type: :path
|
133
|
+
define_option :database_env, desc: t('database.env'),
|
134
|
+
default: DEFAULT_ENV
|
135
|
+
|
136
|
+
# return path to database config
|
137
|
+
def database_config_path(options)
|
138
|
+
if options[:database_env] == 'test'
|
139
|
+
INTERNAL_CONF # used for rspec
|
140
|
+
elsif options[:database_config]
|
141
|
+
options[:database_config]
|
142
|
+
else
|
143
|
+
DEFAULT_CONF
|
144
|
+
end
|
145
|
+
end
|
142
146
|
|
147
|
+
# return database config as a hash
|
148
|
+
def database_config(env, options)
|
149
|
+
if options[:database_config].is_a?(Hash)
|
150
|
+
return { env => options[:database_config] }
|
151
|
+
end
|
152
|
+
|
153
|
+
db_config_path = database_config_path(options)
|
154
|
+
dbconfig = File.read(db_config_path)
|
155
|
+
dbconfig.gsub!(/\$HOME/, Dir.home)
|
156
|
+
dbconfig.gsub!(/\$GEM_ROOT/, GEM_ROOT)
|
157
|
+
YAML.safe_load(dbconfig) || {}
|
158
|
+
end
|
159
|
+
end
|
143
160
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
module Translatomatic
|
2
2
|
# @!visibility private
|
3
3
|
module DefineOptions
|
4
|
-
|
5
4
|
# @!visibility private
|
6
5
|
module ClassMethods
|
7
6
|
attr_reader :options
|
8
7
|
|
9
8
|
private
|
10
9
|
|
11
|
-
def
|
12
|
-
@options
|
10
|
+
def define_option(name, attributes = {})
|
11
|
+
@options ||= []
|
12
|
+
@options << Translatomatic::Option.new(attributes.merge(name: name))
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
private
|
17
|
-
|
16
|
+
# @!visibility private
|
18
17
|
def self.included(klass)
|
19
18
|
klass.extend(ClassMethods)
|
20
19
|
end
|
@@ -1,90 +1,100 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# @see https://github.com/
|
1
|
+
module Translatomatic
|
2
|
+
# Class to encode and decode unicode chars.
|
3
|
+
# This code is highly influenced by Florian Frank's JSON gem
|
4
|
+
# @see https://github.com/jnbt/java-properties
|
5
|
+
# @see https://github.com/flori/json/
|
6
|
+
class EscapedUnicode
|
7
|
+
class << self
|
8
|
+
# Decodes all unicode chars from escape sequences
|
9
|
+
# @param text [String]
|
10
|
+
# @return [String] The encoded text
|
11
|
+
def unescape(text)
|
12
|
+
string = text.gsub(/(?:\\[uU](?:[A-Fa-f\d]{4}))+/) do |c|
|
13
|
+
unescape_char(c)
|
14
|
+
end
|
15
|
+
string.force_encoding(::Encoding::UTF_8)
|
16
|
+
string
|
17
|
+
end
|
18
|
+
|
19
|
+
# Decodes all unicode chars into escape sequences
|
20
|
+
# @param text [String]
|
21
|
+
# @return [String] The decoded text
|
22
|
+
def escape(text)
|
23
|
+
string = text.dup
|
24
|
+
string.force_encoding(::Encoding::ASCII_8BIT)
|
25
|
+
string.gsub!(/["\\\x0-\x1f]/n) { |c| MAP[c] || c }
|
26
|
+
string.gsub!(ESCAPE_REGEX) { |c| escape_char(c) }
|
27
|
+
string.force_encoding(::Encoding::UTF_8)
|
28
|
+
string
|
29
|
+
end
|
5
30
|
|
6
|
-
|
31
|
+
private
|
7
32
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
bytes
|
19
|
-
i += 1
|
33
|
+
def unescape_char(c)
|
34
|
+
c.downcase!
|
35
|
+
bytes = EMPTY_8BIT_STRING.dup
|
36
|
+
i = 0
|
37
|
+
while c[i] == '\\' && c[i + 1] == 'u'
|
38
|
+
(1..2).each do |j|
|
39
|
+
bytes << c[i + j * 2, 2].to_i(16)
|
40
|
+
end
|
41
|
+
i += 6
|
42
|
+
end
|
43
|
+
bytes.encode('utf-8', 'utf-16be')
|
20
44
|
end
|
21
|
-
bytes.encode("utf-8", "utf-16be")
|
22
|
-
end
|
23
|
-
string.force_encoding(::Encoding::UTF_8)
|
24
45
|
|
25
|
-
|
26
|
-
|
27
|
-
|
46
|
+
def escape_char(c)
|
47
|
+
(c.size == 1) && raise(t('unicode.invalid_byte', byte: c))
|
48
|
+
s = c.encode('utf-16be', 'utf-8').unpack('H*')[0]
|
49
|
+
s.force_encoding(::Encoding::ASCII_8BIT)
|
50
|
+
s.gsub!(/.{4}/n, '\\\\u\&')
|
51
|
+
s.force_encoding(::Encoding::UTF_8)
|
52
|
+
end
|
53
|
+
end
|
28
54
|
|
29
|
-
|
30
|
-
|
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!(/(
|
55
|
+
# @private
|
56
|
+
ESCAPE_REGEX = /(
|
37
57
|
(?:
|
38
58
|
[\xc2-\xdf][\x80-\xbf] |
|
39
59
|
[\xe0-\xef][\x80-\xbf]{2} |
|
40
60
|
[\xf0-\xf4][\x80-\xbf]{3}
|
41
61
|
)+ |
|
42
62
|
[\x80-\xc1\xf5-\xff] # invalid
|
43
|
-
)/nx
|
44
|
-
c.size == 1 and raise t("unicode.invalid_byte", 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
|
63
|
+
)/nx
|
56
64
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
EMPTY_8BIT_STRING.force_encoding(::Encoding::ASCII_8BIT)
|
65
|
+
# @private
|
66
|
+
MAP = {
|
67
|
+
"\x0" => '\u0000',
|
68
|
+
"\x1" => '\u0001',
|
69
|
+
"\x2" => '\u0002',
|
70
|
+
"\x3" => '\u0003',
|
71
|
+
"\x4" => '\u0004',
|
72
|
+
"\x5" => '\u0005',
|
73
|
+
"\x6" => '\u0006',
|
74
|
+
"\x7" => '\u0007',
|
75
|
+
"\xb" => '\u000b',
|
76
|
+
"\xe" => '\u000e',
|
77
|
+
"\xf" => '\u000f',
|
78
|
+
"\x10" => '\u0010',
|
79
|
+
"\x11" => '\u0011',
|
80
|
+
"\x12" => '\u0012',
|
81
|
+
"\x13" => '\u0013',
|
82
|
+
"\x14" => '\u0014',
|
83
|
+
"\x15" => '\u0015',
|
84
|
+
"\x16" => '\u0016',
|
85
|
+
"\x17" => '\u0017',
|
86
|
+
"\x18" => '\u0018',
|
87
|
+
"\x19" => '\u0019',
|
88
|
+
"\x1a" => '\u001a',
|
89
|
+
"\x1b" => '\u001b',
|
90
|
+
"\x1c" => '\u001c',
|
91
|
+
"\x1d" => '\u001d',
|
92
|
+
"\x1e" => '\u001e',
|
93
|
+
"\x1f" => '\u001f'
|
94
|
+
}.freeze
|
95
|
+
private_constant :MAP
|
89
96
|
|
97
|
+
# @private
|
98
|
+
EMPTY_8BIT_STRING = ''.force_encoding(::Encoding::ASCII_8BIT).freeze
|
99
|
+
end
|
90
100
|
end
|