ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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.

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 }
checkAllCategoriesWithExamples()
Let's look for categories that don't have examples.
Definition: Language.php:174
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
checkAlwaysFalseCategories()
Let's look for categories that will never occur.
Definition: Language.php:154
$info
Definition: index.php:5

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

+ 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.

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 }

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

+ Here is the caller graph for this function:

◆ 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.

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 }
static reduceFormula($formula)
Reduce some excessively complex formulas.
Definition: Language.php:308
$i
Definition: disco.tpl.php:19

References $f, Gettext\Languages\Language\$formula, $i, and Gettext\Languages\Language\reduceFormula().

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

+ Here is the call graph for this function:
+ 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.

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 }

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

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

+ 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.

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 }

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

+ 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.

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 }

References Gettext\Languages\CldrData\OTHER_CATEGORY.

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

+ 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.

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

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

+ 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.

111 {
112 $result = null;
114 if (isset($info)) {
115 $result = new Language($info);
116 }
117
118 return $result;
119 }

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

+ 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.

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 }
static asciifier(&$value)
Take one variable and, if it's a string, we transliterate it to US-ASCII.
Definition: Language.php:322

References Gettext\Languages\Language\asciifier().

+ Here is the call graph for this function:

◆ 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.

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 }

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

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

+ Here is the caller graph for this function:

◆ 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.

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 }

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

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: