l10nizer 1.0.0 → 1.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9c42cf69ad08d236a007080c7098673a6c9b673b73c73e8005ebe91355f7fe4e
4
+ data.tar.gz: dfc6b968ca72ceb531856ce406f95abe860e200a9c469af1a35c22860b236a25
5
+ SHA512:
6
+ metadata.gz: bc3ae7a90574b9645e0dffacc7dce9f496641cda62ad549105b5b095c4f63e2ad178bdfd27a30d7e1b80fda038ccfa951fa9897600c46ccb50c046903ac12d58
7
+ data.tar.gz: '009657cc294a0e4f66c42bfcc56d3200835721ca5150281070125b384f02fc03d52e4bc85208d1d012a4082d0ca9444a8ccc859553e8f8d8fa0c5b7938dbfb4e'
data/bin/l10nizer CHANGED
@@ -2,31 +2,89 @@
2
2
  require "l10nizer"
3
3
  require "yaml"
4
4
  require "fileutils"
5
+ require "optparse"
5
6
 
6
- Dir.chdir(ARGV.first) if ARGV.first
7
- templates = Dir["app/views/**/*.html.erb"]
8
- raise "Can't find any templates in app/views." unless templates.any?
7
+ executable = File.basename(__FILE__)
8
+
9
+ options = {
10
+ mode: :check,
11
+ path: "."
12
+ }
13
+
14
+ parser = OptionParser.new { |opts|
15
+ opts.banner = "Usage: #{executable} [options]"
16
+ opts.separator <<~STRING
17
+
18
+ #{executable} performs Automatic ex post facto localisation of Rails
19
+ templates.
20
+
21
+ By default, it will check for unlocalised text in templates, returning 0
22
+ if no such text is found, or returning 1 if it is found.
23
+
24
+ If the --extract option is passed, this text will be extracted from the
25
+ templates and deposited in a new file in config/locales/l10nized.yml.
26
+
27
+ STRING
28
+
29
+ opts.on(
30
+ "-e", "--extract",
31
+ "Replace strings with t() and write a locale file"
32
+ ) do
33
+ options[:mode] = :extract
34
+ end
35
+ opts.on(
36
+ "-p", "--path", String,
37
+ "Path to Rails app (default: #{options[:path]})"
38
+ ) do |str|
39
+ options[:path] = str
40
+ end
41
+ opts.on(
42
+ "-h", "--help",
43
+ "Display this help message and exit"
44
+ ) do
45
+ puts opts
46
+ exit
47
+ end
48
+
49
+ opts.separator ""
50
+ }
51
+
52
+ parser.parse!
53
+
54
+ Dir.chdir(options[:path])
55
+ templates = Dir[File.join("app", "views", "**", "*.html.erb")]
56
+ raise "Can't find any templates in #{options[:path]}" unless templates.any?
9
57
 
10
58
  keygen = L10nizer::KeyGenerator.new
59
+ namespacer = L10nizer::Namespacer.new
60
+ files_with_text = []
11
61
  l10ns = {}
12
62
 
13
63
  templates.each do |path|
14
- keygen.namespace = path.split("/")[2]
15
- source = File.read(path)
16
- l10nizer = L10nizer::Processor.new(source, keygen)
17
- l10ns.merge!(l10nizer.l10ns)
18
- File.open(path, "w") do |f|
19
- f << l10nizer.reformed
20
- end
64
+ keygen.namespace = namespacer.call(path)
65
+ l10nizer = L10nizer::Processor.new(File.read(path), keygen)
66
+ next unless l10nizer.l10ns.any?
67
+
68
+ files_with_text << path
69
+ next unless options[:mode] == :extract
70
+
71
+ l10ns.merge! l10nizer.l10ns
72
+ File.write path, l10nizer.reformed
21
73
  end
22
74
 
23
- l10ns = l10ns.inject({}){ |hash, (key, value)|
24
- parts = key.split(".")
25
- parts[0 .. -2].inject(hash){ |h, k| h[k] ||= {} }[parts.last] = value
26
- hash
27
- }
75
+ if files_with_text.any?
76
+ warn "Found unlocalised text in the following files:",
77
+ *files_with_text
28
78
 
29
- FileUtils.mkdir_p("config/locales")
30
- File.open("config/locales/l10nized.yml", "w") do |f|
31
- f << l10ns.to_yaml
79
+ case options[:mode]
80
+ when :extract
81
+ tree = L10nizer::LocaleGenerator.new.call(l10ns)
82
+ path = File.join("config", "locales", "l10nized.yml")
83
+ FileUtils.mkdir_p File.dirname(path)
84
+ File.write path, YAML.dump(tree)
85
+ when :check
86
+ exit 1
87
+ end
88
+ else
89
+ warn "No unlocalised text found."
32
90
  end
@@ -9,19 +9,21 @@ module L10nizer
9
9
  def call(string)
10
10
  provisional = [make_safe(namespace), make_safe(string)].compact * "."
11
11
 
12
- until try(provisional, string)
12
+ until distinct?(provisional, string)
13
13
  match = provisional.match(/_(\d+)$/)
14
14
  if match
15
- provisional.sub! /\d+$/, match[1].to_i.succ.to_s
15
+ provisional = provisional.sub(/\d+$/, match[1].to_i.succ.to_s)
16
16
  else
17
- provisional << "_1"
17
+ provisional += "_1"
18
18
  end
19
19
  end
20
20
 
21
- return provisional
21
+ provisional
22
22
  end
23
23
 
24
- def try(key, string)
24
+ private
25
+
26
+ def distinct?(key, string)
25
27
  if [nil, string].include?(@seen[key])
26
28
  @seen[key] = string
27
29
  true
@@ -32,13 +34,13 @@ module L10nizer
32
34
 
33
35
  def make_safe(string)
34
36
  return nil if string.nil?
35
- safe = string.
36
- downcase.
37
- gsub(/&[a-z0-9]{1,20};/, ""). # entities
38
- gsub(/<[^>]*>/, ""). # html
39
- gsub(/[^a-z0-9]+/, "_"). # non alphanumeric
40
- slice(0, 40).
41
- gsub(/^_|_$/, "") # leading/trailing _
37
+ safe = string
38
+ .downcase
39
+ .gsub(/&[a-z0-9]{1,20};/, "") # entities
40
+ .gsub(/<[^>]*>/, "") # html
41
+ .gsub(/[^a-z0-9.]+/, "_") # non alphanumeric
42
+ .slice(0, 40) # limit length
43
+ .gsub(/^_|_$/, "") # leading/trailing _
42
44
  safe = "unknown" if safe.empty?
43
45
  safe
44
46
  end
@@ -0,0 +1,11 @@
1
+ module L10nizer
2
+ class LocaleGenerator
3
+ def call(l10ns, lang: "en")
4
+ lang_tree = l10ns.each_with_object({}) { |(key, value), hash|
5
+ parts = key.split(".")
6
+ parts[0..-2].inject(hash) { |h, k| h[k] ||= {} }[parts.last] = value
7
+ }
8
+ {lang => lang_tree}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module L10nizer
2
+ class Namespacer
3
+ def call(path)
4
+ path.sub(/\.html\.erb$/, "").split(/\/_?/).drop(2).join(".")
5
+ end
6
+ end
7
+ end
data/lib/l10nizer/node.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module L10nizer
2
2
  class NodeWrapperFactory
3
- def self.wrap(node, keygen=nil)
3
+ def self.wrap(node, keygen = nil)
4
4
  case node
5
5
  when HtmlErb::Text
6
6
  TextNode.new(node, keygen)
@@ -15,8 +15,8 @@ module L10nizer
15
15
  end
16
16
 
17
17
  class BasicNode
18
- def initialize(node, keygen=nil)
19
- @node = node
18
+ def initialize(node, keygen = nil)
19
+ @node = node
20
20
  @keygen = keygen
21
21
  end
22
22
 
@@ -47,7 +47,7 @@ module L10nizer
47
47
  vars, _ = vars_and_text
48
48
  return super unless vars
49
49
 
50
- params = ['"' + key + '"']
50
+ params = ['".' + key.split(".").last + '"']
51
51
  vars.each_with_index do |v, i|
52
52
  params << %{#{variable_name(i)}: (#{v})}
53
53
  end
@@ -55,34 +55,35 @@ module L10nizer
55
55
  %{<%= t(#{params * ", "}) %>}
56
56
  end
57
57
 
58
- private
58
+ private
59
+
59
60
  def children
60
- @node.children.map{ |e| NodeWrapperFactory.wrap(e) }
61
+ @node.children.map { |e| NodeWrapperFactory.wrap(e) }
61
62
  end
62
63
 
63
64
  def variable_name(index)
64
- ("a" .. "z").to_a[index]
65
+ ("a".."z").to_a[index]
65
66
  end
66
67
 
68
+ # rubocop:disable Metrics/MethodLength
67
69
  def vars_and_text
68
- @vars_and_text ||= (
69
- if children.all?{ |c| c.evaluated? } || !children.any?{ |c| c.string? }
70
- []
71
- else
72
- l10n = ""
73
- vars = []
74
- children.each do |e|
75
- if e.evaluated?
76
- l10n << "%{#{variable_name(vars.length)}}"
77
- vars << e.to_s
78
- else
79
- l10n << e.to_s
80
- end
70
+ @vars_and_text ||= if children.all?(&:evaluated?) || children.none?(&:string?)
71
+ []
72
+ else
73
+ l10n = ""
74
+ vars = []
75
+ children.each do |e|
76
+ if e.evaluated?
77
+ l10n << "%{#{variable_name(vars.length)}}"
78
+ vars << e.to_s
79
+ else
80
+ l10n << e.to_s
81
81
  end
82
- [vars, l10n]
83
82
  end
84
- )
83
+ [vars, l10n]
84
+ end
85
85
  end
86
+ # rubocop:enable Metrics/MethodLength
86
87
 
87
88
  def key
88
89
  _, text = vars_and_text
@@ -8,7 +8,7 @@ module HtmlErb
8
8
 
9
9
  class Text < Treetop::Runtime::SyntaxNode
10
10
  def children
11
- elements.map{ |e| e.elements }.flatten
11
+ elements.flat_map(&:elements)
12
12
  end
13
13
  end
14
14
 
@@ -9,19 +9,19 @@ module L10nizer
9
9
  end
10
10
 
11
11
  def l10ns
12
- processed.inject({}){ |hash, node| hash.merge(node.l10n) }
12
+ processed.inject({}) { |hash, node| hash.merge(node.l10n) }
13
13
  end
14
14
 
15
15
  def reformed
16
- processed.map{ |e| e.to_s }.join
16
+ processed.map(&:to_s).join
17
17
  end
18
18
 
19
19
  def processed
20
20
  @processed ||=
21
- HtmlErbParser.new.
22
- parse(@html).
23
- elements.
24
- map{ |e| NodeWrapperFactory.wrap(e, @keygen) }
21
+ HtmlErbParser.new
22
+ .parse(@html)
23
+ .elements
24
+ .map { |e| NodeWrapperFactory.wrap(e, @keygen) }
25
25
  end
26
26
  end
27
27
  end
@@ -1,9 +1,9 @@
1
- module L10nizer #:nodoc:
2
- module VERSION #:nodoc:
1
+ module L10nizer # :nodoc:
2
+ module VERSION # :nodoc:
3
3
  MAJOR = 1
4
- MINOR = 0
5
- TINY = 0
4
+ MINOR = 1
5
+ TINY = 0
6
6
 
7
- STRING = [MAJOR, MINOR, TINY].join('.')
7
+ STRING = [MAJOR, MINOR, TINY].join(".")
8
8
  end
9
9
  end
data/lib/l10nizer.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require "l10nizer/processor"
2
2
  require "l10nizer/keygen"
3
+ require "l10nizer/namespacer"
4
+ require "l10nizer/locale_generator"
metadata CHANGED
@@ -1,81 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: l10nizer
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.0.0
4
+ version: 1.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Paul Battley
9
- autorequire:
10
8
  bindir: bin
11
9
  cert_chain: []
12
- date: 2013-04-03 00:00:00.000000000 Z
10
+ date: 2025-03-04 00:00:00.000000000 Z
13
11
  dependencies:
14
12
  - !ruby/object:Gem::Dependency
15
- type: :runtime
16
13
  name: treetop
17
- prerelease: false
18
14
  requirement: !ruby/object:Gem::Requirement
19
15
  requirements:
20
- - - ! '>='
16
+ - - "~>"
21
17
  - !ruby/object:Gem::Version
22
- version: 1.2.6
23
- none: false
18
+ version: '1.6'
19
+ type: :runtime
20
+ prerelease: false
24
21
  version_requirements: !ruby/object:Gem::Requirement
25
22
  requirements:
26
- - - ! '>='
23
+ - - "~>"
27
24
  - !ruby/object:Gem::Version
28
- version: 1.2.6
29
- none: false
25
+ version: '1.6'
30
26
  - !ruby/object:Gem::Dependency
31
- type: :runtime
32
27
  name: polyglot
33
- prerelease: false
34
28
  requirement: !ruby/object:Gem::Requirement
35
29
  requirements:
36
- - - ! '>='
30
+ - - "~>"
37
31
  - !ruby/object:Gem::Version
38
- version: 0.2.5
39
- none: false
32
+ version: 0.3.5
33
+ type: :runtime
34
+ prerelease: false
40
35
  version_requirements: !ruby/object:Gem::Requirement
41
36
  requirements:
42
- - - ! '>='
37
+ - - "~>"
43
38
  - !ruby/object:Gem::Version
44
- version: 0.2.5
45
- none: false
39
+ version: 0.3.5
46
40
  - !ruby/object:Gem::Dependency
47
- type: :development
48
- name: shoulda
49
- prerelease: false
41
+ name: rake
50
42
  requirement: !ruby/object:Gem::Requirement
51
43
  requirements:
52
- - - ! '>='
44
+ - - "~>"
53
45
  - !ruby/object:Gem::Version
54
- version: '0'
55
- none: false
46
+ version: '13'
47
+ type: :development
48
+ prerelease: false
56
49
  version_requirements: !ruby/object:Gem::Requirement
57
50
  requirements:
58
- - - ! '>='
51
+ - - "~>"
59
52
  - !ruby/object:Gem::Version
60
- version: '0'
61
- none: false
53
+ version: '13'
62
54
  - !ruby/object:Gem::Dependency
55
+ name: rspec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3'
63
61
  type: :development
64
- name: rake
65
62
  prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3'
68
+ - !ruby/object:Gem::Dependency
69
+ name: standard
66
70
  requirement: !ruby/object:Gem::Requirement
67
71
  requirements:
68
- - - ! '>='
72
+ - - ">="
69
73
  - !ruby/object:Gem::Version
70
74
  version: '0'
71
- none: false
75
+ type: :development
76
+ prerelease: false
72
77
  version_requirements: !ruby/object:Gem::Requirement
73
78
  requirements:
74
- - - ! '>='
79
+ - - ">="
75
80
  - !ruby/object:Gem::Version
76
81
  version: '0'
77
- none: false
78
- description:
79
82
  email: pbattley@gmail.com
80
83
  executables:
81
84
  - l10nizer
@@ -84,35 +87,32 @@ extra_rdoc_files: []
84
87
  files:
85
88
  - bin/l10nizer
86
89
  - lib/l10nizer.rb
87
- - lib/l10nizer/version.rb
88
- - lib/l10nizer/processor.rb
89
90
  - lib/l10nizer/grammar.treetop
90
- - lib/l10nizer/parser.rb
91
- - lib/l10nizer/node.rb
92
91
  - lib/l10nizer/keygen.rb
93
- homepage:
92
+ - lib/l10nizer/locale_generator.rb
93
+ - lib/l10nizer/namespacer.rb
94
+ - lib/l10nizer/node.rb
95
+ - lib/l10nizer/parser.rb
96
+ - lib/l10nizer/processor.rb
97
+ - lib/l10nizer/version.rb
94
98
  licenses: []
95
- post_install_message:
99
+ metadata: {}
96
100
  rdoc_options: []
97
101
  require_paths:
98
102
  - lib
99
103
  required_ruby_version: !ruby/object:Gem::Requirement
100
104
  requirements:
101
- - - ! '>='
105
+ - - ">="
102
106
  - !ruby/object:Gem::Version
103
107
  version: '0'
104
- none: false
105
108
  required_rubygems_version: !ruby/object:Gem::Requirement
106
109
  requirements:
107
- - - ! '>='
110
+ - - ">="
108
111
  - !ruby/object:Gem::Version
109
112
  version: '0'
110
- none: false
111
113
  requirements: []
112
- rubyforge_project:
113
- rubygems_version: 1.8.23
114
- signing_key:
115
- specification_version: 3
114
+ rubygems_version: 3.6.2
115
+ specification_version: 4
116
116
  summary: Automatically extract strings from ERB templates and replace with calls to
117
117
  t()
118
118
  test_files: []