58 $this->
id =
$info[
'id'];
59 $this->name =
$info[
'name'];
60 $this->supersededBy = isset(
$info[
'supersededBy']) ?
$info[
'supersededBy'] : null;
61 $this->script = isset(
$info[
'script']) ?
$info[
'script'] : null;
62 $this->territory = isset(
$info[
'territory']) ?
$info[
'territory'] : null;
63 $this->baseLanguage = isset(
$info[
'baseLanguage']) ?
$info[
'baseLanguage'] : null;
65 $this->categories =
array();
66 foreach (
$info[
'categories'] as $cldrCategoryId => $cldrFormulaAndExamples) {
67 $category =
new Category($cldrCategoryId, $cldrFormulaAndExamples);
68 foreach ($this->categories as $c) {
69 if ($category->id === $c->id) {
70 throw new Exception(
"The category '{$category->id}' is specified more than once");
73 $this->categories[] = $category;
75 if (empty($this->categories)) {
76 throw new Exception(
"The language '{$info['id']}' does not have any plural category");
79 usort($this->categories,
function (
Category $category1,
Category $category2) {
128 $alwaysTrueCategory = null;
129 foreach ($this->categories as $category) {
130 if ($category->formula ===
true) {
131 if (!isset($category->examples)) {
132 throw new Exception(
"The category '{$category->id}' should always occur, but it does not have examples (so for CLDR it will never occur for integers!)");
134 $alwaysTrueCategory = $category;
138 if (isset($alwaysTrueCategory)) {
139 foreach ($this->categories as $category) {
140 if (($category !== $alwaysTrueCategory) && isset($category->examples)) {
141 throw new Exception(
"The category '{$category->id}' should never occur, but it has some examples (so for CLDR it will occur!)");
145 $alwaysTrueCategory->formula = null;
146 $this->categories =
array($alwaysTrueCategory);
157 foreach ($this->categories as $category) {
158 if ($category->formula ===
false) {
159 if (isset($category->examples)) {
160 throw new Exception(
"The category '{$category->id}' should never occur, but it has examples (so for CLDR it may occur!)");
163 $filtered[] = $category;
166 $this->categories = $filtered;
176 $allCategoriesIds =
array();
177 $goodCategories =
array();
178 $badCategories =
array();
179 $badCategoriesIds =
array();
180 foreach ($this->categories as $category) {
181 $allCategoriesIds[] = $category->id;
182 if (isset($category->examples)) {
183 $goodCategories[] = $category;
185 $badCategories[] = $category;
186 $badCategoriesIds[] = $category->id;
189 if (empty($badCategories)) {
192 $removeCategoriesWithoutExamples =
false;
193 switch (implode(
',', $badCategoriesIds).
'@'.implode(
',', $allCategoriesIds)) {
196 case '(n % 10 == 1 && n % 100 != 11) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : ((n % 10 == 0 || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 11 && n % 100 <= 14) ? 2 : 3))':
212 $removeCategoriesWithoutExamples =
true;
214 case '(n == 1) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : ((n != 1 && (n % 10 == 0 || n % 10 == 1) || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 12 && n % 100 <= 14) ? 2 : 3))':
230 $removeCategoriesWithoutExamples =
true;
234 if (!$removeCategoriesWithoutExamples) {
235 throw new Exception(
"Unhandled case of plural categories without examples '".implode(
', ', $badCategoriesIds).
"' out of '".implode(
', ', $allCategoriesIds).
"'");
239 $lastGood = $goodCategories[count($goodCategories) - 1];
241 $lastGood->formula = null;
243 $this->categories = $goodCategories;
251 $numCategories = count($this->categories);
252 switch ($numCategories) {
257 return self::reduceFormula(self::reverseFormula($this->categories[0]->formula));
259 $formula = strval($numCategories - 1);
260 for (
$i = $numCategories - 2;
$i >= 0;
$i--) {
261 $f = self::reduceFormula($this->categories[
$i]->formula);
262 if (!preg_match(
'/^\([^()]+\)$/', $f)) {
282 if (preg_match(
'/^n( % \d+)? == \d+(\.\.\d+|,\d+)*?$/',
$formula)) {
283 return str_replace(
' == ',
' != ',
$formula);
285 if (preg_match(
'/^n( % \d+)? != \d+(\.\.\d+|,\d+)*?$/',
$formula)) {
286 return str_replace(
' != ',
' == ',
$formula);
288 if (preg_match(
'/^\(?n == \d+ \|\| n == \d+\)?$/',
$formula)) {
289 return trim(str_replace(
array(
' == ',
' || '),
array(
' != ',
' && '),
$formula),
'()');
292 if (preg_match(
'/^(n(?: % \d+)?) == (\d+) && (n(?: % \d+)?) != (\d+)$/',
$formula,
$m)) {
293 return "{$m[1]} != {$m[2]} || {$m[3]} == {$m[4]}";
296 case '(n == 1 || n == 2 || n == 3) || n % 10 != 4 && n % 10 != 6 && n % 10 != 9':
297 return 'n != 1 && n != 2 && n != 3 && (n % 10 == 4 || n % 10 == 6 || n % 10 == 9)';
298 case '(n == 0 || n == 1) || n >= 11 && n <= 99':
299 return 'n >= 2 && (n < 11 || n > 99)';
301 throw new Exception(
"Unable to reverse the formula '$formula'");
311 'n != 0 && n != 1' =>
'n > 1' ,
312 '(n == 0 || n == 1) && n != 0' =>
'n == 1',
324 if (is_string($value) && ($value !==
'')) {
326 $transliterated = strtr($value,
array(
327 'À' =>
'A',
'Á' =>
'A',
'Â' =>
'A',
'Ã' =>
'A',
'Ä' =>
'A',
328 'È' =>
'E',
'É' =>
'E',
'Ê' =>
'E',
'Ë' =>
'E',
329 'Ì' =>
'I',
'Í' =>
'I',
'Î' =>
'I',
'Ï' =>
'I',
331 'Ò' =>
'O',
'Ó' =>
'O',
'Ô' =>
'O',
'Õ' =>
'O',
'Ö' =>
'O',
332 'Ù' =>
'U',
'Ú' =>
'U',
'Û' =>
'U',
'Ü' =>
'U',
333 'Ÿ' =>
'Y',
'Ý' =>
'Y',
334 'à' =>
'a',
'á' =>
'a',
'â' =>
'a',
'ã' =>
'a',
'ä' =>
'a',
335 'è' =>
'e',
'é' =>
'e',
'ê' =>
'e',
'ë' =>
'e',
336 'ì' =>
'i',
'í' =>
'i',
'î' =>
'i',
'ï' =>
'i',
337 'ñ' =>
'n',
'ò' =>
'o',
'ó' =>
'o',
'ô' =>
'o',
'õ' =>
'o',
'ö' =>
'o',
338 'ù' =>
'u',
'ú' =>
'u',
'û' =>
'u',
'ü' =>
'u',
339 'ý' =>
'y',
'ÿ' =>
'y',
341 $transliterated = @iconv(
'UTF-8',
'US-ASCII//IGNORE//TRANSLIT', $transliterated);
342 if (($transliterated ===
false) || ($transliterated ===
'')) {
343 throw new Exception(
"Unable to transliterate '$value'");
345 $value = $transliterated;
354 $clone = clone $this;
355 self::asciifier($clone->name);
356 self::asciifier($clone->formula);
357 $clone->categories =
array();
358 foreach ($this->categories as $category) {
359 $categoryClone = clone $category;
360 self::asciifier($categoryClone->examples);
361 $clone->categories[] = $categoryClone;
getUSAsciiClone()
Returns a clone of this instance with all the strings to US-ASCII.
checkAlwaysFalseCategories()
Let's look for categories that will never occur.
buildFormula()
Build the formula starting from the currently defined categories.
A helper class that handles a single category rules (eg 'zero', 'one', ...) and its formula and examp...
checkAlwaysTrueCategories()
Let's look for categories that will always occur.
static getById($id)
Return a Language instance given the language id.
static getAll()
Return a list of all languages available.
static getLanguageNames()
Returns a dictionary containing the language names.
Main class to convert the plural rules of a language from CLDR to gettext.
static reverseFormula($formula)
Reverse a formula.
static asciifier(&$value)
Take one variable and, if it's a string, we transliterate it to US-ASCII.
static getLanguageInfo($id)
Retrieve the name of a language, as well as if a language code is deprecated in favor of another lang...
Create styles array
The data for the language used.
__construct($info)
Initialize the instance and parse the language code.
static reduceFormula($formula)
Reduce some excessively complex formulas.
checkAllCategoriesWithExamples()
Let's look for categories that don't have examples.