public function setLocale($locale) { if ($locale == 'en_US' && !Config::get('concrete.misc.enable_translate_locale_en_us')) { $this->translate = null; } else { $this->translate = new Translator(); $this->translate->setLocale($locale); $this->translate->setCache(self::getCache()); // Core language files $languageFile = DIR_LANGUAGES . "/{$locale}/LC_MESSAGES/messages.mo"; if (!is_file($languageFile)) { $languageFile = DIR_LANGUAGES_CORE . "/{$locale}/LC_MESSAGES/messages.mo"; if (!is_file($languageFile)) { $languageFile = ''; } } if ($languageFile !== '') { $this->translate->addTranslationFile('gettext', $languageFile); } // Package language files if (Config::get('app.bootstrap.packages_loaded') === true) { $pkgList = \Concrete\Core\Package\PackageList::get(); foreach ($pkgList->getPackages() as $pkg) { $pkg->setupPackageLocalization($locale, $this->translate); } // Site language files static::setupSiteLocalization($this->translate); } } PunicData::setDefaultLocale($locale); $event = new \Symfony\Component\EventDispatcher\GenericEvent(); $event->setArgument('locale', $locale); Events::dispatch('on_locale_load', $event); }
public function setLocale($locale) { $localeNeededLoading = false; if ($locale == 'en_US' && !Config::get('concrete.misc.enable_translate_locale_en_us')) { if (isset($this->translate)) { unset($this->translate); } PunicData::setDefaultLocale($locale); return; } if (is_dir(DIR_LANGUAGES . '/' . $locale)) { $languageDir = DIR_LANGUAGES . '/' . $locale; } elseif (is_dir(DIR_LANGUAGES_CORE . '/' . $locale)) { $languageDir = DIR_LANGUAGES_CORE . '/' . $locale; } else { return; } $this->translate = new Translator(); $this->translate->addTranslationFilePattern('gettext', $languageDir, 'LC_MESSAGES/messages.mo'); $this->translate->setLocale($locale); $this->translate->setCache(new ZendCacheDriver('cache/expensive')); PunicData::setDefaultLocale($locale); $event = new \Symfony\Component\EventDispatcher\GenericEvent(); $event->setArgument('locale', $locale); Events::dispatch('on_locale_load', $event); }
/** * Initializes the instance. * * @param string $locale * @param bool $caseSensitive */ public function __construct($locale = null, $caseSensitive = false) { $this->cache = array(); $this->locale = isset($locale) ? $locale : \Punic\Data::getDefaultLocale(); $this->caseSensitive = (bool) $caseSensitive; $this->collator = class_exists('\\Collator') ? new \Collator($this->locale) : null; $this->iconv = function_exists('iconv'); }
/** * gets list of locales * * @param boolean $showInCodeLanguage true to show a code's name in the language the code represents * * @return array */ public static function getList($showInCodeLanguage = false) { $locales = Data::getAvailableLocales(); $languages = array(); foreach ($locales as $locale) { $key = \Xoops\Locale::normalizeLocale($locale); $languages[$key] = Language::getName($locale, $showInCodeLanguage ? $locale : null); } \XoopsLocale::asort($languages); return $languages; }
/** * Initializes the instance. * * @param string $locale * @param bool $caseSensitive */ public function __construct($locale = null, $caseSensitive = false) { $this->cache = array(); $this->locale = isset($locale) ? $locale : \Punic\Data::getDefaultLocale(); $this->caseSensitive = (bool) $caseSensitive; $this->collator = null; if (class_exists('\\Collator')) { try { $this->collator = new Collator($this->locale); } catch (PHPException $x) { } } $this->iconv = function_exists('iconv'); }
protected static function joinInternal($list, $keys, $locale) { $result = ''; if (is_array($list)) { $list = array_values($list); $n = count($list); switch ($n) { case 0: break; case 1: $result = strval($list[0]); break; default: $allData = \Punic\Data::get('listPatterns', $locale); $data = null; if (!empty($keys)) { foreach ($keys as $key) { if (array_key_exists($key, $allData)) { $data = $allData[$key]; break; } } } if (is_null($data)) { $data = $allData['standard']; } if (array_key_exists($n, $data)) { $result = vsprintf($data[$n], $list); } else { $result = sprintf($data['end'], $list[$n - 2], $list[$n - 1]); if ($n > 2) { for ($index = $n - 3; $index > 0; $index--) { $result = sprintf($data['middle'], $list[$index], $result); } $result = sprintf($data['start'], $list[0], $result); } } break; } } return $result; }
/** * Return the plural rule ('zero', 'one', 'two', 'few', 'many' or 'other') for a number and a locale * @param string|int|float $number The number to check the plural rule for for * @param string $locale = '' The locale to use. If empty we'll use the default locale set in \Punic\Data * @return string Returns one of the following values: 'zero', 'one', 'two', 'few', 'many', 'other' * @throws \Punic\Exception\BadArgumentType Throws a \Punic\Exception\BadArgumentType if $number is not a valid number * @throws \Exception Throws a \Exception if there were problems calculating the plural rule */ public static function getRule($number, $locale = '') { if (is_int($number)) { $intPartAbs = strval(abs($number)); $floatPart = ''; } elseif (is_float($number)) { $s = strval($number); if (strpos($s, '.') === false) { $intPart = $s; $floatPart = ''; } else { list($intPart, $floatPart) = explode('.', $s); } $intPartAbs = strval(abs(intval($intPart))); } elseif (is_string($number) && strlen($number)) { if (preg_match('/^[+|\\-]?\\d+\\.?$/', $number)) { $v = intval($number); $intPartAbs = strval(abs($v)); $floatPart = ''; } elseif (preg_match('/^(\\d*)\\.(\\d+)$/', $number, $m)) { list($intPart, $floatPart) = explode('.', $number); $v = @intval($intPart); $intPartAbs = strval(abs($v)); } else { throw new Exception\BadArgumentType($number, 'number'); } } else { throw new Exception\BadArgumentType($number, 'number'); } // 'n' => '%1$s', // absolute value of the source number (integer and decimals). $v1 = $intPartAbs . (strlen($floatPart) ? ".{$floatPart}" : ''); // 'i' => '%2$s', // integer digits of n $v2 = $intPartAbs; // 'v' => '%3$s', // number of visible fraction digits in n, with trailing zeros. $v3 = strlen($floatPart); // 'w' => '%4$s', // number of visible fraction digits in n, without trailing zeros. $v4 = strlen(rtrim($floatPart, '0')); // 'f' => '%5$s', // visible fractional digits in n, with trailing zeros. $v5 = strlen($floatPart) ? strval(intval($floatPart)) : '0'; // 't' => '%6$s', // visible fractional digits in n, without trailing zeros. $v6 = trim($floatPart, '0'); if (!strlen($v6)) { $v6 = '0'; } $result = 'other'; $node = \Punic\Data::getLanguageNode(\Punic\Data::getGeneric('plurals'), $locale); foreach ($node as $rule => $formulaPattern) { $formula = sprintf($formulaPattern, $v1, $v2, $v3, $v4, $v5, $v6); $check = str_replace(array('static::inRange(', ' and ', ' or ', ', false, ', ', true, ', ', array('), ' , ', $formula); if (preg_match('/[a-z]/', $check)) { throw new \Exception('Bad formula!'); } // fix for difference in modulo (%) in the definition and the one implemented in PHP for decimal numbers while (preg_match('/(\\d+\\.\\d+) % (\\d+(\\.\\d+)?)/', $formula, $m)) { list(, $decimalPart) = explode('.', $m[1], 2); $decimals = strlen(rtrim($decimalPart, '0')); if ($decimals > 0) { $pow = intval(pow(10, $decimals)); $repl = '(' . strval(intval(floatval($m[1]) * $pow)) . ' % ' . strval(intval(floatval($m[2] * $pow))) . ') / ' . $pow; } else { $repl = strval(intval($m[1])) . ' % ' . $m[2]; } $formula = str_replace($m[0], $repl, $formula); } $formulaResult = @eval("return ({$formula}) ? 'yes' : 'no';"); if ($formulaResult === 'yes') { $result = $rule; break; } elseif ($formulaResult !== 'no') { throw new \Exception('There was a problem in the formula ' . $formulaPattern); } } return $result; }
/** * Format a unit string * @param int|float|string $number The unit amount * @param string $unit The unit identifier (eg 'duration/millisecond' or 'millisecond') * @param string $width = 'short' The format name; it can be 'long' (eg '3 milliseconds'), 'short' (eg '3 ms') or 'narrow' (eg '3ms'). You can also add a precision specifier ('long,2' or just '2') * @param string $locale = '' The locale to use. If empty we'll use the default locale set in \Punic\Data */ public static function format($number, $unit, $width = 'short', $locale = '') { $data = \Punic\Data::get('units', $locale); $precision = null; if (is_int($width)) { $precision = $width; $width = 'short'; } elseif (is_string($width) && preg_match('/^(?:(.*),)?([+\\-]?\\d+)$/', $width, $m)) { $precision = intval($m[2]); $width = $m[1]; if (!strlen($width)) { $width = 'short'; } } if (strpos($width, '_') === 0 || !array_key_exists($width, $data)) { $widths = array(); foreach (array_keys($data) as $w) { if (strpos($w, '_') !== 0) { $widths[] = $w; } } throw new Exception\ValueNotInList($width, $widths); } $data = $data[$width]; if (strpos($unit, '/') === false) { $unitCategory = null; $unitID = null; foreach (array_keys($data) as $c) { if (strpos($c, '_') === false) { if (array_key_exists($unit, $data[$c])) { if (is_null($unitCategory)) { $unitCategory = $c; $unitID = $unit; } else { $unitCategory = null; break; } } } } } else { list($unitCategory, $unitID) = explode('/', $unit, 2); } $rules = null; if (strpos($unit, '_') === false && !is_null($unitCategory) && !is_null($unitID) && array_key_exists($unitCategory, $data) && array_key_exists($unitID, $data[$unitCategory])) { $rules = $data[$unitCategory][$unitID]; } if (is_null($rules)) { $units = array(); foreach ($data as $c => $us) { if (strpos($c, '_') === false) { foreach (array_keys($us) as $u) { if (strpos($c, '_') === false) { $units[] = "{$c}/{$u}"; } } } } throw new \Punic\Exception\ValueNotInList($unit, $units); } $pluralRule = \Punic\Plural::getRule($number, $locale); //@codeCoverageIgnoreStart // These checks aren't necessary since $pluralRule should always be in $rules, but they don't hurt ;) if (!array_key_exists($pluralRule, $rules)) { if (array_key_exists('other', $rules)) { $pluralRule = 'other'; } else { $availableRules = array_keys($rules); $pluralRule = $availableRules[0]; } } //@codeCoverageIgnoreEnd return sprintf($rules[$pluralRule], \Punic\Number::format($number, $precision, $locale)); }
/** * Convert a localized representation of a number to a number (for instance, converts the string '1,234' to 1234 in case of English and to 1.234 in case of Italian) * @param string $value The string value to convert * @param string $locale = '' The locale to use. If empty we'll use the default locale set in \Punic\Data * @return int|float|null Returns null if $value is not valid, the numeric value otherwise */ public static function unformat($value, $locale = '') { $result = null; if (is_int($value) || is_float($value)) { $result = $value; } elseif (is_string($value) && strlen($value)) { $data = \Punic\Data::get('numbers', $locale); $plus = $data['symbols']['plusSign']; $plusQ = preg_quote($plus); $minus = $data['symbols']['minusSign']; $minusQ = preg_quote($minus); $decimal = $data['symbols']['decimal']; $decimalQ = preg_quote($decimal); $group = $data['symbols']['group']; $groupQ = preg_quote($group); $ok = true; if (preg_match('/^' . "({$plusQ}|{$minusQ})?(\\d+(?:{$groupQ}\\d+)*)" . '$/', $value, $m)) { $sign = $m[1]; $int = $m[2]; $float = null; } elseif (preg_match('/^' . "({$plusQ}|{$minusQ})?(\\d+(?:{$groupQ}\\d+)*){$decimalQ}" . '$/', $value, $m)) { $sign = $m[1]; $int = $m[2]; $float = ''; } elseif (preg_match('/^' . "({$plusQ}|{$minusQ})?(\\d+(?:{$groupQ}\\d+)*){$decimalQ}(\\d+)" . '$/', $value, $m)) { $sign = $m[1]; $int = $m[2]; $float = $m[3]; } elseif (preg_match('/^' . "({$plusQ}|{$minusQ})?{$decimalQ}(\\d+)" . '$/', $value, $m)) { $sign = $m[1]; $int = '0'; $float = $m[2]; } else { $ok = false; } if ($ok) { if ($sign === $minus) { $sign = '-'; } else { $sign = ''; } $int = str_replace($group, '', $int); if (is_null($float)) { $result = intval("{$sign}{$int}"); } else { $result = floatval("{$sign}{$int}.{$float}"); } } } return $result; }
/** * To be called every time the current locale changes. * * @param string $locale */ protected function currentLocaleChanged($locale) { PunicData::setDefaultLocale($locale); $app = Facade::getFacadeApplication(); if ($app->bound('director')) { $event = new \Symfony\Component\EventDispatcher\GenericEvent(); $event->setArgument('locale', $locale); $app->make('director')->dispatch('on_locale_load', $event); } }
/** * Describe an relative interval from $dateStart to $dateEnd (eg '2 days ago'). * Only the largest differing unit is described, and the next smaller unit will be used * for rounding. * * @param \DateTime $dateEnd The terminal date * @param \DateTime|null $dateStart The anchor date, defaults to now. (if it has a timezone different than * $dateEnd, we'll use the one of $dateEnd) * @param string $width The format name; it can be '', 'short' or 'narrow' * @param string $locale The locale to use. If empty we'll use the default locale set in \Punic\Data * * @return string * * @throws \InvalidArgumentException */ public static function describeRelativeInterval($dateEnd, $dateStart = null, $width = '', $locale = '') { if (!is_a($dateEnd, '\\DateTime')) { throw new \InvalidArgumentException('Not a DateTime object'); } if (empty($dateStart) && $dateStart !== 0 && $dateStart !== '0') { $dateStart = new \DateTime('now'); } elseif (!is_a($dateStart, '\\DateTime')) { throw new \InvalidArgumentException('Not a DateTime object'); } else { $dateStart = clone $dateStart; } $dateStart->setTimezone($dateEnd->getTimezone()); //$utc = new \DateTimeZone('UTC'); //$dateEndUTC = new \DateTime($dateEnd->format('Y-m-d H:i:s'), $utc); //$dateStartUTC = new \DateTime($dateStart->format('Y-m-d H:i:s'), $utc); $parts = array(); $data = Data::get('dateFields', $locale); $diff = $dateStart->diff($dateEnd, false); $past = (bool) $diff->invert; $value = 0; $key = ''; if ($diff->y != 0) { $key = 'year'; $value = $diff->y + ($diff->m > 6 ? 1 : 0); } elseif ($diff->m != 0) { $key = 'month'; $value = $diff->m + ($diff->d > 15 ? 1 : 0); } elseif ($diff->d != 0) { $key = 'day'; $value = $diff->d + ($diff->h > 12 ? 1 : 0); } elseif ($diff->h != 0) { $key = 'hour'; $value = $diff->h + ($diff->i > 30 ? 1 : 0); } elseif ($diff->i != 0) { $key = 'minute'; $value = $diff->i + ($diff->s > 30 ? 1 : 0); } elseif ($diff->s != 0) { $key = 'second'; $value = $diff->s; } if ($value == 0) { $key = 'second'; $relKey = 'relative-type-0'; $relPattern = null; } elseif ($key === 'day' && $value > 1 && $value < 7) { $dow = $dateEnd->format('N') - 1; $days = array('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'); $key = $days[$dow]; $relKey = $past ? "relative-type--1" : "relative-type-1"; $relPattern = null; } else { if ($value == 1 && isset($data[$key]['relative-type--1'])) { $relKey = $past ? 'relative-type--1' : 'relative-type-1'; $relPattern = null; } else { $relKey = $past ? 'relativeTime-type-past' : 'relativeTime-type-future'; $rule = Plural::getRule($value, $locale); $relPattern = 'relativeTimePattern-count-' . $rule; } } if (!empty($width) && array_key_exists($key . '-' . $width, $data)) { $key .= '-' . $width; } if (empty($relPattern)) { $relativeString = $data[$key][$relKey]; } else { $tempString = $data[$key][$relKey][$relPattern]; $tempString = str_replace('{0}', '%d', $tempString); $relativeString = sprintf($tempString, $value); } return $relativeString; }
/** * Convert a locale designation to a normal form ll_Ssss_CC, where * ll is language code * Ssss is the script code, if specified * CC is the country code, if specified * * @param string $locale locale code * @param string $separator string to use to join locale parts * @param bool $withScript include script if specified, always remove if false * * @return string normalized locale, or empty string on error */ public static function normalizeLocale($locale, $separator = '_', $withScript = true) { try { $keys = Data::explodeLocale($locale); $key = strtolower($keys['language']); $key .= empty($keys['script']) || false === $withScript ? '' : $separator . ucfirst(strtolower($keys['script'])); $key .= empty($keys['territory']) ? '' : $separator . strtoupper($keys['territory']); } catch (InvalidLocale $e) { $key = ''; } return $key; }
/** * detect locale & set cookie if neccesary */ private function initLocale() { $this->locale = $this->detectLocale(); // datetime format if (!setlocale(LC_TIME, $this->locales[$this->locale])) { throw new \Exception(sprintf("Unable to set locale to '%s'", $this->locales[$this->locale])); } // punic default value Data::setDefaultLocale($this->getIETF()); if ('cli' !== PHP_SAPI) { if (!self::request()->getCookie(self::COOKIE_LANGUAGE)) { self::response()->addCookie(new Cookie(self::COOKIE_LANGUAGE, $this->locale, 60 * 60 * 24 * 365)); } } }
protected static function decodeTimezoneDelta(\DateTime $value, $count, $locale) { $offset = $value->getOffset(); $sign = $offset < 0 ? '-' : '+'; $seconds = abs($offset); $hours = intval(floor($seconds / 3600)); $seconds -= $hours * 3600; $minutes = intval(floor($seconds / 60)); $seconds -= $minutes * 60; $partsWithoutSeconds = array(); $partsWithoutSeconds[] = $sign . substr('0' . strval($hours), -2); $partsWithoutSeconds[] = substr('0' . strval($minutes), -2); $partsMaybeWithSeconds = $partsWithoutSeconds; /* @TZWS if ($seconds > 0) { $partsMaybeWithSeconds[] = substr('0' . strval($seconds), -2); } */ switch ($count) { case 1: case 2: case 3: return implode('', $partsMaybeWithSeconds); case 4: $data = \Punic\Data::get('timeZoneNames', $locale); $format = array_key_exists('gmtFormat', $data) ? $data['gmtFormat'] : 'GMT%1$s'; return sprintf($format, implode(':', $partsWithoutSeconds)); case 5: return implode(':', $partsMaybeWithSeconds); default: throw new Exception\ValueNotInList($count, array(1, 2, 3, 4, 5)); } }