From a6bd76228deffce6ac86249ab95f992971064b76 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 5 Aug 2022 03:02:04 -0700 Subject: [PATCH] (dev/translation#78) I18nSubscriber - Allow partial/negotiated locales Definitions: * A fully-supported locale is valid in all localization services (eg `ts()`, `Civi::format()`, `$dbLocale`). * A "negotiated" or "mixed" locale can be used for communication, but it is not fully supported by all other layers. Consequently, it requires some kind of fallback or substitution. Before: * When an API call requests an alternate language (v3's `option.language` or v4's `setLanguage()`), it only activates fully-supported locales. * Specifically, it validates against the multilingual configuration -- those are fully supported locales.) It otherwise ignores the alternate language. After: * When an API call requests an alternate language, it cacn activate fully-supported locales as well as mixed locales. * Specifically, it asks `Locale::negotiate(...)` to examine the local configuration/resources and determine the effective locale. --- Civi/API/Subscriber/I18nSubscriber.php | 55 ++++++-------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/Civi/API/Subscriber/I18nSubscriber.php b/Civi/API/Subscriber/I18nSubscriber.php index dadce282ba..5cff107300 100644 --- a/Civi/API/Subscriber/I18nSubscriber.php +++ b/Civi/API/Subscriber/I18nSubscriber.php @@ -12,6 +12,7 @@ namespace Civi\API\Subscriber; use Civi\API\Events; +use Civi\Core\Locale; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -24,8 +25,9 @@ class I18nSubscriber implements EventSubscriberInterface { * Used for rolling back language to its original setting after the api call. * * @var array + * Array(string $requestId => \Civi\Core\Locale $locale). */ - public $originalLang = []; + protected $originalLocale = []; /** * @return array @@ -56,7 +58,11 @@ class I18nSubscriber implements EventSubscriberInterface { $language = $params['language'] ?? NULL; } if ($language) { - $this->setLocale($language, $apiRequest['id']); + $newLocale = Locale::negotiate($language); + if ($newLocale) { + $this->originalLocale[$apiRequest['id']] = Locale::detect(); + $newLocale->apply(); + } } } @@ -70,48 +76,9 @@ class I18nSubscriber implements EventSubscriberInterface { public function onApiRespond(\Civi\API\Event\Event $event) { $apiRequest = $event->getApiRequest(); - if (!empty($this->originalLang[$apiRequest['id']])) { - global $tsLocale; - global $dbLocale; - $tsLocale = $this->originalLang[$apiRequest['id']]['tsLocale']; - $dbLocale = $this->originalLang[$apiRequest['id']]['dbLocale']; - } - } - - /** - * Sets the tsLocale and dbLocale for multi-lingual sites. - * Some code duplication from CRM/Core/BAO/ConfigSetting.php retrieve() - * to avoid regressions from refactoring. - * @param string $newLocale - * @param int $requestId - * @throws \API_Exception - */ - public function setLocale($newLocale, $requestId) { - $domain = new \CRM_Core_DAO_Domain(); - $domain->id = \CRM_Core_Config::domainID(); - $domain->find(TRUE); - - // Check if the site is multi-lingual - if ($domain->locales && $newLocale) { - // Validate language, otherwise a bad dbLocale could probably lead to sql-injection. - if (!array_key_exists($newLocale, \Civi::settings()->get('languageLimit'))) { - throw new \API_Exception(ts('Language not enabled: %1', [1 => $newLocale])); - } - - global $dbLocale; - global $tsLocale; - - // Store original value to be restored in $this->onApiRespond - $this->originalLang[$requestId] = [ - 'tsLocale' => $tsLocale, - 'dbLocale' => $dbLocale, - ]; - - // Set suffix for table names - use views if more than one language - $dbLocale = "_{$newLocale}"; - - // Also set tsLocale - CRM-4041 - $tsLocale = $newLocale; + if (!empty($this->originalLocale[$apiRequest['id']])) { + $this->originalLocale[$apiRequest['id']]->apply(); + unset($this->originalLocale[$apiRequest['id']]); } } -- 2.25.1