Skip to content

Commit f2cd46b

Browse files
authored
Merge pull request rails#35424 from Korri/validation-rules-locale-fallback
Fall back to parent locale before falling back to the :errors namespace
2 parents 9624241 + 9ccc5e1 commit f2cd46b

File tree

3 files changed

+56
-11
lines changed

3 files changed

+56
-11
lines changed

activemodel/CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
2+
* Changed how validation error translation strings are fetched: The new behaviour
3+
will first try the more specific keys, including doing locale fallback, then try
4+
the less specific ones.
5+
6+
For example this is the order keys will now be tried for a `blank` error on a
7+
`product`'s `title` attribute with current locale set to `en-US`:
8+
9+
en-US.activerecord.errors.models.product.attributes.title.blank
10+
en-US.activerecord.errors.models.product.blank
11+
en-US.activerecord.errors.messages.blank
12+
13+
en.activerecord.errors.models.product.attributes.title.blank
14+
en.activerecord.errors.models.product.blank
15+
en.activerecord.errors.messages.blank
16+
17+
en-US.errors.attributes.title.blank
18+
en-US.errors.messages.blank
19+
20+
en.errors.attributes.title.blank
21+
en.errors.messages.blank
22+
23+
*Hugo Vacher*
24+
125
## Rails 6.0.0.beta2 (February 25, 2019) ##
226

327
* Fix date value when casting a multiparameter date hash to not convert

activemodel/lib/active_model/errors.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@ def full_message(attribute, message)
479479
# * <tt>errors.messages.blank</tt>
480480
def generate_message(attribute, type = :invalid, options = {})
481481
type = options.delete(:message) if options[:message].is_a?(Symbol)
482+
value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
483+
484+
options = {
485+
model: @base.model_name.human,
486+
attribute: @base.class.human_attribute_name(attribute),
487+
value: value,
488+
object: @base
489+
}.merge!(options)
482490

483491
if @base.class.respond_to?(:i18n_scope)
484492
i18n_scope = @base.class.i18n_scope.to_s
@@ -487,6 +495,11 @@ def generate_message(attribute, type = :invalid, options = {})
487495
:"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
488496
end
489497
defaults << :"#{i18n_scope}.errors.messages.#{type}"
498+
499+
catch(:exception) do
500+
translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true))
501+
return translation unless translation.nil?
502+
end unless options[:message]
490503
else
491504
defaults = []
492505
end
@@ -496,15 +509,7 @@ def generate_message(attribute, type = :invalid, options = {})
496509

497510
key = defaults.shift
498511
defaults = options.delete(:message) if options[:message]
499-
value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
500-
501-
options = {
502-
default: defaults,
503-
model: @base.model_name.human,
504-
attribute: @base.class.human_attribute_name(attribute),
505-
value: value,
506-
object: @base
507-
}.merge!(options)
512+
options[:default] = defaults
508513

509514
I18n.translate(key, options)
510515
end

activerecord/test/cases/validations/i18n_generate_message_validation_test.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44
require "models/topic"
55

66
class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
7+
class Backend < I18n::Backend::Simple
8+
include I18n::Backend::Fallbacks
9+
end
10+
711
def setup
812
Topic.clear_validators!
913
@topic = Topic.new
10-
I18n.backend = I18n::Backend::Simple.new
14+
I18n.backend = Backend.new
1115
end
1216

1317
def reset_i18n_load_path
1418
@old_load_path, @old_backend = I18n.load_path.dup, I18n.backend
1519
I18n.load_path.clear
16-
I18n.backend = I18n::Backend::Simple.new
20+
I18n.backend = Backend.new
1721
yield
1822
ensure
1923
I18n.load_path.replace @old_load_path
@@ -83,4 +87,16 @@ def test_generate_message_taken_with_custom_message
8387
assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title")
8488
end
8589
end
90+
91+
test "activerecord attributes scope falls back to parent locale before it falls back to the :errors namespace" do
92+
reset_i18n_load_path do
93+
I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { attributes: { title: { taken: "custom en message" } } } } } }
94+
I18n.backend.store_translations "en-US", errors: { messages: { taken: "generic en-US fallback" } }
95+
96+
I18n.with_locale "en-US" do
97+
assert_equal "custom en message", @topic.errors.generate_message(:title, :taken, value: "title")
98+
assert_equal "generic en-US fallback", @topic.errors.generate_message(:heading, :taken, value: "heading")
99+
end
100+
end
101+
end
86102
end

0 commit comments

Comments
 (0)