extract_i18n 0.4.0 → 0.6.1

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: e096f991f890e9173c84d6e243be7eb37471214d45b10c78b371d00cd655559c
4
- data.tar.gz: 5d4094b82db8a575f16398eee06f89e41e588fecde0e00c60a12c74b62692228
3
+ metadata.gz: 5e9ea495d1a96a93748f313d60ee9b8b3e88d8ddb61b3628ca93cbc748168993
4
+ data.tar.gz: 0e9df509a6f3c6b255cc9b2508bbc5e95ff07e533b2cdfd42f2f3fd5d53856fa
5
5
  SHA512:
6
- metadata.gz: dd60db2f7d6dcccf61af954e2c93dce5d7db2be2571a6b53bc299dab47541d3bbb16ce55422c7c36cbc915395ce166fd6c52bddad5f9d6f1dd5cd4acf0b06f94
7
- data.tar.gz: 73e063ef3162a6dc09f0de306fce9aadb07b2291fc8452c83cae1342915dcd5030894ba913d6f4c5825e6b3f8cf9aeee94dc0d3d7b8a33738d3cab4d0ec80681
6
+ metadata.gz: 9037d8f7c79b3b451dbf7c92ca284003fd5d458bb9637320b8703f22e92615af22246fe17f302eb0c5c12ebca8bba8aef9bc163bc5dfeb5573dd4e6b27c3aa61
7
+ data.tar.gz: 0e23b0cf385fbc1a1796d1881105aacbf5325ce45b6a48dc01000f57f337e8ce2da8c5fc1aae0c87fc402fbad3232206b552369c5d72cb5e63f9b6980fa25f82
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[/^\{\{/]
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
@@ -23,8 +23,8 @@ module ExtractI18n
23
23
  append: /(?<html_tag>append:\s*)/,
24
24
  label: /(?<html_tag>[a-z]*_?label:\s*)/,
25
25
  optionals: /(?<html_tag>(default|include_blank|alt):\s*)/,
26
- input: /(?<html_tag>[a-z]*\.?input:?\s*)/,
27
- button: /(?<html_tag>[a-z]*\.?button:?\s*(\:[a-z]+\s*,\s*)?)/,
26
+ input: /(?<html_tag>[a-z]*\.?input:\s*)/,
27
+ button: /(?<html_tag>[a-z]*\.?button:\s*(\:[a-z]+\s*,\s*)?)/,
28
28
  tag: /(?<html_tag>(submit|content)_tag[\:\(]?\s*)/,
29
29
  data_naive: /(?<html_tag>data:\s*\{\s*(confirm|content):\s*)/
30
30
  }.freeze
@@ -70,7 +70,7 @@ module ExtractI18n
70
70
  end
71
71
 
72
72
  def increment_key!
73
- if @key[-1][/(.*)([0-9]+)$/]
73
+ if @key[/(.+)([0-9]+)$/]
74
74
  rest = $1
75
75
  number = $2.to_i
76
76
  else
@@ -1,3 +1,3 @@
1
1
  module ExtractI18n
2
- VERSION = "0.4.0"
2
+ VERSION = "0.6.1"
3
3
  end
data/lib/extract_i18n.rb CHANGED
@@ -21,7 +21,8 @@ module ExtractI18n
21
21
  self.ignore_functions = %w[where order group select sql]
22
22
  self.ignorelist = [
23
23
  '_',
24
- '::'
24
+ '::',
25
+ %r{^/}
25
26
  ]
26
27
  self.html_fields_with_plaintext = %w[title placeholder alt label aria-label modal-title]
27
28
 
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.4.0
4
+ version: 0.6.1
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-11-18 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: []