i18nize 0.4.4 → 0.5
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 +4 -4
- data/lib/i18nize/comparer.rb +12 -5
- data/lib/i18nize/inserter.rb +43 -18
- data/lib/i18nize/translator.rb +22 -21
- data/lib/i18nize/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 592b298cbac45e06745596fe3b02025797d39f572214e2dd345ef6f9d39abe33
|
|
4
|
+
data.tar.gz: a661e6474225964f79d6d80a38c23f91d531e6c6c58b5c52e3b7b11de211d652
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 210f54125ca483b27318abcdcb0647d947a83639d11e62ce4ca34506974d3cb0f65d2357954b81106eafd28874c64b1e774338548f48f3898d9e2fac84a1b85c
|
|
7
|
+
data.tar.gz: 21ed727606ee36a27b10ab94d7625f4b5deda616b3e4afd2fb745db7b69945b3a5688f0d6ba75d407d7fc4a82ee89eda49475c659f413c75bf03321594550ef0
|
data/lib/i18nize/comparer.rb
CHANGED
|
@@ -14,14 +14,21 @@ module I18nize
|
|
|
14
14
|
from_data.each do |from_path, from_keys|
|
|
15
15
|
dirname = File.dirname(from_path)
|
|
16
16
|
filename = File.basename(from_path)
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
locale_re = /(^|[._])#{Regexp.escape(from_locale)}\.(ya?ml)$/
|
|
19
|
+
expected_to_filename = filename.sub(locale_re) { "#{Regexp.last_match(1)}#{to_locale}.#{Regexp.last_match(2)}" }
|
|
20
|
+
|
|
21
|
+
to_path = if dirname == "." || dirname.empty?
|
|
22
|
+
expected_to_filename
|
|
23
|
+
else
|
|
24
|
+
File.join(dirname, expected_to_filename)
|
|
25
|
+
end
|
|
19
26
|
|
|
20
27
|
to_keys = to_data[to_path] || {}
|
|
21
28
|
|
|
22
|
-
missing = from_keys.
|
|
23
|
-
to_key = key.sub(/^#{from_locale}\./, "#{to_locale}.")
|
|
24
|
-
|
|
29
|
+
missing = from_keys.reject do |key, _|
|
|
30
|
+
to_key = key.sub(/^#{Regexp.escape(from_locale)}\./, "#{to_locale}.")
|
|
31
|
+
to_keys.key?(to_key)
|
|
25
32
|
end
|
|
26
33
|
|
|
27
34
|
result[from_path] = missing unless missing.empty?
|
data/lib/i18nize/inserter.rb
CHANGED
|
@@ -6,32 +6,32 @@ require_relative "comparer"
|
|
|
6
6
|
|
|
7
7
|
module I18nize
|
|
8
8
|
class Inserter
|
|
9
|
+
CONFLICT_POLICY = :overwrite # :overwrite | :skip
|
|
10
|
+
|
|
9
11
|
def self.insert_missing(from_locale: "en", to_locale:, base_path: "config/locales", translator: nil)
|
|
10
12
|
missing_data = Comparer.missing_translations(from_locale: from_locale, to_locale: to_locale)
|
|
11
13
|
|
|
12
14
|
if translator
|
|
13
15
|
char_count = missing_data.character_count
|
|
14
16
|
puts "\n\e[33m[i18nize] Estimated character count: #{char_count}\e[0m"
|
|
15
|
-
|
|
16
|
-
if char_count > 500_000
|
|
17
|
-
puts "\e[31m[i18nize] Warning: DeepL Free has a 500,000 character monthly limit.\e[0m"
|
|
18
|
-
end
|
|
19
|
-
|
|
17
|
+
puts "\e[31m[i18nize] Warning: DeepL Free has a 500,000 character monthly limit.\e[0m" if char_count > 500_000
|
|
20
18
|
print "\e[36mProceed with translation? [y/N]: \e[0m"
|
|
21
|
-
answer = $stdin.gets.strip.downcase
|
|
22
|
-
|
|
19
|
+
answer = $stdin.gets.to_s.strip.downcase
|
|
23
20
|
unless answer == "y"
|
|
24
21
|
puts "\e[90m[i18nize] Aborted by user.\e[0m"
|
|
25
22
|
return
|
|
26
23
|
end
|
|
27
24
|
end
|
|
28
25
|
|
|
26
|
+
overwrites = []
|
|
27
|
+
|
|
29
28
|
missing_data.data.each do |from_rel_path, translations|
|
|
30
29
|
dirname = File.dirname(from_rel_path)
|
|
31
30
|
filename = File.basename(from_rel_path)
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
locale_re = /(^|[._])#{Regexp.escape(from_locale)}\.(ya?ml)$/
|
|
33
|
+
new_filename = filename.sub(locale_re) { "#{Regexp.last_match(1)}#{to_locale}.#{Regexp.last_match(2)}" }
|
|
34
|
+
to_rel_path = dirname == "." || dirname.empty? ? new_filename : File.join(dirname, new_filename)
|
|
35
35
|
to_full_path = File.join(base_path, to_rel_path)
|
|
36
36
|
|
|
37
37
|
existing = File.exist?(to_full_path) ? YAML.load_file(to_full_path) : {}
|
|
@@ -39,16 +39,16 @@ module I18nize
|
|
|
39
39
|
|
|
40
40
|
translation_map =
|
|
41
41
|
if translator
|
|
42
|
-
|
|
43
|
-
translated_values = translator.translate_texts(
|
|
44
|
-
translations.keys.zip(translated_values
|
|
42
|
+
src_values = translations.values
|
|
43
|
+
translated_values = translator.translate_texts(src_values) # => pole!
|
|
44
|
+
translations.keys.zip(translated_values).to_h
|
|
45
45
|
else
|
|
46
46
|
translations
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
translation_map.each do |
|
|
50
|
-
path =
|
|
51
|
-
insert_nested(existing[to_locale], path, value)
|
|
49
|
+
translation_map.each do |full_key, value|
|
|
50
|
+
path = full_key.sub(/^#{Regexp.escape(from_locale)}\./, "").split(".")
|
|
51
|
+
insert_nested(existing[to_locale], path, value, overwrites, to_rel_path, to_locale, CONFLICT_POLICY)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
FileUtils.mkdir_p(File.dirname(to_full_path))
|
|
@@ -56,16 +56,41 @@ module I18nize
|
|
|
56
56
|
|
|
57
57
|
puts "\e[32m[i18nize] Inserted #{translation_map.size} keys into #{to_full_path}\e[0m"
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
if overwrites.any?
|
|
61
|
+
puts "\n\e[33m[i18nize] Overwrote #{overwrites.size} scalar node(s) to create nested structure:\e[0m"
|
|
62
|
+
overwrites.each do |c|
|
|
63
|
+
puts " \e[33m- #{c[:file]}: #{c[:locale]}.#{c[:path].join('.')}\e[0m (was: #{c[:existing_class]})"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
59
66
|
end
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
# conflict_policy: :overwrite (replace scalar with {}), :skip (leave as is)
|
|
69
|
+
def self.insert_nested(base, keys, value, overwrites, file, locale, conflict_policy)
|
|
62
70
|
key = keys.shift
|
|
63
|
-
base[key] ||= {}
|
|
64
71
|
|
|
65
72
|
if keys.empty?
|
|
66
73
|
base[key] = value
|
|
74
|
+
return true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
cur = base[key]
|
|
78
|
+
|
|
79
|
+
case cur
|
|
80
|
+
when nil
|
|
81
|
+
base[key] = {}
|
|
82
|
+
insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
|
|
83
|
+
when Hash
|
|
84
|
+
insert_nested(cur, keys, value, overwrites, file, locale, conflict_policy)
|
|
67
85
|
else
|
|
68
|
-
|
|
86
|
+
if conflict_policy == :overwrite
|
|
87
|
+
overwrites << { file: file, locale: locale, path: [key, *keys], existing_class: cur.class.to_s }
|
|
88
|
+
base[key] = {}
|
|
89
|
+
insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
|
|
90
|
+
else
|
|
91
|
+
# :skip
|
|
92
|
+
false
|
|
93
|
+
end
|
|
69
94
|
end
|
|
70
95
|
end
|
|
71
96
|
end
|
data/lib/i18nize/translator.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
2
|
require "net/http"
|
|
4
3
|
require "uri"
|
|
5
4
|
require "json"
|
|
@@ -7,42 +6,44 @@ require "json"
|
|
|
7
6
|
module I18nize
|
|
8
7
|
class Translator
|
|
9
8
|
ENDPOINT = ENV.fetch("DEEPL_ENDPOINT", "https://api-free.deepl.com/v2/translate")
|
|
9
|
+
PLACEHOLDER_RE = /%{\s*[^}]+\s*}/
|
|
10
10
|
|
|
11
11
|
def initialize(auth_key:, from_lang: "EN", to_lang:)
|
|
12
|
-
@auth_key
|
|
12
|
+
@auth_key = auth_key
|
|
13
13
|
@from_lang = from_lang
|
|
14
|
-
@to_lang
|
|
14
|
+
@to_lang = to_lang
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def translate_texts(texts)
|
|
18
|
-
return
|
|
18
|
+
return [] if texts.empty?
|
|
19
|
+
|
|
20
|
+
placeholders = []
|
|
21
|
+
protected = texts.map do |t|
|
|
22
|
+
t.to_s.gsub(PLACEHOLDER_RE) do |m|
|
|
23
|
+
idx = placeholders.size
|
|
24
|
+
placeholders << m
|
|
25
|
+
"__I18NIZE_PLH_#{idx}__"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
19
28
|
|
|
20
29
|
uri = URI(ENDPOINT)
|
|
21
|
-
|
|
22
|
-
# Opakující se text parametry
|
|
23
30
|
body_params = [
|
|
24
31
|
["auth_key", @auth_key],
|
|
25
32
|
["source_lang", @from_lang],
|
|
26
33
|
["target_lang", @to_lang],
|
|
27
|
-
] +
|
|
34
|
+
] + protected.map { |text| ["text", text] }
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
req = Net::HTTP::Post.new(uri)
|
|
37
|
+
req["Content-Type"] = "application/x-www-form-urlencoded"
|
|
38
|
+
req.body = URI.encode_www_form(body_params)
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
end
|
|
40
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
|
|
41
|
+
raise "DeepL API Error: #{res.code} - #{res.body}" unless res.is_a?(Net::HTTPSuccess)
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
json = JSON.parse(response.body)
|
|
42
|
-
translated = json["translations"].map { |t| t["text"] }
|
|
43
|
+
json = JSON.parse(res.body)
|
|
44
|
+
out = json["translations"].map { |t| t["text"] }
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
out.map { |s| s.gsub(/__I18NIZE_PLH_(\d+)__/) { placeholders[$1.to_i] } }
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
|
-
|
data/lib/i18nize/version.rb
CHANGED