extract_i18n 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0e718931e791745b06662fbf98b56bd9728f24aed2016843ec41b94bc77f466
4
- data.tar.gz: 85fbfbfd1104dbce0a49e6898180c01f5ab9d3fb7ce1d282e1939ece01501114
3
+ metadata.gz: 1d6886c7a13cbbe6698326a72004018aaea5f57e753a9fab278f4025181bdd01
4
+ data.tar.gz: 10172e9a05996706d92f314291137c13bb8c957a0a974e9d9852cd295cb45ceb
5
5
  SHA512:
6
- metadata.gz: 8822e7f750d327573964307a97f2e0d461a81efc5e66e721724611399cb2093fce8312c2cd3a733d95c9321c7715e784c265b924966b2140d86c1daeb533bdbf
7
- data.tar.gz: ba1604c2e7f384d63effe8bc451b0004adb8c33c4ed9a5552115718bea8c09cc5c5f9923c9409a39fec85cb35ab4607e3e7a8b1e2fcfbf1932742a06759230c4
6
+ metadata.gz: dcc33ec2bfab6ec9970508beebb22f57266679c20df3d97ee1eeaea2650c97f052a037ee4ce46de109bc09984b96df7df6a3097edfcb66772e6156c330a466e6
7
+ data.tar.gz: 7d75f557e0a6e1074e504931fa4ea6985153589dd0307fdd08d51faf3d6173ae6a29a0c15c146fee2bbc490d4a201628c067ba5de12257d7999e6a1b13c0bc86
data/README.md CHANGED
@@ -12,15 +12,17 @@ This Gem **supports** the following source files:
12
12
 
13
13
  - Ruby files (controllers, models etc.) via Ruby-Parser, e.g. walking all Ruby Strings
14
14
  - Slim Views (via Regexp parser by [SlimKeyfy](https://github.com/phrase/slimkeyfy) (MIT License))
15
+ - Vue templates
16
+ - will scan all texts and common string-attributes such as title, alt etc. for static strings and replace with vue-i18n's $t
17
+ - Caveats: because of limitations of the HTML/XML parser it will slightly transform the HTML, for example, self closing tags are expanded (e.g. ``<Component />`` will become ``<Component></Component>``). Also multi-line arrangements of attributes, tags etc. might produce unexpected results, so make sure to use Git and diff the result.
15
18
  - Vue Pug views
16
- - Pug is very similar to slim and thus relatively good extractable via Regexp.
19
+ - Pug is very similar to slim and thus relatively well extractable via Regexp.
17
20
  - ERB views
18
21
  - by vendoring/extending https://github.com/ProGM/i18n-html_extractor (MIT License)
19
22
 
20
23
  CURRENTLY THERE IS **NO SUPPORT** FOR:
21
24
 
22
25
  - haml ( integrating https://github.com/shaiguitar/haml-i18n-extractor)
23
- - vue html templates ([Check out my vue pug converting script](https://gist.github.com/zealot128/6c41df1d33a810856a557971a04989f6))
24
26
 
25
27
  But I am open to integrating PRs for those!
26
28
 
@@ -6,7 +6,12 @@ module ExtractI18n::Adapters
6
6
  case file_path
7
7
  when /\.rb$/ then RubyAdapter
8
8
  when /\.slim$/ then SlimAdapter
9
- when /\.vue$/ then VueAdapter
9
+ when /\.vue$/
10
+ if File.read(file_path)[/lang=.pug./]
11
+ VuePugAdapter
12
+ else
13
+ VueAdapter
14
+ end
10
15
  end
11
16
  end
12
17
 
@@ -1,31 +1,138 @@
1
- # frozen_string_literal: true
2
-
1
+ require 'nokogiri'
3
2
  module ExtractI18n::Adapters
4
- class VueAdapter < SlimAdapter
5
- def process_line(old_line)
6
- @mode ||= :template
7
- if old_line[/^<template/]
8
- @mode = :template
9
- elsif old_line[/^<script/]
10
- @mode = :script
11
- elsif old_line[/^<style/]
12
- @mode = :style
13
- end
14
- if @mode != :template
15
- return old_line
16
- end
17
- word = ExtractI18n::Slimkeyfy::Word.for('.vue').new(old_line)
18
- ExtractI18n::Slimkeyfy::VueTransformer.new(word, @file_key).transform do |change|
19
- if change.nil? # nothing to do
20
- return old_line
3
+ class VueAdapter < Adapter
4
+ ATTRIBUTES_WITH_TEXT = %w[
5
+ title
6
+ alt
7
+ placeholder
8
+ label
9
+ description
10
+ ]
11
+ def run(original_content)
12
+ content2, replace_pairs = replace_camelcase_attributes(original_content)
13
+
14
+ doc = Nokogiri::HTML5.fragment(content2)
15
+ template = doc.at('template')
16
+ return original_content unless template
17
+ return original_content if template['lang']
18
+
19
+ nodes = template.xpath(".//text() | text()").select { |i| i.to_s.strip.length > 0 }
20
+
21
+ nodes.each do |node|
22
+ process_change(node)
23
+ end
24
+
25
+ ATTRIBUTES_WITH_TEXT.each do |attr|
26
+ template.search("*[#{attr}]").each do |node|
27
+ process_attribute_change(node, attr)
28
+ end
29
+ end
30
+
31
+ out = unreplace_camelcase_attributes(doc.to_s, replace_pairs)
32
+ out.gsub!(/ (\w+)=""/) do |all_match|
33
+ m = $1
34
+ if original_content[/ #{m}[^=]/]
35
+ " #{m}"
36
+ else
37
+ all_match
21
38
  end
39
+ end
40
+ out
41
+ end
22
42
 
23
- if @on_ask.call(change)
24
- change.i18n_t
43
+ # nokogir::html can parse @click.prevent stuff, but transforms all CamelCase Attributes to kebab-case by default
44
+ # To keep the original case, we replace it with a placeholder and unreplace it back
45
+ def replace_camelcase_attributes(text)
46
+ cc = 1
47
+ pairs = []
48
+ replaced = text.gsub(/ ([a-zA-Z:]+=)/) { |pp|
49
+ match = Regexp.last_match
50
+ cc += 1
51
+ # kebab-case
52
+ if pp[/[A-Z]/]
53
+ kebab = match[1].gsub(/([A-Z])/) { |i| "-#{i.downcase}" }
54
+ hack = " :camelcase-nokogiri-hack-#{cc}-#{kebab}"
55
+ pairs << [hack, " " + match[1]]
56
+ hack
25
57
  else
26
- old_line
58
+ pp
27
59
  end
60
+ }
61
+ # tags
62
+ replaced.scan(/<([a-zA-Z0-9]+)/).flatten.each do |pp|
63
+ next pp unless pp[/[A-Z]/]
64
+
65
+ cc += 1
66
+
67
+ kebab = pp.gsub(/([A-Z])/) { |i| "-#{i.downcase}" }.sub(/^-/, '')
68
+ hack = "camelcase-nokogiri-hack-#{cc}-#{kebab}"
69
+ replaced.gsub!(/<#{pp}/, "<#{hack}")
70
+ replaced.gsub!(/<\/ *#{pp}/, "</#{hack}")
71
+ pairs << ["<#{hack}", "<#{pp}"]
72
+ pairs << ["</#{hack}", "</#{pp}"]
73
+ end
74
+ [replaced, pairs]
75
+ end
76
+
77
+ def unreplace_camelcase_attributes(text, pairs)
78
+ txt = text.dup
79
+ pairs.each do |hack, camel|
80
+ txt.gsub!(hack, camel)
81
+ end
82
+ txt
83
+ end
84
+
85
+ def process_attribute_change(node, attr)
86
+ _, ws_before, content, ws_after = node[attr].to_s.match(/(\s*)(.*?)(\s*)$/m).to_a
87
+
88
+ interpolate_arguments, content = extract_arguments(content)
89
+
90
+ change = ExtractI18n::SourceChange.new(
91
+ i18n_key: "#{@file_key}.#{ExtractI18n.key(content)}",
92
+ i18n_string: content,
93
+ source_line: node.to_s,
94
+ remove: content,
95
+ t_template: %[$t('%s'%s)],
96
+ interpolation_type: :vue,
97
+ interpolate_arguments: interpolate_arguments,
98
+ )
99
+ if @on_ask.call(change)
100
+ node.remove_attribute "title"
101
+ node[":" + attr] = "#{ws_before}#{change.i18n_t}#{ws_after}"
102
+ end
103
+ end
104
+
105
+ def process_change(node)
106
+ _, ws_before, content, ws_after = node.to_s.match(/(\s*)(.*?)(\s*)$/m).to_a
107
+
108
+ return if content.include?("{{")
109
+
110
+ interpolate_arguments, content = extract_arguments(content)
111
+
112
+ change = ExtractI18n::SourceChange.new(
113
+ i18n_key: "#{@file_key}.#{ExtractI18n.key(content)}",
114
+ i18n_string: content,
115
+ source_line: node.parent.to_s,
116
+ remove: content,
117
+ t_template: %[{{ $t('%s'%s) }}],
118
+ interpolation_type: :vue,
119
+ interpolate_arguments: interpolate_arguments,
120
+ )
121
+ if @on_ask.call(change)
122
+ node.replace("#{ws_before}#{change.i18n_t}#{ws_after}")
123
+ end
124
+ end
125
+
126
+ def extract_arguments(translation)
127
+ args = {}
128
+ translation.scan(/\{\{([^}]*)\}\}/).each_with_index do |stripped_arg, index|
129
+ arg = Regexp.last_match[0]
130
+ key = ExtractI18n.key(arg)
131
+ key = key + index.to_s if index > 0
132
+ translation = translation.gsub(arg, "{#{key}}")
133
+ args[key] = stripped_arg[0]
28
134
  end
135
+ [args, translation]
29
136
  end
30
137
  end
31
138
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExtractI18n::Adapters
4
+ class VuePugAdapter < SlimAdapter
5
+ def process_line(old_line)
6
+ @mode ||= :template
7
+ if old_line[/^<template/]
8
+ @mode = :template
9
+ elsif old_line[/^<script/]
10
+ @mode = :script
11
+ elsif old_line[/^<style/]
12
+ @mode = :style
13
+ end
14
+ if @mode != :template
15
+ return old_line
16
+ end
17
+ word = ExtractI18n::Slimkeyfy::Word.for('.vue').new(old_line)
18
+ ExtractI18n::Slimkeyfy::VueTransformer.new(word, @file_key).transform do |change|
19
+ if change.nil? # nothing to do
20
+ return old_line
21
+ end
22
+
23
+ if @on_ask.call(change)
24
+ change.i18n_t
25
+ else
26
+ old_line
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module ExtractI18n
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
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.5.0
4
+ version: 0.6.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: 2020-12-02 00:00:00.000000000 Z
11
+ date: 2022-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -136,6 +136,7 @@ files:
136
136
  - lib/extract_i18n/adapters/slim_adapter.rb
137
137
  - lib/extract_i18n/adapters/slim_adapter_wip.rb
138
138
  - lib/extract_i18n/adapters/vue_adapter.rb
139
+ - lib/extract_i18n/adapters/vue_pug_adapter.rb
139
140
  - lib/extract_i18n/cli.rb
140
141
  - lib/extract_i18n/file_processor.rb
141
142
  - lib/extract_i18n/html_extractor/erb_document.rb
@@ -157,7 +158,7 @@ homepage: https://github.com/pludoni/extract_i18n
157
158
  licenses:
158
159
  - MIT
159
160
  metadata: {}
160
- post_install_message:
161
+ post_install_message:
161
162
  rdoc_options: []
162
163
  require_paths:
163
164
  - lib
@@ -172,9 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
173
  - !ruby/object:Gem::Version
173
174
  version: '0'
174
175
  requirements: []
175
- rubyforge_project:
176
- rubygems_version: 2.7.6
177
- signing_key:
176
+ rubygems_version: 3.1.6
177
+ signing_key:
178
178
  specification_version: 4
179
179
  summary: Extact i18n from Ruby files using Ruby parser and slim files using regex
180
180
  test_files: []