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. | |
f34c86fb | 164 | Civi::cache('fields')->clear(); |
6a488035 TO |
165 | |
166 | //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache. | |
f34c86fb | 167 | Civi::cache('navigation')->clear(); |
96689db3 SL |
168 | // reset ACL and System caches |
169 | CRM_Core_BAO_Cache::resetCaches(); | |
6a488035 | 170 | |
6a488035 | 171 | // make the site multi-lang if requested |
a7488080 | 172 | if (!empty($values['makeMultilingual'])) { |
6a488035 TO |
173 | CRM_Core_I18n_Schema::makeMultilingual($values['lcMessages']); |
174 | $values['languageLimit'][$values['lcMessages']] = 1; | |
175 | // make the site single-lang if requested | |
176 | } | |
a7488080 | 177 | elseif (!empty($values['makeSinglelingual'])) { |
6a488035 TO |
178 | CRM_Core_I18n_Schema::makeSinglelingual($values['lcMessages']); |
179 | $values['languageLimit'] = ''; | |
180 | } | |
181 | ||
182 | // add a new db locale if the requested language is not yet supported by the db | |
de6c59ca | 183 | if (empty($values['makeSinglelingual']) && !empty($values['addLanguage'])) { |
394d18d3 CW |
184 | $locales = CRM_Core_I18n::getMultilingual(); |
185 | if (!in_array($values['addLanguage'], $locales)) { | |
6a488035 TO |
186 | CRM_Core_I18n_Schema::addLocale($values['addLanguage'], $values['lcMessages']); |
187 | } | |
188 | $values['languageLimit'][$values['addLanguage']] = 1; | |
189 | } | |
190 | ||
921ed8ae AS |
191 | // current language should be in the ui list |
192 | if (!in_array($values['lcMessages'], $values['uiLanguages'])) { | |
193 | $values['uiLanguages'][] = $values['lcMessages']; | |
194 | } | |
195 | ||
6a488035 | 196 | // if we manipulated the language list, return to the localization admin screen |
02fc859b | 197 | $return = (bool) (CRM_Utils_Array::value('makeMultilingual', $values) or CRM_Utils_Array::value('addLanguage', $values)); |
6a488035 | 198 | |
fb7d2ea1 MW |
199 | // Update enabled currencies |
200 | // we do this only to initialize monetary decimal point and thousand separator | |
201 | $config = CRM_Core_Config::singleton(); | |
202 | // save enabled currencies and default currency in option group 'currencies_enabled' | |
203 | // CRM-1496 | |
204 | if (empty($values['currencyLimit'])) { | |
205 | $values['currencyLimit'] = [$values['defaultCurrency']]; | |
206 | } | |
207 | elseif (!in_array($values['defaultCurrency'], $values['currencyLimit'])) { | |
208 | $values['currencyLimit'][] = $values['defaultCurrency']; | |
209 | } | |
210 | self::updateEnabledCurrencies($values['currencyLimit'], $values['defaultCurrency']); | |
211 | // unset currencyLimit so we dont store there | |
212 | unset($values['currencyLimit']); | |
213 | ||
b72b5fc0 TO |
214 | $filteredValues = $values; |
215 | unset($filteredValues['makeMultilingual']); | |
216 | unset($filteredValues['makeSinglelingual']); | |
217 | unset($filteredValues['addLanguage']); | |
218 | unset($filteredValues['languageLimit']); | |
219 | ||
220 | Civi::settings()->set('languageLimit', CRM_Utils_Array::value('languageLimit', $values)); | |
221 | ||
6a488035 | 222 | // save all the settings |
b72b5fc0 | 223 | parent::commonProcess($filteredValues); |
6a488035 TO |
224 | |
225 | if ($return) { | |
226 | CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/localization', 'reset=1')); | |
227 | } | |
228 | } | |
96025800 | 229 | |
ece6501c ML |
230 | /** |
231 | * Replace available currencies by the ones provided | |
232 | * | |
233 | * @param $currencies array of currencies ['USD', 'CAD'] | |
234 | * @param $default default currency | |
235 | */ | |
236 | public static function updateEnabledCurrencies($currencies, $default) { | |
237 | ||
238 | // sort so that when we display drop down, weights have right value | |
239 | sort($currencies); | |
240 | ||
241 | // get labels for all the currencies | |
be2fb01f | 242 | $options = []; |
ece6501c ML |
243 | |
244 | $currencySymbols = CRM_Admin_Form_Setting_Localization::getCurrencySymbols(); | |
245 | for ($i = 0; $i < count($currencies); $i++) { | |
be2fb01f | 246 | $options[] = [ |
ece6501c ML |
247 | 'label' => $currencySymbols[$currencies[$i]], |
248 | 'value' => $currencies[$i], | |
249 | 'weight' => $i + 1, | |
250 | 'is_active' => 1, | |
251 | 'is_default' => $currencies[$i] == $default, | |
be2fb01f | 252 | ]; |
ece6501c ML |
253 | } |
254 | ||
255 | $dontCare = NULL; | |
256 | CRM_Core_OptionGroup::createAssoc('currencies_enabled', $options, $dontCare); | |
257 | ||
258 | } | |
259 | ||
8a61528e TO |
260 | /** |
261 | * @return array | |
262 | */ | |
263 | public static function getAvailableCountries() { | |
264 | $i18n = CRM_Core_I18n::singleton(); | |
be2fb01f | 265 | $country = []; |
8a61528e | 266 | CRM_Core_PseudoConstant::populate($country, 'CRM_Core_DAO_Country', TRUE, 'name', 'is_active'); |
be2fb01f | 267 | $i18n->localizeArray($country, ['context' => 'country']); |
8a61528e TO |
268 | asort($country); |
269 | return $country; | |
270 | } | |
271 | ||
272 | /** | |
8246bca4 | 273 | * Get the default locale options. |
274 | * | |
8a61528e TO |
275 | * @return array |
276 | */ | |
277 | public static function getDefaultLocaleOptions() { | |
394d18d3 CW |
278 | $locales = CRM_Core_I18n::getMultilingual(); |
279 | $languages = CRM_Core_I18n::languages(); | |
280 | if ($locales) { | |
8a61528e | 281 | // for multi-lingual sites, populate default language drop-down with available languages |
394d18d3 | 282 | return array_intersect_key($languages, array_flip($locales)); |
8a61528e TO |
283 | } |
284 | else { | |
394d18d3 | 285 | return $languages; |
8a61528e | 286 | } |
8a61528e TO |
287 | } |
288 | ||
289 | /** | |
290 | * Get a list of currencies (with their symbols). | |
291 | * | |
292 | * @return array | |
293 | * Array('USD' => 'USD ($)'). | |
294 | */ | |
295 | public static function getCurrencySymbols() { | |
be2fb01f | 296 | $symbols = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'currency', [ |
8a61528e TO |
297 | 'labelColumn' => 'symbol', |
298 | 'orderColumn' => TRUE, | |
be2fb01f CW |
299 | ]); |
300 | $_currencySymbols = []; | |
8a61528e TO |
301 | foreach ($symbols as $key => $value) { |
302 | $_currencySymbols[$key] = "$key"; | |
303 | if ($value) { | |
304 | $_currencySymbols[$key] .= " ($value)"; | |
305 | } | |
306 | } | |
307 | return $_currencySymbols; | |
308 | } | |
309 | ||
f2ac86d1 | 310 | /** |
311 | * Update session and uf_match table when the locale is updated. | |
312 | * | |
313 | * @param string $oldLocale | |
314 | * @param string $newLocale | |
315 | * @param array $metadata | |
316 | * @param int $domainID | |
317 | */ | |
b72b5fc0 TO |
318 | public static function onChangeLcMessages($oldLocale, $newLocale, $metadata, $domainID) { |
319 | if ($oldLocale == $newLocale) { | |
320 | return; | |
321 | } | |
322 | ||
323 | $session = CRM_Core_Session::singleton(); | |
324 | if ($newLocale && $session->get('userID')) { | |
325 | $ufm = new CRM_Core_DAO_UFMatch(); | |
326 | $ufm->contact_id = $session->get('userID'); | |
327 | if ($newLocale && $ufm->find(TRUE)) { | |
b72b5fc0 TO |
328 | $session->set('lcMessages', $newLocale); |
329 | } | |
330 | } | |
331 | } | |
332 | ||
ece6501c ML |
333 | public static function onChangeDefaultCurrency($oldCurrency, $newCurrency, $metadata) { |
334 | if ($oldCurrency == $newCurrency) { | |
335 | return; | |
336 | } | |
337 | ||
338 | // ensure that default currency is always in the list of enabled currencies | |
339 | $currencies = array_keys(CRM_Core_OptionGroup::values('currencies_enabled')); | |
340 | if (!in_array($newCurrency, $currencies)) { | |
341 | if (empty($currencies)) { | |
be2fb01f | 342 | $currencies = [$values['defaultCurrency']]; |
ece6501c ML |
343 | } |
344 | else { | |
345 | $currencies[] = $newCurrency; | |
346 | } | |
347 | ||
348 | CRM_Admin_Form_Setting_Localization::updateEnabledCurrencies($currencies, $newCurrency); | |
349 | } | |
350 | ||
351 | } | |
352 | ||
9c325795 TO |
353 | /** |
354 | * @return array | |
355 | */ | |
356 | public static function getDefaultLanguageOptions() { | |
be2fb01f | 357 | return [ |
9c325795 TO |
358 | '*default*' => ts('Use default site language'), |
359 | 'undefined' => ts('Leave undefined'), | |
360 | 'current_site_language' => ts('Use language in use at the time'), | |
be2fb01f | 361 | ]; |
9c325795 TO |
362 | } |
363 | ||
6a488035 | 364 | } |