CRM_Core_I18n::setLocale() - Fix bug with repeated usage
authorTim Otten <totten@civicrm.org>
Thu, 21 May 2020 07:22:46 +0000 (00:22 -0700)
committerTim Otten <totten@civicrm.org>
Thu, 21 May 2020 07:52:57 +0000 (00:52 -0700)
commitda460d9d00c283bf2e34680603521bb7e5e715ff
tree77f1b0e32a426d8440e422f7c896cb7ddd415f43
parent714b8746abcb4029b154d73e41a99f03ae2f1d8a
CRM_Core_I18n::setLocale() - Fix bug with repeated usage

Overview
--------

Suppose you use `setLocale()` to change back and forth between languages, e.g.

```php
/*1*/ $i18n->setLocale('en_US'); echo ts('Yes');
/*2*/ $i18n->setLocale('fr_FR'); echo ts('Yes');
/*3*/ $i18n->setLocale('de_DE'); echo ts('Yes');
/*4*/ $i18n->setLocale('en_US'); echo ts('Yes');
/*5*/ $i18n->setLocale('fr_FR'); echo ts('Yes');
/*6*/ $i18n->setLocale('de_DE'); echo ts('Yes');
```

This fixes a bug with that use-case.

For more detailed example/reproduction, see https://gist.github.com/totten/de0dc9add8dee3956ecad29ec0906cc3 -
specifically variant 2.

Before
------

There is a leak which causes mistranslations.

After
-----

You can freely switch between instances of `CRM_Core_I18n`.

Technical Details
-----------------

(1) I'm using a default configuration, wherein `CIVICRM_GETTEXT_NATIVE` is not
set...  so it uses phpgettext.

(2) As you use multiple locales, `CRM_Core_I18n::singleton()` constructs
multiple instances of `CRM_Core_I18n` (one for each locale; this despite the
misnomer of `singleton`). `singleton()` always returns the instance indicated
by the active locale (as directed by `global $tsLocale`).

The problem: if you call `$enUS->setPhpGettextLocale('fr_FR')`, then future
requests for American English will actually return French.  Similarly, if
you call `$frFR->setPhpGettextLocale('de_DE')`, then future requests for
French will actually return German.
CRM/Core/I18n.php
tests/phpunit/CRM/Core/I18n/LocaleTest.php