Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | /** | |
ce064e4f | 19 | * This class generates form components for Localization. |
6a488035 TO |
20 | */ |
21 | class CRM_Admin_Form_Setting_Localization extends CRM_Admin_Form_Setting { | |
8a61528e | 22 | |
be2fb01f | 23 | protected $_settings = [ |
9c325795 | 24 | 'contact_default_language' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, |
8a61528e TO |
25 | 'countryLimit' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, |
26 | 'customTranslateFunction' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
27 | 'defaultContactCountry' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
28 | 'defaultContactStateProvince' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
29 | 'defaultCurrency' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
30 | 'fieldSeparator' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
31 | 'inheritLocale' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
32 | 'lcMessages' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
33 | 'legacyEncoding' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
34 | 'monetaryThousandSeparator' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
35 | 'monetaryDecimalPoint' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
36 | 'moneyformat' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
37 | 'moneyvalueformat' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
38 | 'provinceLimit' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, | |
fe810d04 | 39 | 'uiLanguages' => CRM_Core_BAO_Setting::LOCALIZATION_PREFERENCES_NAME, |
be2fb01f | 40 | ]; |
6a488035 TO |
41 | |
42 | /** | |
eceb18cc | 43 | * Build the form object. |
6a488035 TO |
44 | */ |
45 | public function buildQuickForm() { | |
46 | $config = CRM_Core_Config::singleton(); | |
47 | ||
6a488035 TO |
48 | CRM_Utils_System::setTitle(ts('Settings - Localization')); |
49 | ||
fe25a292 | 50 | $warningTitle = json_encode(ts("Warning")); |
b72b5fc0 | 51 | $defaultLocaleOptions = CRM_Admin_Form_Setting_Localization::getDefaultLocaleOptions(); |
8a61528e | 52 | |
921ed8ae | 53 | if (CRM_Core_I18n::isMultiLingual()) { |
6a488035 | 54 | // add language limiter and language adder |
b72b5fc0 | 55 | $this->addCheckBox('languageLimit', ts('Available Languages'), array_flip($defaultLocaleOptions), NULL, NULL, NULL, NULL, ' '); |
be2fb01f | 56 | $this->addElement('select', 'addLanguage', ts('Add Language'), array_merge(['' => ts('- select -')], array_diff(CRM_Core_I18n::languages(), $defaultLocaleOptions))); |
6a488035 TO |
57 | |
58 | // add the ability to return to single language | |
fe25a292 | 59 | $warning = ts('This will make your CiviCRM installation a single-language one again. THIS WILL DELETE ALL DATA RELATED TO LANGUAGES OTHER THAN THE DEFAULT ONE SELECTED ABOVE (and only that language will be preserved).'); |
6a488035 | 60 | $this->assign('warning', $warning); |
fe25a292 | 61 | $warning = json_encode($warning); |
6a488035 | 62 | $this->addElement('checkbox', 'makeSinglelingual', ts('Return to Single Language'), |
be2fb01f | 63 | NULL, ['onChange' => "if (this.checked) CRM.alert($warning, $warningTitle)"] |
6a488035 TO |
64 | ); |
65 | } | |
66 | else { | |
fe25a292 | 67 | $warning = ts('Enabling multiple languages changes the schema of your database, so make sure you know what you are doing when enabling this function; making a database backup is strongly recommended.'); |
6a488035 | 68 | $this->assign('warning', $warning); |
fe25a292 | 69 | $warning = json_encode($warning); |
6a488035 TO |
70 | $validTriggerPermission = CRM_Core_DAO::checkTriggerViewPermission(TRUE); |
71 | ||
72 | if ($validTriggerPermission && | |
344b05bc | 73 | !\Civi::settings()->get('logging') |
6a488035 TO |
74 | ) { |
75 | $this->addElement('checkbox', 'makeMultilingual', ts('Enable Multiple Languages'), | |
be2fb01f | 76 | NULL, ['onChange' => "if (this.checked) CRM.alert($warning, $warningTitle)"] |
6a488035 TO |
77 | ); |
78 | } | |
79 | } | |
9c325795 TO |
80 | $this->addElement('select', 'contact_default_language', ts('Default Language for users'), |
81 | CRM_Admin_Form_Setting_Localization::getDefaultLanguageOptions()); | |
6a488035 TO |
82 | |
83 | $includeCurrency = &$this->addElement('advmultiselect', 'currencyLimit', | |
8a61528e | 84 | ts('Available Currencies') . ' ', self::getCurrencySymbols(), |
be2fb01f | 85 | [ |
6a488035 TO |
86 | 'size' => 5, |
87 | 'style' => 'width:150px', | |
88 | 'class' => 'advmultiselect', | |
be2fb01f | 89 | ] |
6a488035 TO |
90 | ); |
91 | ||
be2fb01f CW |
92 | $includeCurrency->setButtonAttributes('add', ['value' => ts('Add >>')]); |
93 | $includeCurrency->setButtonAttributes('remove', ['value' => ts('<< Remove')]); | |
6a488035 | 94 | |
be2fb01f | 95 | $this->addFormRule(['CRM_Admin_Form_Setting_Localization', 'formRule']); |
6a488035 TO |
96 | |
97 | parent::buildQuickForm(); | |
98 | } | |
99 | ||
e0ef6999 EM |
100 | /** |
101 | * @param $fields | |
102 | * | |
103 | * @return array|bool | |
104 | */ | |
00be9182 | 105 | public static function formRule($fields) { |
be2fb01f | 106 | $errors = []; |
6a488035 TO |
107 | if (CRM_Utils_Array::value('monetaryThousandSeparator', $fields) == |
108 | CRM_Utils_Array::value('monetaryDecimalPoint', $fields) | |
109 | ) { | |
110 | $errors['monetaryThousandSeparator'] = ts('Thousands Separator and Decimal Delimiter can not be the same.'); | |
111 | } | |
112 | ||
113 | if (strlen($fields['monetaryThousandSeparator']) == 0) { | |
114 | $errors['monetaryThousandSeparator'] = ts('Thousands Separator can not be empty. You can use a space character instead.'); | |
115 | } | |
116 | ||
6a488035 TO |
117 | if (strlen($fields['monetaryDecimalPoint']) > 1) { |
118 | $errors['monetaryDecimalPoint'] = ts('Decimal Delimiter can not have more than 1 character.'); | |
119 | } | |
120 | ||
121 | if (trim($fields['customTranslateFunction']) && | |
122 | !function_exists(trim($fields['customTranslateFunction'])) | |
123 | ) { | |
124 | $errors['customTranslateFunction'] = ts('Please define the custom translation function first.'); | |
125 | } | |
126 | ||
127 | // CRM-7962, CRM-7713, CRM-9004 | |
128 | if (!empty($fields['defaultContactCountry']) && | |
8cc574cf | 129 | (!empty($fields['countryLimit']) && |
6a488035 TO |
130 | (!in_array($fields['defaultContactCountry'], $fields['countryLimit'])) |
131 | ) | |
132 | ) { | |
133 | $errors['defaultContactCountry'] = ts('Please select a default country that is in the list of available countries.'); | |
b05e28de | 134 | } |
6a488035 TO |
135 | |
136 | return empty($errors) ? TRUE : $errors; | |
137 | } | |
138 | ||
f2ac86d1 | 139 | /** |
140 | * Set the default values for the form. | |
141 | * | |
142 | * @return array | |
143 | */ | |
00be9182 | 144 | public function setDefaultValues() { |
6a488035 TO |
145 | parent::setDefaultValues(); |
146 | ||
147 | // CRM-1496 | |
148 | // retrieve default values for currencyLimit | |
149 | $this->_defaults['currencyLimit'] = array_keys(CRM_Core_OptionGroup::values('currencies_enabled')); | |
150 | ||
b72b5fc0 TO |
151 | $this->_defaults['languageLimit'] = Civi::settings()->get('languageLimit'); |
152 | ||
6a488035 TO |
153 | // CRM-5111: unset these two unconditionally, we don’t want them to stick – ever |
154 | unset($this->_defaults['makeMultilingual']); | |
155 | unset($this->_defaults['makeSinglelingual']); | |
156 | return $this->_defaults; | |
157 | } | |
158 | ||
159 | public function postProcess() { | |
160 | $values = $this->exportValues(); | |
161 | ||
6a488035 TO |
162 | //cache contact fields retaining localized titles |
163 | //though we changed localization, so reseting cache. | |
9cdf85c1 | 164 | Civi::cache('fields')->flush(); |
6a488035 TO |
165 | |
166 | //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache. | |
96689db3 SL |
167 | Civi::cache('navigation')->flush(); |
168 | // reset ACL and System caches | |
169 | CRM_Core_BAO_Cache::resetCaches(); | |
6a488035 TO |
170 | |
171 | // we do this only to initialize monetary decimal point and thousand separator | |
172 | $config = CRM_Core_Config::singleton(); | |
173 | ||
ece6501c | 174 | // save enabled currencies and default currency in option group 'currencies_enabled' |
6a488035 TO |
175 | // CRM-1496 |
176 | if (empty($values['currencyLimit'])) { | |
be2fb01f | 177 | $values['currencyLimit'] = [$values['defaultCurrency']]; |
6a488035 | 178 | } |
ece6501c | 179 | elseif (!in_array($values['defaultCurrency'], $values['currencyLimit'])) { |
6a488035 TO |
180 | $values['currencyLimit'][] = $values['defaultCurrency']; |
181 | } | |
182 | ||
ece6501c | 183 | self::updateEnabledCurrencies($values['currencyLimit'], $values['defaultCurrency']); |
6a488035 TO |
184 | |
185 | // unset currencyLimit so we dont store there | |
186 | unset($values['currencyLimit']); | |
187 | ||
188 | // make the site multi-lang if requested | |
a7488080 | 189 | if (!empty($values['makeMultilingual'])) { |
6a488035 TO |
190 | CRM_Core_I18n_Schema::makeMultilingual($values['lcMessages']); |
191 | $values['languageLimit'][$values['lcMessages']] = 1; | |
192 | // make the site single-lang if requested | |
193 | } | |
a7488080 | 194 | elseif (!empty($values['makeSinglelingual'])) { |
6a488035 TO |
195 | CRM_Core_I18n_Schema::makeSinglelingual($values['lcMessages']); |
196 | $values['languageLimit'] = ''; | |
197 | } | |
198 | ||
199 | // add a new db locale if the requested language is not yet supported by the db | |
de6c59ca | 200 | if (empty($values['makeSinglelingual']) && !empty($values['addLanguage'])) { |
6a488035 TO |
201 | $domain = new CRM_Core_DAO_Domain(); |
202 | $domain->find(TRUE); | |
203 | if (!substr_count($domain->locales, $values['addLanguage'])) { | |
204 | CRM_Core_I18n_Schema::addLocale($values['addLanguage'], $values['lcMessages']); | |
205 | } | |
206 | $values['languageLimit'][$values['addLanguage']] = 1; | |
207 | } | |
208 | ||
921ed8ae AS |
209 | // current language should be in the ui list |
210 | if (!in_array($values['lcMessages'], $values['uiLanguages'])) { | |
211 | $values['uiLanguages'][] = $values['lcMessages']; | |
212 | } | |
213 | ||
6a488035 | 214 | // if we manipulated the language list, return to the localization admin screen |
02fc859b | 215 | $return = (bool) (CRM_Utils_Array::value('makeMultilingual', $values) or CRM_Utils_Array::value('addLanguage', $values)); |
6a488035 | 216 | |
b72b5fc0 TO |
217 | $filteredValues = $values; |
218 | unset($filteredValues['makeMultilingual']); | |
219 | unset($filteredValues['makeSinglelingual']); | |
220 | unset($filteredValues['addLanguage']); | |
221 | unset($filteredValues['languageLimit']); | |
222 | ||
223 | Civi::settings()->set('languageLimit', CRM_Utils_Array::value('languageLimit', $values)); | |
224 | ||
6a488035 | 225 | // save all the settings |
b72b5fc0 | 226 | parent::commonProcess($filteredValues); |
6a488035 TO |
227 | |
228 | if ($return) { | |
229 | CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/localization', 'reset=1')); | |
230 | } | |
231 | } | |
96025800 | 232 | |
ece6501c ML |
233 | /** |
234 | * Replace available currencies by the ones provided | |
235 | * | |
236 | * @param $currencies array of currencies ['USD', 'CAD'] | |
237 | * @param $default default currency | |
238 | */ | |
239 | public static function updateEnabledCurrencies($currencies, $default) { | |
240 | ||
241 | // sort so that when we display drop down, weights have right value | |
242 | sort($currencies); | |
243 | ||
244 | // get labels for all the currencies | |
be2fb01f | 245 | $options = []; |
ece6501c ML |
246 | |
247 | $currencySymbols = CRM_Admin_Form_Setting_Localization::getCurrencySymbols(); | |
248 | for ($i = 0; $i < count($currencies); $i++) { | |
be2fb01f | 249 | $options[] = [ |
ece6501c ML |
250 | 'label' => $currencySymbols[$currencies[$i]], |
251 | 'value' => $currencies[$i], | |
252 | 'weight' => $i + 1, | |
253 | 'is_active' => 1, | |
254 | 'is_default' => $currencies[$i] == $default, | |
be2fb01f | 255 | ]; |
ece6501c ML |
256 | } |
257 | ||
258 | $dontCare = NULL; | |
259 | CRM_Core_OptionGroup::createAssoc('currencies_enabled', $options, $dontCare); | |
260 | ||
261 | } | |
262 | ||
8a61528e TO |
263 | /** |
264 | * @return array | |
265 | */ | |
266 | public static function getAvailableCountries() { | |
267 | $i18n = CRM_Core_I18n::singleton(); | |
be2fb01f | 268 | $country = []; |
8a61528e | 269 | CRM_Core_PseudoConstant::populate($country, 'CRM_Core_DAO_Country', TRUE, 'name', 'is_active'); |
be2fb01f | 270 | $i18n->localizeArray($country, ['context' => 'country']); |
8a61528e TO |
271 | asort($country); |
272 | return $country; | |
273 | } | |
274 | ||
275 | /** | |
8246bca4 | 276 | * Get the default locale options. |
277 | * | |
8a61528e TO |
278 | * @return array |
279 | */ | |
280 | public static function getDefaultLocaleOptions() { | |
281 | $domain = new CRM_Core_DAO_Domain(); | |
282 | $domain->find(TRUE); | |
283 | $locales = CRM_Core_I18n::languages(); | |
284 | if ($domain->locales) { | |
285 | // for multi-lingual sites, populate default language drop-down with available languages | |
be2fb01f | 286 | $defaultLocaleOptions = []; |
8a61528e TO |
287 | foreach ($locales as $loc => $lang) { |
288 | if (substr_count($domain->locales, $loc)) { | |
b72b5fc0 | 289 | $defaultLocaleOptions[$loc] = $lang; |
8a61528e TO |
290 | } |
291 | } | |
292 | } | |
293 | else { | |
b72b5fc0 | 294 | $defaultLocaleOptions = $locales; |
8a61528e | 295 | } |
b72b5fc0 | 296 | return $defaultLocaleOptions; |
8a61528e TO |
297 | } |
298 | ||
299 | /** | |
300 | * Get a list of currencies (with their symbols). | |
301 | * | |
302 | * @return array | |
303 | * Array('USD' => 'USD ($)'). | |
304 | */ | |
305 | public static function getCurrencySymbols() { | |
be2fb01f | 306 | $symbols = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'currency', [ |
8a61528e TO |
307 | 'labelColumn' => 'symbol', |
308 | 'orderColumn' => TRUE, | |
be2fb01f CW |
309 | ]); |
310 | $_currencySymbols = []; | |
8a61528e TO |
311 | foreach ($symbols as $key => $value) { |
312 | $_currencySymbols[$key] = "$key"; | |
313 | if ($value) { | |
314 | $_currencySymbols[$key] .= " ($value)"; | |
315 | } | |
316 | } | |
317 | return $_currencySymbols; | |
318 | } | |
319 | ||
f2ac86d1 | 320 | /** |
321 | * Update session and uf_match table when the locale is updated. | |
322 | * | |
323 | * @param string $oldLocale | |
324 | * @param string $newLocale | |
325 | * @param array $metadata | |
326 | * @param int $domainID | |
327 | */ | |
b72b5fc0 TO |
328 | public static function onChangeLcMessages($oldLocale, $newLocale, $metadata, $domainID) { |
329 | if ($oldLocale == $newLocale) { | |
330 | return; | |
331 | } | |
332 | ||
333 | $session = CRM_Core_Session::singleton(); | |
334 | if ($newLocale && $session->get('userID')) { | |
335 | $ufm = new CRM_Core_DAO_UFMatch(); | |
336 | $ufm->contact_id = $session->get('userID'); | |
337 | if ($newLocale && $ufm->find(TRUE)) { | |
338 | $ufm->language = $newLocale; | |
339 | $ufm->save(); | |
340 | $session->set('lcMessages', $newLocale); | |
341 | } | |
342 | } | |
343 | } | |
344 | ||
ece6501c ML |
345 | public static function onChangeDefaultCurrency($oldCurrency, $newCurrency, $metadata) { |
346 | if ($oldCurrency == $newCurrency) { | |
347 | return; | |
348 | } | |
349 | ||
350 | // ensure that default currency is always in the list of enabled currencies | |
351 | $currencies = array_keys(CRM_Core_OptionGroup::values('currencies_enabled')); | |
352 | if (!in_array($newCurrency, $currencies)) { | |
353 | if (empty($currencies)) { | |
be2fb01f | 354 | $currencies = [$values['defaultCurrency']]; |
ece6501c ML |
355 | } |
356 | else { | |
357 | $currencies[] = $newCurrency; | |
358 | } | |
359 | ||
360 | CRM_Admin_Form_Setting_Localization::updateEnabledCurrencies($currencies, $newCurrency); | |
361 | } | |
362 | ||
363 | } | |
364 | ||
9c325795 TO |
365 | /** |
366 | * @return array | |
367 | */ | |
368 | public static function getDefaultLanguageOptions() { | |
be2fb01f | 369 | return [ |
9c325795 TO |
370 | '*default*' => ts('Use default site language'), |
371 | 'undefined' => ts('Leave undefined'), | |
372 | 'current_site_language' => ts('Use language in use at the time'), | |
be2fb01f | 373 | ]; |
9c325795 TO |
374 | } |
375 | ||
6a488035 | 376 | } |