Class: Keela::Strategies::I18nKeys
- Inherits:
-
Keela::Strategy
- Object
- Keela::Strategy
- Keela::Strategies::I18nKeys
- Defined in:
- lib/keela/strategies/i18n_keys.rb
Overview
Detects unused I18n translation keys in locale files.
Definitions are extracted from YAML locale files (config/locales/*.yml) and flattened to dot notation (e.g., "users.show.title").
Usage is detected by searching for:
- I18n.t("key") or I18n.t('key')
- t("key") or t('key')
- t(:key)
- .human_attribute_name(:attr)
Pluralization keys (zero, one, two, few, many, other) are grouped: if t("items.count", count: n) is called, all siblings are considered used.
Lazy lookup is supported: t('.title') in app/views/users/show.html.erb resolves to 'users.show.title'.
Constant Summary collapse
- PLURAL_SUFFIXES =
%w[zero one two few many other].freeze
- VIEW_PATH_REGEX =
%r{(?:ee/)?app/views/(.+)\.html\.(?:erb|haml|slim)$}.freeze
- LAZY_LOOKUP_REGEX =
/(?:I18n\.)?t\s*\(\s*['"](\.[^'"]+)['"]/
Instance Method Summary collapse
-
#additional_used_names(source_files) ⇒ Object
Build a set of expanded lazy lookup keys from view files Called by the scanner to detect usage via lazy lookup.
- #default_definition_file_pattern ⇒ Object
- #extract_definition(_line) ⇒ Object
-
#extract_definitions_from_file(filepath, _lines) ⇒ Object
Override: I18n keys need special YAML parsing, not line-by-line.
-
#extract_lazy_keys(content) ⇒ Object
Extract lazy lookup keys from view content Returns array of keys like [".title", ".description"].
- #name ⇒ Object
- #skip_comments? ⇒ Boolean
- #usage_regex(name) ⇒ Object
-
#view_path_to_prefix(path) ⇒ Object
Convert a view file path to its I18n prefix "app/views/users/show.html.erb" -> "users.show" "app/views/users/_form.html.erb" -> "users.form" "ee/app/views/users/show.html.erb" -> "users.show".
Methods inherited from Keela::Strategy
Instance Method Details
#additional_used_names(source_files) ⇒ Object
Build a set of expanded lazy lookup keys from view files Called by the scanner to detect usage via lazy lookup
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/keela/strategies/i18n_keys.rb', line 120 def additional_used_names(source_files) = Set.new source_files.each do |filepath, lines| prefix = view_path_to_prefix(filepath) next unless prefix content = lines.join("\n") lazy_keys = extract_lazy_keys(content) lazy_keys.each do |lazy_key| # .title -> users.show.title full_key = "#{prefix}#{lazy_key}" << full_key end end end |
#default_definition_file_pattern ⇒ Object
32 33 34 35 |
# File 'lib/keela/strategies/i18n_keys.rb', line 32 def default_definition_file_pattern # Match locale YAML files %r{config/locales/.*\.ya?ml$} end |
#extract_definition(_line) ⇒ Object
61 62 63 64 |
# File 'lib/keela/strategies/i18n_keys.rb', line 61 def extract_definition(_line) # Not used - we override extract_definitions_from_file instead nil end |
#extract_definitions_from_file(filepath, _lines) ⇒ Object
Override: I18n keys need special YAML parsing, not line-by-line
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/keela/strategies/i18n_keys.rb', line 38 def extract_definitions_from_file(filepath, _lines) return [] unless File.exist?(filepath) content = YAML.load_file(filepath, permitted_classes: [Symbol]) || {} keys = flatten_keys(content).map do |key| # Remove the locale prefix (e.g., "en.users.show" -> "users.show") key.sub(/^[a-z]{2}(-[A-Z]{2})?\./, "") end # For pluralization keys, also add the parent key so that # t("items.count", count: n) marks all siblings as used parent_keys = keys.filter_map do |key| parent_key_for_pluralization(key) end.uniq (keys + parent_keys).uniq.map do |key| { name: key, file: filepath } end rescue Psych::SyntaxError => e warn "Warning: Could not parse #{filepath}: #{e.}" [] end |
#extract_lazy_keys(content) ⇒ Object
Extract lazy lookup keys from view content Returns array of keys like [".title", ".description"]
114 115 116 |
# File 'lib/keela/strategies/i18n_keys.rb', line 114 def extract_lazy_keys(content) content.scan(LAZY_LOOKUP_REGEX).flatten end |
#name ⇒ Object
28 29 30 |
# File 'lib/keela/strategies/i18n_keys.rb', line 28 def name "i18n_keys" end |
#skip_comments? ⇒ Boolean
90 91 92 |
# File 'lib/keela/strategies/i18n_keys.rb', line 90 def skip_comments? true end |
#usage_regex(name) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/keela/strategies/i18n_keys.rb', line 66 def usage_regex(name) # Match various I18n lookup patterns: # I18n.t("users.show.title") # I18n.t('users.show.title') # t("users.show.title") # t('users.show.title') # t(:users_show_title) - symbol form (underscored) # # For pluralization keys, also match the parent key: # t("items.count", count: n) should match items.count.one, items.count.other, etc. quoted_name = Regexp.quote(name) # Check if this is a pluralization key and build alternate pattern parent_key = parent_key_for_pluralization(name) if parent_key quoted_parent = Regexp.quote(parent_key) # Match either the exact key OR the parent key /(?:I18n\.)?t\s*\(\s*["':]+(?:#{quoted_name}|#{quoted_parent})["']?\s*[,)]/ else # Build pattern that matches the key in quotes or as a symbol /(?:I18n\.)?t\s*\(\s*["':]+#{quoted_name}["']?\s*[,)]/ end end |
#view_path_to_prefix(path) ⇒ Object
Convert a view file path to its I18n prefix "app/views/users/show.html.erb" -> "users.show" "app/views/users/_form.html.erb" -> "users.form" "ee/app/views/users/show.html.erb" -> "users.show"
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/keela/strategies/i18n_keys.rb', line 98 def view_path_to_prefix(path) return nil unless path =~ VIEW_PATH_REGEX view_path = Regexp.last_match(1) # Split into parts and process parts = view_path.split("/") # Handle partials: _form -> form parts[-1] = parts[-1].sub(/^_/, "") parts.join(".") end |