From 29a5d6ae5096fe3bdca230db803ec97446c5d62b Mon Sep 17 00:00:00 2001 From: Christian Beeznest Date: Wed, 6 Aug 2025 18:23:53 -0500 Subject: [PATCH 1/3] User: Fix signup notification translations - refs #22823 --- public/main/inc/lib/usermanager.lib.php | 20 ++++++++--- ...t_registration_platform_to_admin.html.twig | 34 +++++++++++++------ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/public/main/inc/lib/usermanager.lib.php b/public/main/inc/lib/usermanager.lib.php index 8531b7db619..e8029127e4b 100644 --- a/public/main/inc/lib/usermanager.lib.php +++ b/public/main/inc/lib/usermanager.lib.php @@ -14,6 +14,7 @@ use Chamilo\CoreBundle\Event\UserCreatedEvent; use Chamilo\CoreBundle\Event\UserUpdatedEvent; use Chamilo\CoreBundle\Framework\Container; +use Chamilo\CoreBundle\Repository\LanguageRepository; use Chamilo\CoreBundle\Repository\Node\UserRepository; use Chamilo\CoreBundle\Helpers\NameConventionHelper; use ChamiloSession as Session; @@ -548,12 +549,21 @@ public static function create_user( $form->removeElement('pass2'); $formData = $form->returnForm(); $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId(); + + /** @var LanguageRepository $langRepo */ + $langRepo = Container::$container->get(LanguageRepository::class); + $languageEntity = $langRepo->findOneBy(['isocode' => $user->getLocale()]); + + $userLanguageName = $languageEntity + ? $languageEntity->getOriginalName() + : $user->getLocale(); + $params = [ - 'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)), - 'user_added' => $user, - 'link' => Display::url($url, $url), - 'form' => $formData, - 'user_language' => $user->getLocale(), + 'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)), + 'user_added' => $user, + 'link' => Display::url($url, $url), + 'form' => $formData, + 'user_language' => $userLanguageName, ]; $emailBody = $tpl->render( '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig', diff --git a/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig b/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig index 715d2e75207..e781714a1e6 100644 --- a/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig +++ b/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig @@ -1,15 +1,27 @@ {% autoescape false %} -

{{ 'User %s with language %s registered to the site'|trans|format(complete_name, user_language) }}

-

{{ 'His profile is'|trans }}

-
-
-
- {{ form }} +

+ {{ 'User %s with language %s registered to the site' + |trans({}, 'messages', locale) + |format(complete_name, user_language) + }} +

+

+ {{ 'His profile is' + |trans({}, 'messages', locale) + }} +

+
+
+
+ {{ form }} +
-
- -

{{ 'You can assign a tutor in this link %s'|trans|format(link)}}

- -{% include '@ChamiloCore/Mailer/Legacy/_admin_signature_footer.html.twig' %} +

+ {{ 'You can assign a tutor in this link %s' + |trans({}, 'messages', locale) + |format(link) + }} +

+ {% include '@ChamiloCore/Mailer/Legacy/_admin_signature_footer.html.twig' %} {% endautoescape %} From 5b087fc1e62ecb4238ba9dfcc01036547d61188a Mon Sep 17 00:00:00 2001 From: Christian Beeznest Date: Thu, 7 Aug 2025 15:55:19 -0500 Subject: [PATCH 2/3] User: Translate notification body using recipient locale from registration - refs BT#22823 --- public/main/inc/lib/usermanager.lib.php | 94 ++++++++++--------- ...t_registration_platform_to_admin.html.twig | 24 ++--- 2 files changed, 56 insertions(+), 62 deletions(-) diff --git a/public/main/inc/lib/usermanager.lib.php b/public/main/inc/lib/usermanager.lib.php index e8029127e4b..51099b79306 100644 --- a/public/main/inc/lib/usermanager.lib.php +++ b/public/main/inc/lib/usermanager.lib.php @@ -19,6 +19,7 @@ use Chamilo\CoreBundle\Helpers\NameConventionHelper; use ChamiloSession as Session; use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Contracts\Translation\TranslatorInterface; /** * This library provides functions for user management. @@ -535,59 +536,64 @@ public static function create_user( } } + /** @var TranslatorInterface $translator */ + $translator = Container::$container->get('translator'); + $currentTranslatorLang = $translator->getLocale(); + if ($sendEmailToAllAdmins) { $adminList = self::get_all_administrators(); - // variables for the default template - $renderer = FormValidator::getDefaultRenderer(); - // Form template - $elementTemplate = ' {label}: {element}
'; - $renderer->setElementTemplate($elementTemplate); - /** @var FormValidator $form */ - $form->freeze(null, $elementTemplate); - $form->removeElement('submit'); - $form->removeElement('pass1'); - $form->removeElement('pass2'); - $formData = $form->returnForm(); - $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId(); - - /** @var LanguageRepository $langRepo */ - $langRepo = Container::$container->get(LanguageRepository::class); - $languageEntity = $langRepo->findOneBy(['isocode' => $user->getLocale()]); - - $userLanguageName = $languageEntity - ? $languageEntity->getOriginalName() - : $user->getLocale(); - - $params = [ - 'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)), - 'user_added' => $user, - 'link' => Display::url($url, $url), - 'form' => $formData, - 'user_language' => $userLanguageName, - ]; - $emailBody = $tpl->render( - '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig', - $params - ); + foreach ($adminList as $adminId => $adminData) { + $adminLocale = $adminData['locale']; + $translator->setLocale($adminLocale); + $renderer = FormValidator::getDefaultRenderer(); + $elementTemplate = ' {label}: {element}
'; + $renderer->setElementTemplate($elementTemplate); + + $form->freeze(null, $elementTemplate); + $form->removeElement('submit'); + $form->removeElement('pass1'); + $form->removeElement('pass2'); + + foreach ($form->_elements as $element) { + $origLabel = $element->getLabel(); + $element->setLabel( get_lang($origLabel, $adminLocale) ); + } - if (!empty($emailBodyTemplate) && - isset($emailTemplate['content_registration_platform_to_admin.tpl']) && - !empty($emailTemplate['content_registration_platform_to_admin.tpl']) - ) { - $emailBody = $mailTemplateManager->parseTemplate( - $emailTemplate['content_registration_platform_to_admin.tpl'], - $userInfo + $formData = $form->returnForm(); + + /** @var LanguageRepository $langRepo */ + $langRepo = Container::$container->get(LanguageRepository::class); + $languageEntity = $langRepo->findOneBy(['isocode' => $user->getLocale()]); + $userLanguageName = $languageEntity + ? $languageEntity->getOriginalName() + : $user->getLocale(); + + $url = api_get_path(WEB_CODE_PATH) + . 'admin/user_information.php?user_id=' . $user->getId(); + + $params = [ + 'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)), + 'user_added' => $user, + 'link' => Display::url($url, $url), + 'form' => $formData, + 'user_language' => $userLanguageName, + ]; + + $emailBody = $tpl->render( + '@ChamiloCore/Mailer/Legacy/content_registration_platform_to_admin.html.twig', + $params ); - } - $subject = get_lang('The user has been added'); - foreach ($adminList as $adminId => $data) { + $subject = get_lang('The user has been added', $adminLocale); + MessageManager::send_message_simple( $adminId, $subject, $emailBody, $userId ); + + $translator->setLocale($currentTranslatorLang); } } } @@ -3807,7 +3813,7 @@ public static function get_all_administrators() $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $access_url_id = api_get_current_access_url_id(); if (api_get_multiple_access_url()) { - $sql = "SELECT admin.user_id, username, firstname, lastname, email, active + $sql = "SELECT admin.user_id, username, firstname, lastname, email, active, locale FROM $tbl_url_rel_user as url INNER JOIN $table_admin as admin ON (admin.user_id=url.user_id) @@ -3815,7 +3821,7 @@ public static function get_all_administrators() ON (u.id=admin.user_id) WHERE access_url_id ='".$access_url_id."'"; } else { - $sql = "SELECT admin.user_id, username, firstname, lastname, email, active + $sql = "SELECT admin.user_id, username, firstname, lastname, email, active, locale FROM $table_admin as admin INNER JOIN $table_user u ON (u.id=admin.user_id)"; diff --git a/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig b/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig index e781714a1e6..0ef15cd4f1f 100644 --- a/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig +++ b/src/CoreBundle/Resources/views/Mailer/Legacy/content_registration_platform_to_admin.html.twig @@ -1,27 +1,15 @@ {% autoescape false %} -

- {{ 'User %s with language %s registered to the site' - |trans({}, 'messages', locale) - |format(complete_name, user_language) - }} -

-

- {{ 'His profile is' - |trans({}, 'messages', locale) - }} -

+

{{ 'User %s with language %s registered to the site'|trans|format(complete_name, user_language) }}

+

{{ 'His profile is'|trans }}

+
- {{ form }} + {{ form|raw }}
-

- {{ 'You can assign a tutor in this link %s' - |trans({}, 'messages', locale) - |format(link) - }} -

+ +

{{ 'You can assign a tutor in this link %s'|trans|format(link) }}

{% include '@ChamiloCore/Mailer/Legacy/_admin_signature_footer.html.twig' %} {% endautoescape %} From 6ae58ee71e06a4d654b3d30305df9335761dd7dd Mon Sep 17 00:00:00 2001 From: Christian Beeznest Date: Fri, 8 Aug 2025 13:13:54 -0500 Subject: [PATCH 3/3] =?UTF-8?q?User:=20Localize=20registration=20email=20f?= =?UTF-8?q?ields;=20fix=20QuickForm=20=E2=80=9Csubmit=E2=80=9D=20error=20-?= =?UTF-8?q?=20refs=20BT#22823?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/main/inc/lib/usermanager.lib.php | 175 ++++++++++++++++++++---- 1 file changed, 146 insertions(+), 29 deletions(-) diff --git a/public/main/inc/lib/usermanager.lib.php b/public/main/inc/lib/usermanager.lib.php index 51099b79306..32cff7fb0bb 100644 --- a/public/main/inc/lib/usermanager.lib.php +++ b/public/main/inc/lib/usermanager.lib.php @@ -537,45 +537,25 @@ public static function create_user( } /** @var TranslatorInterface $translator */ - $translator = Container::$container->get('translator'); - $currentTranslatorLang = $translator->getLocale(); + $translator = Container::$container->get('translator'); + $currentLocale = $translator->getLocale(); if ($sendEmailToAllAdmins) { $adminList = self::get_all_administrators(); + $url = api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$user->getId(); + foreach ($adminList as $adminId => $adminData) { - $adminLocale = $adminData['locale']; + $adminLocale = $adminData['locale'] ?? 'en_US'; $translator->setLocale($adminLocale); - $renderer = FormValidator::getDefaultRenderer(); - $elementTemplate = ' {label}: {element}
'; - $renderer->setElementTemplate($elementTemplate); - - $form->freeze(null, $elementTemplate); - $form->removeElement('submit'); - $form->removeElement('pass1'); - $form->removeElement('pass2'); - - foreach ($form->_elements as $element) { - $origLabel = $element->getLabel(); - $element->setLabel( get_lang($origLabel, $adminLocale) ); - } - - $formData = $form->returnForm(); - - /** @var LanguageRepository $langRepo */ - $langRepo = Container::$container->get(LanguageRepository::class); - $languageEntity = $langRepo->findOneBy(['isocode' => $user->getLocale()]); - $userLanguageName = $languageEntity - ? $languageEntity->getOriginalName() - : $user->getLocale(); - $url = api_get_path(WEB_CODE_PATH) - . 'admin/user_information.php?user_id=' . $user->getId(); + $profileHtml = self::renderRegistrationProfileHtml($user, $extra ?? [], $adminLocale); + $userLanguageName = self::resolveLanguageName($user->getLocale()); $params = [ 'complete_name' => stripslashes(api_get_person_name($firstName, $lastName)), 'user_added' => $user, 'link' => Display::url($url, $url), - 'form' => $formData, + 'form' => $profileHtml, 'user_language' => $userLanguageName, ]; @@ -593,7 +573,7 @@ public static function create_user( $userId ); - $translator->setLocale($currentTranslatorLang); + $translator->setLocale($currentLocale); } } } @@ -622,6 +602,143 @@ public static function create_user( return $userId; } + /** + * Returns the human-readable language name for a given ISO code. + * + * Accepts ISO 639-1/2 codes (e.g. "en", "es", "eng"). If $iso is null or the + * code is unknown, an empty string is returned. + * + * @param string|null $iso Two- or three-letter ISO 639 language code. + * @return string Language name in English (e.g. "English", "Spanish"). + */ + private static function resolveLanguageName(?string $iso): string + { + if (empty($iso)) { + return ''; + } + + /** @var LanguageRepository $langRepo */ + $langRepo = Container::$container->get(LanguageRepository::class); + $entity = $langRepo->findOneBy(['isocode' => $iso]); + + return $entity ? $entity->getOriginalName() : $iso; + } + + /** + * Build the “profile” HTML (core + dynamic extra fields) for the admin email, localized in $adminLocale. + * + * @param User $user + * @param array $extraParams Raw POST values from registration (keys: "extra_*"). + * @param string $adminLocale e.g. "es_ES", "fr_FR". + */ + private static function renderRegistrationProfileHtml(User $user, array $extraParams, string $adminLocale): string + { + $statusLabel = ((int) $user->getStatus() === COURSEMANAGER) + ? get_lang('Teach courses', $adminLocale) + : get_lang('Follow courses', $adminLocale); + + $languageName = $user->getLocale(); + $langRepo = Container::$container->get(LanguageRepository::class); + if ($langRepo && ($lang = $langRepo->findOneBy(['isocode' => $user->getLocale()]))) { + $languageName = $lang->getOriginalName(); + } + + $corePairs = [ + get_lang('e-mail', $adminLocale) => (string) $user->getEmail(), + get_lang('First name', $adminLocale) => (string) $user->getFirstname(), + get_lang('Last name', $adminLocale) => (string) $user->getLastname(), + get_lang('Username', $adminLocale) => (string) $user->getUsername(), + get_lang('Official code', $adminLocale) => (string) ($user->getOfficialCode() ?? ''), + get_lang('Phone', $adminLocale) => (string) ($user->getPhone() ?? ''), + get_lang('User address', $adminLocale) => (string) ($user->getAddress() ?? ''), + get_lang('Language', $adminLocale) => (string) $languageName, + get_lang('What do you want to do?', $adminLocale) => $statusLabel, + ]; + + if ($user->getDateOfBirth() instanceof \DateTimeInterface) { + $corePairs[get_lang('Date of birth', $adminLocale)] = $user->getDateOfBirth()->format('Y-m-d'); + } + + $efv = new \ExtraFieldValue('user'); + $ef = new \ExtraField('user'); + + $extraPairs = []; + $presentVars = []; + $rows = $efv->getAllValuesByItem((int) $user->getId()); + + if (is_array($rows)) { + foreach ($rows as $row) { + $fieldId = (int)$row['id']; + $variable = (string)$row['variable']; + $presentVars[$variable] = true; + + $tr = $efv->get_values_by_handler_and_field_id((int) $user->getId(), $fieldId, true); + $val = null; + + if ($tr && array_key_exists('value', $tr)) { + $val = $tr['value']; + } else { + $val = $row['value']; + } + + $type = (int)$row['value_type']; + if ($type === \ExtraField::FIELD_TYPE_CHECKBOX) { + $val = ((string)$val === '1') ? get_lang('Yes', $adminLocale) : get_lang('No', $adminLocale); + } + if ($type === \ExtraField::FIELD_TYPE_TAG && is_array($val)) { + $val = implode(', ', array_map(fn($t) => is_array($t) ? (string)($t['value'] ?? '') : (string)$t, $val)); + } + if (is_string($val)) { + $val = str_replace(['
','
','
'], ', ', $val); + } + + $label = !empty($row['display_text']) + ? get_lang($row['display_text'], $adminLocale) + : get_lang(ucwords(str_replace('_',' ',$variable)), $adminLocale); + + if ($val !== '' && $val !== null) { + $extraPairs[$label] = (string)$val; + } + } + } + + foreach ($extraParams as $k => $v) { + if (strpos($k, 'extra_') !== 0) continue; + $variable = substr($k, 6); + if (isset($presentVars[$variable])) continue; + + $def = $ef->get_handler_field_info_by_field_variable($variable); + $label = $def && !empty($def['display_text']) + ? get_lang($def['display_text'], $adminLocale) + : get_lang(ucwords(str_replace('_',' ',$variable)), $adminLocale); + + $val = $v; + if (is_array($val)) { + $val = implode(', ', array_map('strval', $val)); + } elseif ($val === '1') { + $val = get_lang('Yes', $adminLocale); + } elseif ($val === '0') { + $val = get_lang('No', $adminLocale); + } + + if ($val !== '' && $val !== null) { + $extraPairs[$label] = (string)$val; + } + } + + $html = '
'; + foreach ($corePairs as $k => $v) { + if ($v === '' || $v === null) continue; + $html .= '
'.$k.': '.\Security::remove_XSS((string)$v).'
'; + } + foreach ($extraPairs as $k => $v) { + $html .= '
'.$k.': '.\Security::remove_XSS((string)$v).'
'; + } + $html .= '
'; + + return $html; + } + /** * Can user be deleted? This function checks whether there's a course * in which the given user is the