canvas-i18n-editor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/canvas-i18n-editor +164 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '0777905a738e9fee9146ed71fef0f70fad8018df1f834e425cd9348bc7aa98f4'
|
4
|
+
data.tar.gz: da069aed8d20995f8bc51a464ea78a58a9873d93a3547a06eec987b199c8e5d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ad3f83a7151abebeff87dd96232ff801374ecd11578ecd51de02835094284dd52c6ec1e28e0c1e4cf3964b34933ec987710f3b3ae3bd7651610580c4e5636a0b
|
7
|
+
data.tar.gz: ef6feaee7ba8125d6a443374a9262b129980a15c8e7837848a9e9a16c17e1f0924364553f888898b4071c346a3a5419dd9e2ec758952b763c71ff47708f0fe42
|
@@ -0,0 +1,164 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "zlib"
|
5
|
+
require "optparse"
|
6
|
+
require "fileutils"
|
7
|
+
require "json"
|
8
|
+
|
9
|
+
Options = Struct.new(:translate_from, :translate_to, :mode, :apply_js)
|
10
|
+
|
11
|
+
ACCEPTED_MODE = %w[canvas rails reverse].freeze
|
12
|
+
|
13
|
+
LOCALE_FILE = "config/locales/zh-Hant.yml"
|
14
|
+
JS_LOCALE_FILE = "public/javascripts/translations/zh-Hant.json"
|
15
|
+
TMP_FILE = "/tmp/canvas-i18n"
|
16
|
+
|
17
|
+
# index = 4, skip 4 lines to translation body
|
18
|
+
def update_rails_i18n(args)
|
19
|
+
raw_key = args.translate_from
|
20
|
+
# find key in config/locales/zh-Hant.yml
|
21
|
+
data = File.readlines(LOCALE_FILE)
|
22
|
+
keywords = raw_key.split(".")
|
23
|
+
current_layer = 1
|
24
|
+
get_layer = -> { _1.match(/^\s*/)[0].size / 2 }
|
25
|
+
updated_flag = false
|
26
|
+
File.open(TMP_FILE, "w:UTF-8") do |file|
|
27
|
+
data[0..3].each { file.write(_1) }
|
28
|
+
(4..data.size - 1).each do |line_index|
|
29
|
+
line = data[line_index]
|
30
|
+
unless updated_flag
|
31
|
+
if data[line_index].match?(/^\s*#{keywords[0]}:/)
|
32
|
+
line_number = line_index + 1
|
33
|
+
key = keywords.shift
|
34
|
+
current_layer += 1
|
35
|
+
puts "find #{key} in line #{line_number}"
|
36
|
+
# find last key, should update content now
|
37
|
+
if keywords.empty?
|
38
|
+
line = line.sub(/#{key}:\s?/, "#{key}: ").sub(/(?<=#{key}:\s).+/, "\"#{args.translate_to}\"")
|
39
|
+
updated_flag = true
|
40
|
+
end
|
41
|
+
elsif line_index < data.size - 1 && get_layer[data[line_index + 1]] < current_layer
|
42
|
+
# determine can't find key early, update with nested structure
|
43
|
+
update_nested_key(file, keywords, current_layer, args)
|
44
|
+
updated_flag = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
file.write(line)
|
49
|
+
end
|
50
|
+
|
51
|
+
update_nested_key(file, keywords, current_layer, args) unless updated_flag
|
52
|
+
file.close
|
53
|
+
end
|
54
|
+
FileUtils.mv(TMP_FILE, LOCALE_FILE)
|
55
|
+
update_js(raw_key, args.translate_to, args.apply_js)
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_nested_key(file, keywords, current_layer, args)
|
59
|
+
keywords[0..-2].each do |key|
|
60
|
+
file.write("#{' ' * 2 * current_layer}#{key}: \n")
|
61
|
+
current_layer += 1
|
62
|
+
end
|
63
|
+
file.write("#{' ' * 2 * current_layer}#{keywords[-1]}: #{args.translate_to}\n")
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_js(key, translate_to, apply_js)
|
67
|
+
data = File.read(JS_LOCALE_FILE)
|
68
|
+
data = data.sub(/(?<="#{key}":)"[^"]+"/, "\"#{translate_to}\"")
|
69
|
+
puts "update js translations"
|
70
|
+
|
71
|
+
File.write(JS_LOCALE_FILE, data)
|
72
|
+
generate_hashed_js if apply_js
|
73
|
+
end
|
74
|
+
|
75
|
+
def generate_hashed_js
|
76
|
+
`rm public/dist/javascripts/translations/zh-Hant-*.json`
|
77
|
+
puts "generate scoped js translations"
|
78
|
+
`bundle exec rails js:gulp_rev`
|
79
|
+
end
|
80
|
+
|
81
|
+
def update_canvas_i18n(args)
|
82
|
+
hash = Zlib.crc32("#{args.translate_from.size}:#{args.translate_from}").to_s(16)
|
83
|
+
prefix = args.translate_from.downcase[0,50].gsub(/[\s\-\/_:]{1,}/, "_").gsub(/[^a-zA-Z0-9_-]/, "")
|
84
|
+
key = "#{prefix}_#{hash}"
|
85
|
+
updated_flag = false
|
86
|
+
# find key in config/locales/zh-Hant.yml
|
87
|
+
File.open(TMP_FILE, "w:UTF-8") do |file|
|
88
|
+
File.readlines(LOCALE_FILE).each_with_index do |line, line_index|
|
89
|
+
if !updated_flag && line.match?(/^\s*#{key}:/)
|
90
|
+
line_number = line_index + 1
|
91
|
+
puts "find key in line #{line_number}"
|
92
|
+
line = line.sub(/#{key}:\s?/, "#{key}: ").sub(/(?<=#{key}:\s).+/, "\"#{args.translate_to}\"")
|
93
|
+
updated_flag = true
|
94
|
+
end
|
95
|
+
|
96
|
+
file.write(line)
|
97
|
+
end
|
98
|
+
|
99
|
+
unless updated_flag
|
100
|
+
puts "specified key not found in locale file, create one in last line"
|
101
|
+
file.write(" #{key}: #{args.translate_to}\n")
|
102
|
+
end
|
103
|
+
|
104
|
+
file.close
|
105
|
+
end
|
106
|
+
|
107
|
+
FileUtils.mv(TMP_FILE, LOCALE_FILE)
|
108
|
+
update_js(key, args.translate_to, args.apply_js)
|
109
|
+
end
|
110
|
+
|
111
|
+
def update_from_content(args)
|
112
|
+
search_keyword = args.translate_from
|
113
|
+
# TODO: use translate_from(means original content here) to search for key(query like %keyword%)
|
114
|
+
# TODO: raise error if there's multiple candidate
|
115
|
+
# TODO: use the key to update yml directly, and get full key if it's rails i18n
|
116
|
+
# TODO: use key(full key) to update_js
|
117
|
+
end
|
118
|
+
|
119
|
+
class Parser
|
120
|
+
def self.parse(user_input)
|
121
|
+
args = Options.new
|
122
|
+
|
123
|
+
opt_parser = OptionParser.new do |opts|
|
124
|
+
opts.banner = "Usage:
|
125
|
+
cool_i18n_edit translateFrom translateTo [options]
|
126
|
+
|
127
|
+
cool_i18n_edit -t canvas 'Click Me' '點我' # edit i18n using canvas liner-style key
|
128
|
+
cool_i18n_edit -t rails 'controller_name.action_name.click_me' '點我' # edit i18n using rails i18n key
|
129
|
+
"
|
130
|
+
|
131
|
+
opts.on("-m MODE", "--mode MODE", "canvas, rails or reverse") do |mode|
|
132
|
+
args.mode = mode
|
133
|
+
end
|
134
|
+
|
135
|
+
opts.on("-a", "--apply", "apply js translations") do
|
136
|
+
args.apply_js = true
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on("-h", "--help", "Prints this help") do
|
140
|
+
puts opts
|
141
|
+
exit
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
opt_parser.parse!(user_input) # options are remove after this line
|
146
|
+
raise "-m option not set" unless args.mode
|
147
|
+
raise "invalid -m option #{args.mode}\nonly below types are allowed\n#{ACCEPTED_MODE.join(",")}" unless ACCEPTED_MODE.include?(args.mode)
|
148
|
+
|
149
|
+
args.translate_from = user_input[0].strip
|
150
|
+
args.translate_to = user_input[1].strip
|
151
|
+
|
152
|
+
args
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
args = Parser.parse(ARGV)
|
157
|
+
case args.mode
|
158
|
+
in "rails"
|
159
|
+
update_rails_i18n(args)
|
160
|
+
in "canvas"
|
161
|
+
update_canvas_i18n(args)
|
162
|
+
in "reverse"
|
163
|
+
update_from_content(args)
|
164
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: canvas-i18n-editor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pero
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-06-28 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: i18n edit
|
14
|
+
email: 0711kps@gmail.com
|
15
|
+
executables:
|
16
|
+
- canvas-i18n-editor
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/canvas-i18n-editor
|
21
|
+
homepage: https://rubygems.org/gems/hola
|
22
|
+
licenses:
|
23
|
+
- MIT
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.7'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubygems_version: 3.3.26
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: i18n edit
|
44
|
+
test_files: []
|