Skip to content

Commit

Permalink
Use translation for default language, if exists
Browse files Browse the repository at this point in the history
There is an assumption in the code that for the default language a translation is not used.

However, the features around draft versions are all set up around
translations, so it becomes necessary to create translations
even for the default language. This change ensures they are
used if they exist.

Although we have a lot of complexity in the translation framework
on the rendering side I think assuming that where stuff is configured
people configured it to be used is a good underlying principle.
  • Loading branch information
eileenmcnaughton committed Jul 5, 2023
1 parent 8927e12 commit 49489f5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
30 changes: 29 additions & 1 deletion CRM/Core/BAO/Translation.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static function hook_civicrm_apiWrappers(&$wrappers, $apiRequest): void {
}

$communicationLanguage = \Civi\Core\Locale::detect()->nominal;
if ($communicationLanguage === Civi::settings()->get('lcMessages')) {
if (!$communicationLanguage || !self::isTranslate($communicationLanguage)) {
return;
}

Expand All @@ -205,6 +205,34 @@ public static function hook_civicrm_apiWrappers(&$wrappers, $apiRequest): void {
}
}

/**
* Should the translation process be followed.
*
* It can be short-circuited if there we are in the site default language and
* it is not translated.
*
* @param string $communicationLanguage
*
* @return bool
*/
protected static function isTranslate(string $communicationLanguage): bool {
if ($communicationLanguage !== Civi::settings()->get('lcMessages')) {
return TRUE;
}
if (!isset(\Civi::$statics[__CLASS__]['translate_main'][$communicationLanguage])) {
// The code had an assumption that you would not translate the primary language.
// However, the UI is such that the features (approval flow) so it makes sense
// to translation the default site language as well. If we can see sites are
// doing this then let's treat the main locale like any other locale
\Civi::$statics[__CLASS__]['translate_main'] = (bool) CRM_Core_DAO::singleValueQuery(
'SELECT COUNT(*) FROM civicrm_translation WHERE language = %1 LIMIT 1', [
1 => [$communicationLanguage, 'String'],
]
);
}
return \Civi::$statics[__CLASS__]['translate_main'];
}

/**
* @param \Civi\Api4\Generic\AbstractAction $apiRequest
* @return array translated fields.
Expand Down
12 changes: 11 additions & 1 deletion tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ public function getLocaleConfigurations(): array {
$allTemplates['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '{contribution.total_amount}'];
$allTemplates['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '{contribution.total_amount}'];
$allTemplates['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => '{contribution.total_amount}'];
// en_US is the default language. We add it to ensure the translation is loaded rather than falling back to
// the message template. While it might seem you don't need a translation for the site default language
// all the draft & approval logic is attached to the translation, not the template.
$allTemplates['en_US'] = ['subject' => 'site default', 'html' => 'site default language', 'text' => '{contribution.total_amount}'];

$rendered = [];
// $rendered['*'] = ['subject' => 'Hello', 'html' => 'Look there!', 'text' => '$ 100.00'];
Expand All @@ -78,6 +82,7 @@ public function getLocaleConfigurations(): array {
$rendered['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '100,00 $ US'];
$rendered['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '100.00 $US'];
$rendered['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => 'US$100.00'];
$rendered['en_US'] = ['subject' => 'site default', 'html' => 'site default language', 'text' => '$100.00'];

$result = [/* settings, templates, preferredLanguage, expectMessage */];

Expand All @@ -92,11 +97,16 @@ public function getLocaleConfigurations(): array {
$result['fr_CA falls back to fr_FR (ltd-tpls; no-partials)'] = [$noPartials, $this->getLocaleTemplates($allTemplates, ['*', 'fr_FR']), 'fr_CA', $rendered['fr_FR']];

$result['th_TH matches th_TH (all-tpls; yes-partials)'] = [$yesPartials, $allTemplates, 'th_TH', $rendered['th_TH']];
$result['th_TH falls back to system default (all-tpls; no-partials)'] = [$noPartials, $allTemplates, 'th_TH', $rendered['*']];
$result['th_TH falls back to site default translation (all-tpls; no-partials)'] = [$noPartials, $allTemplates, 'th_TH', $rendered['en_US']];
// Absent a translation for the site default language it should fall back to the message template.
$result['th_TH falls back to system default (all-tpls; no-partials)'] = [$noPartials, array_diff_key($allTemplates, ['en_US' => TRUE]), 'th_TH', $rendered['*']];
// ^^ The essence of the `partial_locales` setting -- whether partially-supported locales (th_TH) use mixed-mode or fallback to completely diff locale.
$result['th_TH falls back to system default (ltd-tpls; yes-partials)'] = [$yesPartials, $this->getLocaleTemplates($allTemplates, ['*']), 'th_TH', $rendered['*']];
$result['th_TH falls back to system default (ltd-tpls; no-partials)'] = [$noPartials, $this->getLocaleTemplates($allTemplates, ['*']), 'th_TH', $rendered['*']];

// Check that the en_US template is loaded, if exists.
$result['en_US matches en_US (all-tpls; yes-partials)'] = [$yesPartials, $allTemplates, 'en_US', $rendered['en_US']];

return $result;
}

Expand Down

0 comments on commit 49489f5

Please sign in to comment.