Only downcase first letter of each auth key, not the entire string (#5822)

A previous change #4834 introduced a downcase call to each attribute, so
that it'd fix an invalid grammar issue on some languages like English
that were showing `Email` in the middle of flash message sentences.

However, it caused a bug with German which uses the word `E-Mail` and at
the beginning of the sentence, causing it to be converted to `E-mail`
incorrectly.

The fix here will only downcase the first char of each word, and convert
it back to upcase at the beginning of the sentence, which should work
for both the original fix (English message), and for the new bug (German
 message)

If we end up running into any more of these edge cases with the message,
we might roll it all back and provide a different set of interpolation
values for the original vs downcased translations, so people can use
what makes the most sense for each language without us having to
manually massage these strings.

Fixes #5820
This commit is contained in:
Carlos Antonio da Silva
2026-02-13 10:11:07 -03:00
committed by GitHub
parent dbc1bb2254
commit 03c419e70c
4 changed files with 25 additions and 1 deletions

View File

@@ -1,3 +1,8 @@
### Unreleased
* bug fixes
* Fix translation issue with German `E-Mail` on invalid authentication messages caused by previous fix for incorrect grammar [#5822](https://github.com/heartcombo/devise/pull/5822)
### 5.0.0 - 2026-01-23
no changes

View File

@@ -112,7 +112,9 @@ module Devise
options[:default] = [message]
auth_keys = scope_class.authentication_keys
human_keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key|
scope_class.human_attribute_name(key).downcase
# TODO: Remove the fallback and just use `downcase_first` once we drop support for Rails 7.0.
human_key = scope_class.human_attribute_name(key)
human_key.respond_to?(:downcase_first) ? human_key.downcase_first : human_key[0].downcase + human_key[1..]
}
options[:authentication_keys] = human_keys.join(I18n.t(:"support.array.words_connector"))
options = i18n_options(options)

View File

@@ -215,6 +215,11 @@ class FailureTest < ActiveSupport::TestCase
assert_equal 'Email ou senha inválidos.', @request.flash[:alert]
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
call_failure('warden' => OpenStruct.new(message: :invalid), 'warden.options' => { locale: :de })
assert_equal 'E-Mail oder Passwort ist ungültig.', @request.flash[:alert]
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
end
test 'uses the proxy failure message as string' do

View File

@@ -0,0 +1,12 @@
de:
activerecord:
attributes:
user:
email: E-Mail
mongoid:
attributes:
user:
email: E-Mail
devise:
failure:
invalid: "%{authentication_keys} oder Passwort ist ungültig."