canvas-i18n-editor 0.0.1

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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/canvas-i18n-editor +164 -0
  3. 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: []