ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
Gettext\Languages\Language Class Reference

Main class to convert the plural rules of a language from CLDR to gettext. More...

+ Collaboration diagram for Gettext\Languages\Language:

Public Member Functions

 getUSAsciiClone ()
 Returns a clone of this instance with all the strings to US-ASCII. More...
 

Static Public Member Functions

static getAll ()
 Return a list of all languages available. More...
 
static getById ($id)
 Return a Language instance given the language id. More...
 

Data Fields

 $id
 
 $name
 
 $supersededBy
 
 $script
 
 $territory
 
 $baseLanguage
 
 $categories
 
 $formula
 

Private Member Functions

 __construct ($info)
 Initialize the instance and parse the language code. More...
 
 checkAlwaysTrueCategories ()
 Let's look for categories that will always occur. More...
 
 checkAlwaysFalseCategories ()
 Let's look for categories that will never occur. More...
 
 checkAllCategoriesWithExamples ()
 Let's look for categories that don't have examples. More...
 
 buildFormula ()
 Build the formula starting from the currently defined categories. More...
 

Static Private Member Functions

static reverseFormula ($formula)
 Reverse a formula. More...
 
static reduceFormula ($formula)
 Reduce some excessively complex formulas. More...
 
static asciifier (&$value)
 Take one variable and, if it's a string, we transliterate it to US-ASCII. More...
 

Detailed Description

Main class to convert the plural rules of a language from CLDR to gettext.

Definition at line 9 of file Language.php.

Constructor & Destructor Documentation

◆ __construct()

Gettext\Languages\Language::__construct (   $info)
private

Initialize the instance and parse the language code.

Parameters
array$infoThe result of CldrData::getLanguageInfo()
Exceptions
ExceptionThrows an Exception if $fullId is not valid.

Definition at line 56 of file Language.php.

References Gettext\Languages\CldrData\$categories, $info, array, Gettext\Languages\Language\buildFormula(), Gettext\Languages\Language\checkAllCategoriesWithExamples(), Gettext\Languages\Language\checkAlwaysFalseCategories(), Gettext\Languages\Language\checkAlwaysTrueCategories(), and Gettext\Languages\CldrData\OTHER_CATEGORY.

57  {
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;
64  // Let's build the category list
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");
71  }
72  }
73  $this->categories[] = $category;
74  }
75  if (empty($this->categories)) {
76  throw new Exception("The language '{$info['id']}' does not have any plural category");
77  }
78  // Let's sort the categories from 'zero' to 'other'
79  usort($this->categories, function (Category $category1, Category $category2) {
80  return array_search($category1->id, CldrData::$categories) - array_search($category2->id, CldrData::$categories);
81  });
82  // The 'other' category should always be there
83  if ($this->categories[count($this->categories) - 1]->id !== CldrData::OTHER_CATEGORY) {
84  throw new Exception("The language '{$info['id']}' does not have the '".CldrData::OTHER_CATEGORY."' plural category");
85  }
89  $this->formula = $this->buildFormula();
90  }
checkAlwaysFalseCategories()
Let's look for categories that will never occur.
Definition: Language.php:154
buildFormula()
Build the formula starting from the currently defined categories.
Definition: Language.php:249
checkAlwaysTrueCategories()
Let's look for categories that will always occur.
Definition: Language.php:126
Create styles array
The data for the language used.
checkAllCategoriesWithExamples()
Let's look for categories that don't have examples.
Definition: Language.php:174
$info
Definition: index.php:5
+ Here is the call graph for this function:

Member Function Documentation

◆ asciifier()

static Gettext\Languages\Language::asciifier ( $value)
staticprivate

Take one variable and, if it's a string, we transliterate it to US-ASCII.

Parameters
mixed$valueThe variable to work on.
Exceptions
Exception

Definition at line 322 of file Language.php.

References array.

323  {
324  if (is_string($value) && ($value !== '')) {
325  // Avoid converting from 'Ÿ' to '"Y', let's prefer 'Y'
326  $transliterated = strtr($value, array(
327  'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A',
328  'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E',
329  'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I',
330  'Ñ' => 'N',
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',
340  ));
341  $transliterated = @iconv('UTF-8', 'US-ASCII//IGNORE//TRANSLIT', $transliterated);
342  if (($transliterated === false) || ($transliterated === '')) {
343  throw new Exception("Unable to transliterate '$value'");
344  }
345  $value = $transliterated;
346  }
347  }
Create styles array
The data for the language used.

◆ buildFormula()

Gettext\Languages\Language::buildFormula ( )
private

Build the formula starting from the currently defined categories.

Returns
string

Definition at line 249 of file Language.php.

References Gettext\Languages\Language\$formula, and $i.

Referenced by Gettext\Languages\Language\__construct(), and Gettext\Languages\Language\checkAllCategoriesWithExamples().

250  {
251  $numCategories = count($this->categories);
252  switch ($numCategories) {
253  case 1:
254  // Just one category
255  return '0';
256  case 2:
257  return self::reduceFormula(self::reverseFormula($this->categories[0]->formula));
258  default:
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)) {
263  $f = "($f)";
264  }
265  $formula = "$f ? $i : $formula";
266  if ($i > 0) {
267  $formula = "($formula)";
268  }
269  }
270 
271  return $formula;
272  }
273  }
$i
Definition: disco.tpl.php:19
+ Here is the caller graph for this function:

◆ checkAllCategoriesWithExamples()

Gettext\Languages\Language::checkAllCategoriesWithExamples ( )
private

Let's look for categories that don't have examples.

This because with decimals (CLDR) we may have more cases, with integers (gettext) we have some less cases. If we found those categories, we check that they never occur and we strip them out.

Exceptions
Exception

Definition at line 174 of file Language.php.

References array, Gettext\Languages\Language\buildFormula(), and Gettext\Languages\CldrData\OTHER_CATEGORY.

Referenced by Gettext\Languages\Language\__construct().

175  {
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;
184  } else {
185  $badCategories[] = $category;
186  $badCategoriesIds[] = $category->id;
187  }
188  }
189  if (empty($badCategories)) {
190  return;
191  }
192  $removeCategoriesWithoutExamples = false;
193  switch (implode(',', $badCategoriesIds).'@'.implode(',', $allCategoriesIds)) {
195  switch ($this->buildFormula()) {
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))':
197  // Numbers ending with 0 => case 2 ('many')
198  // Numbers ending with 1 but not with 11 => case 0 ('one')
199  // Numbers ending with 11 => case 2 ('many')
200  // Numbers ending with 2 but not with 12 => case 1 ('few')
201  // Numbers ending with 12 => case 2 ('many')
202  // Numbers ending with 3 but not with 13 => case 1 ('few')
203  // Numbers ending with 13 => case 2 ('many')
204  // Numbers ending with 4 but not with 14 => case 1 ('few')
205  // Numbers ending with 14 => case 2 ('many')
206  // Numbers ending with 5 => case 2 ('many')
207  // Numbers ending with 6 => case 2 ('many')
208  // Numbers ending with 7 => case 2 ('many')
209  // Numbers ending with 8 => case 2 ('many')
210  // Numbers ending with 9 => case 2 ('many')
211  // => the 'other' case never occurs: use 'other' for 'many'
212  $removeCategoriesWithoutExamples = true;
213  break;
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))':
215  // Numbers ending with 0 => case 2 ('many')
216  // Numbers ending with 1 but not number 1 => case 2 ('many')
217  // Number 1 => case 0 ('one')
218  // Numbers ending with 2 but not with 12 => case 1 ('few')
219  // Numbers ending with 12 => case 2 ('many')
220  // Numbers ending with 3 but not with 13 => case 1 ('few')
221  // Numbers ending with 13 => case 2 ('many')
222  // Numbers ending with 4 but not with 14 => case 1 ('few')
223  // Numbers ending with 14 => case 2 ('many')
224  // Numbers ending with 5 => case 2 ('many')
225  // Numbers ending with 6 => case 2 ('many')
226  // Numbers ending with 7 => case 2 ('many')
227  // Numbers ending with 8 => case 2 ('many')
228  // Numbers ending with 9 => case 2 ('many')
229  // => the 'other' case never occurs: use 'other' for 'many'
230  $removeCategoriesWithoutExamples = true;
231  break;
232  }
233  }
234  if (!$removeCategoriesWithoutExamples) {
235  throw new Exception("Unhandled case of plural categories without examples '".implode(', ', $badCategoriesIds)."' out of '".implode(', ', $allCategoriesIds)."'");
236  }
237  if ($badCategories[count($badCategories) - 1]->id === CldrData::OTHER_CATEGORY) {
238  // We're removing the 'other' cagory: let's change the last good category to 'other'
239  $lastGood = $goodCategories[count($goodCategories) - 1];
240  $lastGood->id = CldrData::OTHER_CATEGORY;
241  $lastGood->formula = null;
242  }
243  $this->categories = $goodCategories;
244  }
buildFormula()
Build the formula starting from the currently defined categories.
Definition: Language.php:249
Create styles array
The data for the language used.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ checkAlwaysFalseCategories()

Gettext\Languages\Language::checkAlwaysFalseCategories ( )
private

Let's look for categories that will never occur.

This because with decimals (CLDR) we may have more cases, with integers (gettext) we have some less cases. If we found those categories we strip them out.

Definition at line 154 of file Language.php.

References array.

Referenced by Gettext\Languages\Language\__construct().

155  {
156  $filtered = array();
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!)");
161  }
162  } else {
163  $filtered[] = $category;
164  }
165  }
166  $this->categories = $filtered;
167  }
Create styles array
The data for the language used.
+ Here is the caller graph for this function:

◆ checkAlwaysTrueCategories()

Gettext\Languages\Language::checkAlwaysTrueCategories ( )
private

Let's look for categories that will always occur.

This because with decimals (CLDR) we may have more cases, with integers (gettext) we have just one case. If we found that (single) category we reduce the categories to that one only.

Definition at line 126 of file Language.php.

References array, and Gettext\Languages\CldrData\OTHER_CATEGORY.

Referenced by Gettext\Languages\Language\__construct().

127  {
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!)");
133  }
134  $alwaysTrueCategory = $category;
135  break;
136  }
137  }
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!)");
142  }
143  }
144  $alwaysTrueCategory->id = CldrData::OTHER_CATEGORY;
145  $alwaysTrueCategory->formula = null;
146  $this->categories = array($alwaysTrueCategory);
147  }
148  }
Create styles array
The data for the language used.
+ Here is the caller graph for this function:

◆ getAll()

static Gettext\Languages\Language::getAll ( )
static

Return a list of all languages available.

Exceptions
Exception
Returns
Language[]

Definition at line 96 of file Language.php.

References $result, array, Gettext\Languages\CldrData\getLanguageInfo(), and Gettext\Languages\CldrData\getLanguageNames().

97  {
98  $result = array();
99  foreach (array_keys(CldrData::getLanguageNames()) as $cldrLanguageId) {
100  $result[] = new Language(CldrData::getLanguageInfo($cldrLanguageId));
101  }
102 
103  return $result;
104  }
$result
static getLanguageNames()
Returns a dictionary containing the language names.
Definition: CldrData.php:140
static getLanguageInfo($id)
Retrieve the name of a language, as well as if a language code is deprecated in favor of another lang...
Definition: CldrData.php:199
Create styles array
The data for the language used.
+ Here is the call graph for this function:

◆ getById()

static Gettext\Languages\Language::getById (   $id)
static

Return a Language instance given the language id.

Parameters
string$id
Returns
Language|null

Definition at line 110 of file Language.php.

References Gettext\Languages\Language\$id, $info, $result, and Gettext\Languages\CldrData\getLanguageInfo().

111  {
112  $result = null;
114  if (isset($info)) {
115  $result = new Language($info);
116  }
117 
118  return $result;
119  }
$result
static getLanguageInfo($id)
Retrieve the name of a language, as well as if a language code is deprecated in favor of another lang...
Definition: CldrData.php:199
$info
Definition: index.php:5
+ Here is the call graph for this function:

◆ getUSAsciiClone()

Gettext\Languages\Language::getUSAsciiClone ( )

Returns a clone of this instance with all the strings to US-ASCII.

Returns
Language

Definition at line 352 of file Language.php.

References array.

353  {
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;
362  }
363 
364  return $clone;
365  }
Create styles array
The data for the language used.

◆ reduceFormula()

static Gettext\Languages\Language::reduceFormula (   $formula)
staticprivate

Reduce some excessively complex formulas.

Parameters
string$formula
Returns
string

Definition at line 308 of file Language.php.

References Gettext\Languages\Language\$formula, and array.

309  {
310  $map = array(
311  'n != 0 && n != 1' => 'n > 1' ,
312  '(n == 0 || n == 1) && n != 0' => 'n == 1',
313  );
314 
315  return isset($map[$formula]) ? $map[$formula] : $formula;
316  }
Create styles array
The data for the language used.

◆ reverseFormula()

static Gettext\Languages\Language::reverseFormula (   $formula)
staticprivate

Reverse a formula.

Parameters
string$formula
Exceptions
Exception
Returns
string

Definition at line 280 of file Language.php.

References Gettext\Languages\Language\$formula, $m, and array.

281  {
282  if (preg_match('/^n( % \d+)? == \d+(\.\.\d+|,\d+)*?$/', $formula)) {
283  return str_replace(' == ', ' != ', $formula);
284  }
285  if (preg_match('/^n( % \d+)? != \d+(\.\.\d+|,\d+)*?$/', $formula)) {
286  return str_replace(' != ', ' == ', $formula);
287  }
288  if (preg_match('/^\(?n == \d+ \|\| n == \d+\)?$/', $formula)) {
289  return trim(str_replace(array(' == ', ' || '), array(' != ', ' && '), $formula), '()');
290  }
291  $m = null;
292  if (preg_match('/^(n(?: % \d+)?) == (\d+) && (n(?: % \d+)?) != (\d+)$/', $formula, $m)) {
293  return "{$m[1]} != {$m[2]} || {$m[3]} == {$m[4]}";
294  }
295  switch ($formula) {
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)';
300  }
301  throw new Exception("Unable to reverse the formula '$formula'");
302  }
Create styles array
The data for the language used.

Field Documentation

◆ $baseLanguage

Gettext\Languages\Language::$baseLanguage

Definition at line 40 of file Language.php.

◆ $categories

Gettext\Languages\Language::$categories

Definition at line 45 of file Language.php.

◆ $formula

◆ $id

Gettext\Languages\Language::$id

Definition at line 15 of file Language.php.

Referenced by Gettext\Languages\Language\getById().

◆ $name

Gettext\Languages\Language::$name

Definition at line 20 of file Language.php.

◆ $script

Gettext\Languages\Language::$script

Definition at line 30 of file Language.php.

◆ $supersededBy

Gettext\Languages\Language::$supersededBy

Definition at line 25 of file Language.php.

◆ $territory

Gettext\Languages\Language::$territory

Definition at line 35 of file Language.php.


The documentation for this class was generated from the following file: