Problem/Motivation
On a multilingual site, when a new user registers via OpenID Connect, the user entity is always created with the site's default language, regardless of the language the user registered from (e.g. /es/). Additionally, all user-facing status messages (e.g. "Thank you for applying for an account. Your account is currently pending approval by the site administrator.") are rendered in the site default language.
This was partially addressed for 2.x in #3143650 (https://www.drupal.org/project/openid_connect/issues/3143650) (redirect language), but the user entity langcode and status message translation were never fixed and the issue persists in 3.x.
Steps to reproduce
1. Configure a multilingual site with at least two languages (e.g. English as default, Spanish as secondary).
2. Configure language detection via URL path prefix (/en/, /es/).
3. Configure OpenID Connect with a provider (e.g. Google).
4. Set registration to "Visitors, but administrator approval is required".
5. Navigate to the login page under /es/ and authenticate via OpenID Connect as a new user.
6. Check the newly created user's langcode and preferred_langcode fields.
7. Observe the status message displayed after registration.
Expected result: The user entity has langcode: es and preferred_langcode: es. The status message is displayed in Spanish.
Actual result: The user entity has langcode: en and preferred_langcode: en. The status message is displayed in English.
Proposed resolution
Root cause: The OAuth callback URL (/openid-connect/{client}) has no language path prefix, so Drupal negotiates the content language to the site default for the entire duration of completeAuthorization(). This causes two issues:
1. OpenIDConnect::createUser() does not include langcode in the $account_data array passed to externalAuth->register(), so the user entity is created with the site default language. The langcode and preferred_langcode fields are explicitly listed in userPropertiesIgnore() and are never set during saveUserinfo().
2. All $this->t() calls inside completeAuthorization() (e.g. the "Thank you for applying" message) are translated to the negotiated language (en), not the user's original language. Note: OpenIDConnectSession::saveDestination() does save openid_connect_langcode to the session before the redirect, but it is consumed by retrieveDestination() before the redirect controller renders the page, and completeAuthorization() runs before that point.
Two possible approaches:
1. In OpenIDConnect::createUser(), read the langcode from the session (openid_connect_langcode, already saved by OpenIDConnectSession::saveDestination()) and include it in $account_data. This ensures the user entity is created with the correct language.
2. In OpenIDConnect::completeAuthorization(), temporarily set the content language from the session before calling createUser() and any $this->t() calls, then restore it. This would fix both the user langcode and the status messages in one place.
Remaining tasks
- Decide on the approach (or a combination of both).
- Create a patch.
- Add test coverage for multilingual user registration.
User interface changes
None. Status messages would be correctly translated, and the user's language preference would match the registration language.
API changes
None.
Data model changes
None. The langcode and preferred_langcode fields already exist on the user entity.
| Comment | File | Size | Author |
|---|---|---|---|
| #4 | openid_connect-3584014-2.patch | 7.17 KB | alekas |
Comments
Comment #2
alekas commentedApproach:
Why not override the negotiated language globally?
Changing the content language via ConfigurableLanguageManager::reset() or similar approaches is fragile and can have unintended side effects (affecting config overrides, cache contexts, etc.). Passing the langcode explicitly to the two places that need it ($this->t() options and $account_data) is minimal, safe, and has zero side effects on non-multilingual sites.
Tested against: 3.0.0-alpha8
Comment #3
alekas commentedComment #4
alekas commentedAttached a revised patch that uses proper git diff format with relative paths. This replaces the previous attachment.
Changes in this version: