Skip to content

Commit fc46631

Browse files
Ensure auth keys at the start of the i18n msg are properly cased
Otherwise if we humanized the whole string, it could cause us to change the output of strings with periods and maybe other side-effects, since we're changing the whole string from i18n. This is safer as it only changes the first char of the translated message, and only if it is a match with the first translated auth key, so we can more safely humanize & downcase all auth keys to interpolate in the message whenever needed. Also add changelog for the change.
1 parent 356b094 commit fc46631

File tree

2 files changed

+10
-6
lines changed

2 files changed

+10
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
* Fix passing `format` option to `devise_for` [#5732](https://github.com/heartcombo/devise/pull/5732)
5555
* Use `ActiveRecord::SecurityUtils.secure_compare` in `Devise.secure_compare` to match two empty strings correctly. [#4829](https://github.com/heartcombo/devise/pull/4829)
5656
* Respond with `401 Unauthorized` for non-navigational requests to destroy the session when there is no authenticated resource. [#4878](https://github.com/heartcombo/devise/pull/4878)
57+
* Fix incorrect grammar of invalid authentication message with capitalized attributes, e.g.: "Invalid Email or password" => "Invalid email or password". (originally introduced by [#4014](https://github.com/heartcombo/devise/pull/4014), released on v4.1.0) [#4834](https://github.com/heartcombo/devise/pull/4834)
5758
5859
5960
Please check [4-stable](https://github.com/heartcombo/devise/blob/4-stable/CHANGELOG.md)

lib/devise/failure_app.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,16 @@ def i18n_message(default = nil)
111111
options[:scope] = "devise.failure"
112112
options[:default] = [message]
113113
auth_keys = scope_class.authentication_keys
114-
keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key).downcase }
115-
options[:authentication_keys] = keys.join(I18n.t(:"support.array.words_connector"))
114+
human_keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key|
115+
scope_class.human_attribute_name(key).downcase
116+
}
117+
options[:authentication_keys] = human_keys.join(I18n.t(:"support.array.words_connector"))
116118
options = i18n_options(options)
117-
translated_message = I18n.t(:"#{scope}.#{message}", **options)
118-
# only call `#humanize` when the message is `:invalid` to ensure the original format
119-
# of other messages - like `:does_not_exist` - is kept.
120-
message == :invalid ? translated_message.humanize : translated_message
119+
120+
I18n.t(:"#{scope}.#{message}", **options).then { |msg|
121+
# Ensure that auth keys at the start of the translated string are properly cased.
122+
msg.start_with?(human_keys.first) ? msg.upcase_first : msg
123+
}
121124
else
122125
message.to_s
123126
end

0 commit comments

Comments
 (0)