extract_i18n 0.6.2 → 0.7.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.
@@ -7,6 +7,7 @@ module ExtractI18n::Adapters
7
7
  when /\.rb$/ then RubyAdapter
8
8
  when /\.erb$/ then ErbAdapter
9
9
  when /\.slim$/ then SlimAdapter
10
+ when /\.ts$/, /\.js$/, /\.mjs/, /\.jsx$/ then JsAdapter
10
11
  when /\.vue$/
11
12
  if File.read(file_path)[/lang=.pug./]
12
13
  VuePugAdapter
@@ -0,0 +1,79 @@
1
+ require 'open3'
2
+ require 'json'
3
+
4
+ module ExtractI18n::Adapters
5
+ class JsAdapter < Adapter
6
+ IGNORE_AFTER = /(key: *|import .*|require\(.*)/
7
+
8
+ def run(original_context)
9
+ path = '../../../js/find_string_tokens.js'
10
+ abs_path = File.expand_path(path, __dir__)
11
+ stdout, stderr, status = Open3.capture3('node', abs_path, stdin_data: original_context)
12
+ unless status.success?
13
+ warn stderr
14
+ warn "Failed to run js/find_string_tokens.js: #{status}"
15
+ return original_context
16
+ end
17
+ @current_buffer = original_context.dup
18
+ @original_context = original_context.dup.freeze
19
+
20
+ @t_template = %[t('%s'%s)]
21
+ if vue2?(original_context)
22
+ @t_template = %[this.$t('%s'%s)]
23
+ end
24
+
25
+ @byte_offset = 0
26
+
27
+ results = ::JSON.parse(stdout, symbolize_names: true)
28
+ results.each do |item|
29
+ if item[:type] == 'literal'
30
+ replace_string(item)
31
+ else
32
+ warn "Template String literals not implemented yet: #{JSON.pretty_generate(item)}"
33
+ end
34
+ end
35
+ @current_buffer
36
+ end
37
+
38
+ def replace_string(item)
39
+ content = item[:value]
40
+ start = [item.dig(:loc, :start, :line) - 1, item.dig(:loc, :start, :column)]
41
+ finish = [item.dig(:loc, :end, :line) - 1, item.dig(:loc, :end, :column)]
42
+
43
+ source_line = @original_context.lines[start[0]]
44
+ change = ExtractI18n::SourceChange.new(
45
+ i18n_key: "#{@file_key}.#{ExtractI18n.key(content)}",
46
+ i18n_string: content,
47
+ source_line: source_line,
48
+ remove: item[:raw],
49
+ t_template: @t_template,
50
+ interpolation_type: :vue,
51
+ interpolate_arguments: {},
52
+ )
53
+
54
+ if ExtractI18n.ignore?(change.i18n_string)
55
+ return
56
+ end
57
+ token = Regexp.escape(item[:raw])
58
+ regexp = Regexp.new(IGNORE_AFTER.to_s + token)
59
+ return if source_line.match?(regexp)
60
+ return if change.i18n_string[file_key]
61
+
62
+ byte_from = @original_context.lines[0...start[0]].join.length + start[1]
63
+ byte_to = @original_context.lines[0...finish[0]].join.length + finish[1]
64
+
65
+ if @on_ask.call(change)
66
+ byte_from += @byte_offset
67
+ byte_to += @byte_offset
68
+
69
+ @current_buffer = @current_buffer[0...byte_from] + change.i18n_t + @current_buffer[byte_to..]
70
+
71
+ @byte_offset += change.i18n_t.length - item[:raw].length
72
+ end
73
+ end
74
+
75
+ def vue2?(content)
76
+ content['data()'] || content['computed:'] || content['this.$i18n'] || content['this.$t'] || content['this.$store']
77
+ end
78
+ end
79
+ end
@@ -37,7 +37,9 @@ module ExtractI18n::Adapters
37
37
  all_match
38
38
  end
39
39
  end
40
- out
40
+ @new_content = out.split("\n")
41
+ check_javascript_for_strings!
42
+ @new_content.join("\n")
41
43
  end
42
44
 
43
45
  # nokogir::html can parse @click.prevent stuff, but transforms all CamelCase Attributes to kebab-case by default
@@ -134,5 +136,20 @@ module ExtractI18n::Adapters
134
136
  end
135
137
  [args, translation]
136
138
  end
139
+
140
+ def check_javascript_for_strings!
141
+ lines = @new_content
142
+ # drop lines until <script
143
+ start = lines.find_index { |line| line[/^<script/] }
144
+ finish = lines.find_index { |line| line[/^<\/script/] }
145
+ return if start.nil? || finish.nil?
146
+
147
+ js_content = lines[(start + 1)...finish].join("\n")
148
+
149
+ js_adapter = ExtractI18n::Adapters::JsAdapter.new(file_key: @file_key, on_ask: @on_ask, options: @options)
150
+ js_replaced = js_adapter.run(js_content)
151
+
152
+ @new_content = lines[0..start] + js_replaced.split("\n") + lines[(finish)..-1]
153
+ end
137
154
  end
138
155
  end
@@ -2,6 +2,27 @@
2
2
 
3
3
  module ExtractI18n::Adapters
4
4
  class VuePugAdapter < SlimAdapter
5
+ def run(original_content)
6
+ super
7
+ check_javascript_for_strings!
8
+ @new_content.join("\n")
9
+ end
10
+
11
+ def check_javascript_for_strings!
12
+ lines = @new_content
13
+ # drop lines until <script
14
+ start = lines.find_index { |line| line[/^<script/] }
15
+ finish = lines.find_index { |line| line[/^<\/script/] }
16
+ return if start.nil? || finish.nil?
17
+
18
+ js_content = lines[(start + 1)...finish].join("\n")
19
+
20
+ js_adapter = ExtractI18n::Adapters::JsAdapter.new(file_key: @file_key, on_ask: @on_ask, options: @options)
21
+ js_replaced = js_adapter.run(js_content)
22
+
23
+ @new_content = lines[0..start] + js_replaced.split("\n") + lines[(finish)..-1]
24
+ end
25
+
5
26
  def process_line(old_line)
6
27
  @mode ||= :template
7
28
  if old_line[/^<template/]
@@ -19,6 +40,9 @@ module ExtractI18n::Adapters
19
40
  if change.nil? # nothing to do
20
41
  return old_line
21
42
  end
43
+ if ExtractI18n.ignore?(change.i18n_string) || change.i18n_string.empty?
44
+ return old_line
45
+ end
22
46
 
23
47
  if @on_ask.call(change)
24
48
  change.i18n_t
@@ -1,3 +1,3 @@
1
1
  module ExtractI18n
2
- VERSION = "0.6.2"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/extract_i18n.rb CHANGED
@@ -22,10 +22,19 @@ module ExtractI18n
22
22
  self.ignorelist = [
23
23
  '_',
24
24
  '::',
25
- %r{^/}
25
+ 'v-else',
26
+ 'v-else-if',
27
+ '&nbsp;',
28
+ %r{^#[^ ]+$},
29
+ %r{^/},
30
+ %r{^(mdi|fa|fas|far|icon)-},
26
31
  ]
27
32
  self.html_fields_with_plaintext = %w[title placeholder alt label aria-label modal-title]
28
33
 
34
+ def self.ignore?(string)
35
+ ExtractI18n.ignorelist.any? { |item| string.to_s[item] }
36
+ end
37
+
29
38
  def self.key(string, length: 25)
30
39
  string.strip.
31
40
  unicode_normalize(:nfkd).gsub(/(\p{Letter})\p{Mark}+/, '\\1').
@@ -35,9 +44,10 @@ module ExtractI18n
35
44
 
36
45
  def self.file_key(path)
37
46
  path.gsub(strip_path, '').
38
- gsub(%r{^/|/$}, '').
39
- gsub(/\.(vue|rb|html\.slim|\.slim)$/, '').
40
- gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').
47
+ gsub(%r{^/|/$}, ''). # remove leading and trailing slashes
48
+ gsub(/\.[a-z]+$/, ''). # remove file extension
49
+ gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'). # convert camelcase to underscore
50
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
41
51
  gsub('/_', '.').
42
52
  gsub('/', '.').
43
53
  tr("-", "_").downcase
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extract_i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Wienert
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-29 00:00:00.000000000 Z
11
+ date: 2024-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -121,6 +121,7 @@ files:
121
121
  - ".gitignore"
122
122
  - ".rspec"
123
123
  - ".rubocop.yml"
124
+ - CONTRIBUTING.md
124
125
  - Gemfile
125
126
  - LICENSE.txt
126
127
  - README.md
@@ -129,9 +130,13 @@ files:
129
130
  - bin/setup
130
131
  - exe/extract-i18n
131
132
  - extract_i18n.gemspec
133
+ - js/.gitignore
134
+ - js/.tool-versions
135
+ - js/find_string_tokens.js
132
136
  - lib/extract_i18n.rb
133
137
  - lib/extract_i18n/adapters/adapter.rb
134
138
  - lib/extract_i18n/adapters/erb_adapter.rb
139
+ - lib/extract_i18n/adapters/js_adapter.rb
135
140
  - lib/extract_i18n/adapters/ruby_adapter.rb
136
141
  - lib/extract_i18n/adapters/slim_adapter.rb
137
142
  - lib/extract_i18n/adapters/slim_adapter_wip.rb
@@ -157,8 +162,9 @@ files:
157
162
  homepage: https://github.com/pludoni/extract_i18n
158
163
  licenses:
159
164
  - MIT
160
- metadata: {}
161
- post_install_message:
165
+ metadata:
166
+ rubygems_mfa_required: 'true'
167
+ post_install_message:
162
168
  rdoc_options: []
163
169
  require_paths:
164
170
  - lib
@@ -166,15 +172,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
166
172
  requirements:
167
173
  - - ">="
168
174
  - !ruby/object:Gem::Version
169
- version: '0'
175
+ version: 2.7.0
170
176
  required_rubygems_version: !ruby/object:Gem::Requirement
171
177
  requirements:
172
178
  - - ">="
173
179
  - !ruby/object:Gem::Version
174
180
  version: '0'
175
181
  requirements: []
176
- rubygems_version: 3.2.33
177
- signing_key:
182
+ rubygems_version: 3.5.11
183
+ signing_key:
178
184
  specification_version: 4
179
185
  summary: Extact i18n from Ruby files using Ruby parser and slim files using regex
180
186
  test_files: []