Skip to content

Commit

Permalink
Merge branch 'master' into interpolate_documentation_syntax_fix
Browse files Browse the repository at this point in the history
* master:
  Remove unnecessary line
  Use left recursion
  Optimize I18n::Locale::Fallbacks#compute
  Fix example doc
  More examples documented
  Modify behaviour for Hash and (maybe nested) Array translations
  Add tests and error handling for non-string translations
  racc has been extracted to a gem since Ruby 3.3
  Add I18n.interpolation_keys
  • Loading branch information
radar committed May 6, 2024
2 parents b0f1e1c + 73fd07e commit 305edf4
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 3 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ gem 'test_declarative', '0.0.6'
gem 'rake', '~> 13'
gem 'minitest', '~> 5.14'
gem 'json'
gem 'racc'
1 change: 1 addition & 0 deletions gemfiles/Gemfile.rails-6.0.x
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'mocha', '~> 2.1.0'
gem 'test_declarative', '0.0.6'
gem 'rake'
gem 'minitest', '~> 5.14'
gem 'racc'

platforms :mri do
gem 'oj'
Expand Down
1 change: 1 addition & 0 deletions gemfiles/Gemfile.rails-6.1.x
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'mocha', '~> 2.1.0'
gem 'test_declarative', '0.0.6'
gem 'rake'
gem 'minitest', '~> 5.14'
gem 'racc'

platforms :mri do
gem 'oj'
Expand Down
1 change: 1 addition & 0 deletions gemfiles/Gemfile.rails-7.0.x
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'mocha', '~> 2.1.0'
gem 'test_declarative', '0.0.6'
gem 'rake'
gem 'minitest', '~> 5.14'
gem 'racc'

platforms :mri do
gem 'oj'
Expand Down
1 change: 1 addition & 0 deletions gemfiles/Gemfile.rails-7.1.x
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'mocha', '~> 2'
gem 'test_declarative', '0.0.6'
gem 'rake'
gem 'minitest', '~> 5.14'
gem 'racc'

platforms :mri do
gem 'oj'
Expand Down
1 change: 1 addition & 0 deletions gemfiles/Gemfile.rails-main
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'mocha', '~> 2.1.0'
gem 'test_declarative', '0.0.6'
gem 'rake'
gem 'minitest', '~> 5.1'
gem 'racc'

platforms :mri do
gem 'oj'
Expand Down
40 changes: 40 additions & 0 deletions lib/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,35 @@ def translate!(key, **options)
end
alias :t! :translate!

# Returns an array of interpolation keys for the given translation key
#
# *Examples*
#
# Suppose we have the following:
# I18n.t 'example.zero' == 'Zero interpolations'
# I18n.t 'example.one' == 'One interpolation %{foo}'
# I18n.t 'example.two' == 'Two interpolations %{foo} %{bar}'
# I18n.t 'example.three' == ['One %{foo}', 'Two %{bar}', 'Three %{baz}']
# I18n.t 'example.one', locale: :other == 'One interpolation %{baz}'
#
# Then we can expect the following results:
# I18n.interpolation_keys('example.zero') #=> []
# I18n.interpolation_keys('example.one') #=> ['foo']
# I18n.interpolation_keys('example.two') #=> ['foo', 'bar']
# I18n.interpolation_keys('example.three') #=> ['foo', 'bar', 'baz']
# I18n.interpolation_keys('one', scope: 'example', locale: :other) #=> ['baz']
# I18n.interpolation_keys('does-not-exist') #=> []
# I18n.interpolation_keys('example') #=> []
def interpolation_keys(key, **options)
raise I18n::ArgumentError if !key.is_a?(String) || key.empty?

return [] unless exists?(key, **options.slice(:locale, :scope))

translation = translate(key, **options.slice(:locale, :scope))
interpolation_keys_from_translation(translation)
.flatten.compact
end

# Returns true if a translation exists for a given key, otherwise returns false.
def exists?(key, _locale = nil, locale: _locale, **options)
locale ||= config.locale
Expand Down Expand Up @@ -429,6 +458,17 @@ def normalize_key(key, separator)
keys
end
end

def interpolation_keys_from_translation(translation)
case translation
when ::String
translation.scan(Regexp.union(I18n.config.interpolation_patterns))
when ::Array
translation.map { |element| interpolation_keys_from_translation(element) }
else
[]
end
end
end

extend Base
Expand Down
8 changes: 5 additions & 3 deletions lib/i18n/locale/fallbacks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@ def inspect
protected

def compute(tags, include_defaults = true, exclude = [])
result = Array(tags).flat_map do |tag|
result = []
Array(tags).each do |tag|
tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] }
tags
result += tags
tags.each { |_tag| result += compute(@map[_tag], false, exclude + result) if @map[_tag] }
end

result.push(*defaults) if include_defaults
result.uniq!
result.compact!
Expand Down
28 changes: 28 additions & 0 deletions test/i18n_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,34 @@ def setup
assert_equal I18n.config.available_locales.size * 2, I18n.config.available_locales_set.size
end

test "interpolation_keys returns an array of keys" do
store_translations(:en, "example_two" => "Two interpolations %{foo} %{bar}")
assert_equal ["foo", "bar"], I18n.interpolation_keys("example_two")
end

test "interpolation_keys returns an empty array when no interpolations " do
store_translations(:en, "example_zero" => "Zero interpolations")
assert_equal [], I18n.interpolation_keys("example_zero")
end

test "interpolation_keys returns an empty array when missing translation " do
assert_equal [], I18n.interpolation_keys("does-not-exist")
end

test "interpolation_keys returns an empty array when nested translation" do
store_translations(:en, "example_nested" => { "one" => "One %{foo}", "two" => "Two %{bar}" })
assert_equal [], I18n.interpolation_keys("example_nested")
end

test "interpolation_keys returns an array of keys when translation is an Array" do
store_translations(:en, "example_array" => ["One %{foo}", ["Two %{bar}", ["Three %{baz}"]]])
assert_equal ["foo", "bar", "baz"], I18n.interpolation_keys("example_array")
end

test "interpolation_keys raises I18n::ArgumentError when non-string argument" do
assert_raises(I18n::ArgumentError) { I18n.interpolation_keys(["bad-argument"]) }
end

test "exists? given an existing key will return true" do
assert_equal true, I18n.exists?(:currency)
end
Expand Down

0 comments on commit 305edf4

Please sign in to comment.