diff --git a/lib/i18n/tasks/scanners/relative_keys.rb b/lib/i18n/tasks/scanners/relative_keys.rb index 4c7924c6..6c230e8f 100644 --- a/lib/i18n/tasks/scanners/relative_keys.rb +++ b/lib/i18n/tasks/scanners/relative_keys.rb @@ -9,7 +9,9 @@ module RelativeKeys # @param roots [Array] paths to relative roots # @param calling_method [#call, Symbol, String, false, nil] # @return [String] absolute version of the key - def absolute_key(key, path, roots: config[:relative_roots], calling_method: nil) + def absolute_key(key, path, roots: config[:relative_roots], + exclude_method_name_paths: config[:exclude_method_name_paths], + calling_method: nil) return key unless key.start_with?(DOT) fail 'roots argument is required' unless roots.present? @@ -18,7 +20,12 @@ def absolute_key(key, path, roots: config[:relative_roots], calling_method: nil) fail(CommandError, "Cannot resolve relative key \"#{key}\".\n" \ "Set search.relative_roots in config/i18n-tasks.yml (currently #{roots.inspect})") normalized_path.sub!(root, '') - "#{prefix(normalized_path, calling_method: calling_method)}#{key}" + + if (exclude_method_name_paths || []).map { |p| expand_path(p) }.include?(root) + "#{prefix(normalized_path)}#{key}" + else + "#{prefix(normalized_path, calling_method: calling_method)}#{key}" + end end private @@ -31,12 +38,19 @@ def absolute_key(key, path, roots: config[:relative_roots], calling_method: nil) # @return [String] the closest ancestor root for path, with a trailing {File::SEPARATOR}. def path_root(path, roots) roots.map do |p| - File.expand_path(p) + File::SEPARATOR + expand_path(p) end.sort.reverse_each.detect do |root| path.start_with?(root) end end + # Expand a path and add a trailing {File::SEPARATOR} + # @param [String] path relative path + # @return [String] absolute path, with a trailing {File::SEPARATOR}. + def expand_path(path) + File.expand_path(path) + File::SEPARATOR + end + # @param normalized_path [String] path/relative/to/a/root # @param calling_method [#call, Symbol, String, false, nil] def prefix(normalized_path, calling_method: nil) diff --git a/lib/i18n/tasks/used_keys.rb b/lib/i18n/tasks/used_keys.rb index 5784ce74..c841ee39 100644 --- a/lib/i18n/tasks/used_keys.rb +++ b/lib/i18n/tasks/used_keys.rb @@ -16,6 +16,7 @@ module I18n::Tasks module UsedKeys # rubocop:disable Metrics/ModuleLength SEARCH_DEFAULTS = { paths: %w[app/].freeze, + relative_exclude_method_name_paths: [], relative_roots: %w[app/controllers app/helpers app/mailers app/presenters app/views].freeze, scanners: [ ['::I18n::Tasks::Scanners::RubyAstScanner', { only: %w[*.rb] }], @@ -105,7 +106,7 @@ def search_config def merge_scanner_configs(a, b) a.deep_merge(b).tap do |c| - %i[scanners paths relative_roots].each do |key| + %i[scanners paths relative_exclude_method_name_paths relative_roots].each do |key| c[key] = a[key] if b[key].blank? end %i[exclude].each do |key| diff --git a/spec/relative_keys_spec.rb b/spec/relative_keys_spec.rb index 015d766f..7910a122 100644 --- a/spec/relative_keys_spec.rb +++ b/spec/relative_keys_spec.rb @@ -5,6 +5,10 @@ class RelativeKeysUser include ::I18n::Tasks::Scanners::RelativeKeys + + def config + {} + end end RSpec.describe 'Relative keys' do @@ -102,5 +106,47 @@ class RelativeKeysUser end end end + + context 'using exclude_method_name_paths' do + it 'works' do + key = relative_keys.absolute_key( + '.subject', + 'app/mailers/user_mailer.rb', + roots: %w[app/mailers], + exclude_method_name_paths: %w[app/mailers], + calling_method: 'welcome' + ) + + expect(key).to eq('user_mailer.subject') + end + + context 'multiple words in file name' do + it 'works' do + key = relative_keys.absolute_key( + '.subject', + 'app/mailers/admin_user_mailer.rb', + roots: %w[app/mailers], + exclude_method_name_paths: %w[app/mailers], + calling_method: 'welcome' + ) + + expect(key).to eq('admin_user_mailer.subject') + end + end + + context 'nested in module' do + it 'works' do + key = relative_keys.absolute_key( + '.subject', + 'app/mailers/nested/user_mailer.rb', + roots: %w[app/mailers], + exclude_method_name_paths: %w[app/mailers], + calling_method: 'welcome' + ) + + expect(key).to eq('nested.user_mailer.subject') + end + end + end end end diff --git a/templates/config/i18n-tasks.yml b/templates/config/i18n-tasks.yml index 4a6b27d6..0accdd53 100644 --- a/templates/config/i18n-tasks.yml +++ b/templates/config/i18n-tasks.yml @@ -64,6 +64,13 @@ search: # - app/presenters # - app/views + ## Directories where method names which should not be part of a relative key resolution. + # By default, if a relative translation is used inside a method, the name of the method will be considered part of the resolved key. + # Directories listed here will not consider the name of the method part of the resolved key + # + # relative_exclude_method_name_paths: + # - + ## Files or `File.fnmatch` patterns to exclude from search. Some files are always excluded regardless of this setting: ## %w(*.jpg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less *.yml *.json) exclude: