auto-l18n 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e1461d71a3c1c714d84295c11605c26cb984a8939c07f265c61489036a1cc58
4
- data.tar.gz: c5805b85181f8e87a65a25371c651d4cf936084e9c67d1e2e1c49e09e8934a45
3
+ metadata.gz: d827a80d2d978e8855592c2fe411c97f169a5c44b59d2a7e3a87da698bad39ad
4
+ data.tar.gz: 82096e37eb8ad1dad0473c5762c1cd04b5e2f078b952747212bc84656bbacab8
5
5
  SHA512:
6
- metadata.gz: d33f864be73e4bfa056f17d1897e581e2f8456d93a307871e7173ee19c995f7d09c426af5c8d82b5e77e22d6ede15286aa952525ad46ed2ff444896944e5f825
7
- data.tar.gz: 3868fec113b95cd2d64f0e371630c58e27854792dc5b98462d2d1fbe13c55c40cdfd56880464b65b150b39f97c2c74a753cbd0ba0de75c2737bda64274200d2a
6
+ metadata.gz: b5cbf6914f5e5c1ae1c42d3f7a18895596b621280eee99071110234c878279096d49a226886b6f8a3a9c583fec8ef55c06d5652c18779fe8d2e63d978d58aa58
7
+ data.tar.gz: 945cb23e8fd293d78a81e89a717f3aea3ebfac24358b84df5bc0ac10bd36c765ecb681b8f49090b1888e2e1fa2a5d38ceacb1a3e792661f643d8470b2699bc1a
data/README.md CHANGED
@@ -50,7 +50,7 @@ texts.each { |t| puts "- #{t}" }
50
50
  # Preview changes (dry run)
51
51
  result = Auto::L18n.auto_internationalize(
52
52
  "app/views/posts/show.html.erb",
53
- namespace: "views.posts.show",
53
+ # namespace: "views.posts.show", # Optional – will be derived from the file path if omitted
54
54
  dry_run: true
55
55
  )
56
56
 
@@ -58,8 +58,7 @@ puts "Would replace #{result[:total_replaced]} strings"
58
58
 
59
59
  # Apply changes
60
60
  result = Auto::L18n.auto_internationalize(
61
- "app/views/posts/show.html.erb",
62
- namespace: "views.posts.show"
61
+ "app/views/posts/show.html.erb"
63
62
  )
64
63
  ```
65
64
 
@@ -70,12 +69,13 @@ result = Auto::L18n.auto_internationalize(
70
69
  ruby exe/auto-l18n app/views/posts/show.html.erb
71
70
 
72
71
  # Replace with I18n calls (dry run)
72
+ # Note: If --namespace is omitted, it will be derived from the file path (e.g., app/views/admin/users/show.html.erb -> views.admin.users.show)
73
73
  ruby exe/auto-l18n app/views/posts/show.html.erb \
74
- --replace --namespace views.posts.show --dry-run
74
+ --replace --dry-run
75
75
 
76
76
  # Actually apply changes
77
77
  ruby exe/auto-l18n app/views/posts/show.html.erb \
78
- --replace --namespace views.posts.show
78
+ --replace
79
79
  ```
80
80
 
81
81
  ## Example Transformation
@@ -178,7 +178,7 @@ Options:
178
178
  --ext=EXTS File extensions (default: .html.erb)
179
179
  --replace Replace hardcoded text with I18n calls
180
180
  --locale-path=PATH Locale file path (default: config/locales/en.yml)
181
- --namespace=NS Translation key namespace (e.g., views.posts)
181
+ --namespace=NS Translation key namespace (e.g., views.posts). If omitted, it is derived from the file path (folder hierarchy).
182
182
  --dry-run Preview changes without modifying files
183
183
  --no-backup Don't create backup files
184
184
  -h, --help Show help
data/exe/auto-l18n CHANGED
@@ -42,7 +42,7 @@ parser = OptionParser.new do |opts|
42
42
  options[:locale_path] = path
43
43
  end
44
44
 
45
- opts.on("--namespace=NS", "Namespace for translation keys (e.g., views.posts)") do |ns|
45
+ opts.on("--namespace=NS", "Namespace for translation keys (e.g., views.posts). If omitted, it is derived from the file path (folder hierarchy).") do |ns|
46
46
  options[:namespace] = ns
47
47
  end
48
48
 
@@ -101,16 +101,47 @@ if paths.empty?
101
101
  end
102
102
 
103
103
  if options[:mode] == "find"
104
- # Original behavior: find and list hardcoded text
104
+ # Find and list hardcoded text; in --dry-run also show the keys that would be used
105
105
  total = 0
106
106
  paths.each do |p|
107
107
  found = Auto::L18n.find_text(p)
108
108
  next if found.empty?
109
109
 
110
- total += found.size
111
110
  puts "\nFile: #{p}"
112
- found.each do |s|
113
- puts " - #{s}"
111
+ # List found strings
112
+ total += found.size
113
+ found.each { |s| puts " - #{s}" }
114
+
115
+ # In dry-run, show the keys that would be used for replacement
116
+ if options[:dry_run]
117
+ structured = Auto::L18n.find_text(p, structured: true)
118
+ # mimic the sort used by exchange_text_for_l18n_placeholder (by line desc)
119
+ sorted = structured.sort_by { |f| -(f.line || 0) }
120
+
121
+ # Determine effective namespace as in the library code
122
+ effective_ns = options[:namespace]
123
+ if (effective_ns.nil? || effective_ns.empty?)
124
+ # Call private helper via send to derive from path
125
+ begin
126
+ effective_ns = Auto::L18n.send(:derive_namespace_from_path, p, {})
127
+ effective_ns = nil if effective_ns.nil? || effective_ns.empty?
128
+ rescue NoMethodError
129
+ # Fallback: no derived namespace available
130
+ effective_ns = options[:namespace]
131
+ end
132
+ end
133
+
134
+ keys = sorted.each_with_index.map do |f, idx|
135
+ begin
136
+ Auto::L18n.send(:generate_translation_key, f.text, f.type, effective_ns, idx)
137
+ rescue NoMethodError
138
+ # Extremely unlikely; just show placeholder when method not accessible
139
+ "generated_key_#{idx}"
140
+ end
141
+ end
142
+
143
+ puts " Keys that would be used:"
144
+ keys.each { |k| puts " - #{k}" }
114
145
  end
115
146
  end
116
147
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Auto
4
4
  module L18n
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
data/lib/auto/l18n.rb CHANGED
@@ -424,7 +424,7 @@ module Auto
424
424
  results
425
425
  end
426
426
 
427
- # Exchange hardcoded text for I18n placeholders
427
+ # Exchange hardcoded text for I18n placeholders
428
428
  #
429
429
  # This method replaces hardcoded strings in a file with I18n translation calls
430
430
  # and adds the translations to a locale file (default: en.yml).
@@ -440,7 +440,7 @@ module Auto
440
440
  # @option options [Boolean] :backup (true) Create backup files before modifying
441
441
  #
442
442
  # @return [Hash] Summary of changes made
443
- def self.exchange_text_for_l18n_placeholder(path, options = {})
443
+ def self.exchange_text_for_l18n_placeholder(path, options = {})
444
444
  raise ArgumentError, "path must be a String" unless path.is_a?(String)
445
445
  raise ArgumentError, "File not found: #{path}" unless File.file?(path)
446
446
 
@@ -449,6 +449,9 @@ module Auto
449
449
  locale_path: "config/locales/en.yml",
450
450
  locale: "en",
451
451
  namespace: nil,
452
+ namespace_from_path: true, # derive namespace from folder/file path when none provided
453
+ path_root: nil, # optional root to strip (e.g., "app/views")
454
+ namespace_prefix: nil, # optional prefix to prepend (e.g., "views")
452
455
  dry_run: false,
453
456
  min_length: 2,
454
457
  ignore_patterns: [],
@@ -474,9 +477,17 @@ module Auto
474
477
  # Process findings in reverse order by position to maintain string positions
475
478
  sorted_findings = findings.sort_by { |f| -(f.line || 0) }
476
479
 
480
+ # Determine effective namespace: user-provided or derived from file path
481
+ effective_namespace = opts[:namespace]
482
+ if (effective_namespace.nil? || effective_namespace.empty?) && opts[:namespace_from_path]
483
+ effective_namespace = derive_namespace_from_path(path, opts)
484
+ # Normalize to nil if empty
485
+ effective_namespace = nil if effective_namespace.nil? || effective_namespace.empty?
486
+ end
487
+
477
488
  sorted_findings.each_with_index do |finding, idx|
478
489
  # Generate translation key
479
- key = generate_translation_key(finding.text, finding.type, opts[:namespace], idx)
490
+ key = generate_translation_key(finding.text, finding.type, effective_namespace, idx)
480
491
 
481
492
  # Add to locale file
482
493
  set_nested_key(locale_data, key, finding.text, opts[:locale])
@@ -603,6 +614,64 @@ module Auto
603
614
  parts.join('.')
604
615
  end
605
616
 
617
+ # Derive a namespace from the file path, producing a dotted hierarchy
618
+ # Examples:
619
+ # - app/views/admin/users/show.html.erb -> "views.admin.users.show"
620
+ # - app/views/posts/index.html.erb -> "views.posts.index"
621
+ # - src/templates/home.html.erb (with namespace_prefix: nil) -> "src.templates.home"
622
+ # - test/test.html.erb (no root) -> "test.test"
623
+ def self.derive_namespace_from_path(path, options = {})
624
+ require 'pathname'
625
+ abs_path = File.expand_path(path)
626
+
627
+ # Resolve root to strip
628
+ root = options[:path_root]
629
+ prefix = options[:namespace_prefix]
630
+
631
+ # Auto-detect common Rails views root and default prefix
632
+ if root.nil? && abs_path.include?(File.join('app', 'views'))
633
+ root = abs_path.split(File.join('app', 'views')).first + File.join('app', 'views')
634
+ prefix ||= 'views'
635
+ end
636
+
637
+ rel_path = nil
638
+ if root && abs_path.start_with?(File.expand_path(root) + File::SEPARATOR)
639
+ rel_path = Pathname.new(abs_path).relative_path_from(Pathname.new(File.expand_path(root))).to_s
640
+ else
641
+ # Try relative to current working directory
642
+ cwd = Dir.pwd
643
+ if abs_path.start_with?(cwd + File::SEPARATOR)
644
+ rel_path = abs_path.sub(cwd + File::SEPARATOR, '')
645
+ else
646
+ rel_path = File.basename(abs_path)
647
+ end
648
+ end
649
+
650
+ # Remove all extensions (handle multi-extensions like .html.erb)
651
+ base = rel_path.dup
652
+ loop do
653
+ ext = File.extname(base)
654
+ break if ext.nil? || ext.empty?
655
+ base = base.chomp(ext)
656
+ end
657
+
658
+ # Split into segments, normalize, and join with dots
659
+ segments = base.split(File::SEPARATOR).map do |seg|
660
+ seg.downcase
661
+ .gsub(/[^\w\-\.]+/, '_')
662
+ .gsub(/[\-\.]/, '_')
663
+ .gsub(/_+/, '_')
664
+ .gsub(/^_|_$/, '')
665
+ end.reject(&:empty?)
666
+
667
+ derived = segments.join('.')
668
+ if prefix && !prefix.to_s.empty?
669
+ [prefix, derived].reject(&:empty?).join('.')
670
+ else
671
+ derived
672
+ end
673
+ end
674
+
606
675
  # Load locale file (YAML)
607
676
  def self.load_locale_file(path, locale)
608
677
  if File.exist?(path)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: auto-l18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Reiner