Browse Source

Added a PluralRules class to correctly select the plural form for each langauge

Jose Lorenzo Rodriguez 11 years ago
parent
commit
fd11578530
3 changed files with 199 additions and 2 deletions
  1. 3 1
      src/I18n/Formatter/SprintfFormatter.php
  2. 0 1
      src/I18n/I18n.php
  3. 196 0
      src/I18n/PluralRules.php

+ 3 - 1
src/I18n/Formatter/SprintfFormatter.php

@@ -15,6 +15,7 @@
 namespace Cake\I18n\Formatter;
 
 use Aura\Intl\FormatterInterface;
+use Cake\I18n\PluralRules;
 
 /**
  *
@@ -23,7 +24,8 @@ class SprintfFormatter implements FormatterInterface {
 
 	public function format($locale, $message, array $vars) {
 		if (isset($vars['_count']) && !is_string($message)) {
-			$message = $message[$vars['_count'] - 1];
+			$form = PluralRules::calculate($locale, $vars['_count']);
+			$message = $message[$form];
 		}
 
 		return vsprintf($message, $vars);

+ 0 - 1
src/I18n/I18n.php

@@ -24,7 +24,6 @@ use Cake\I18n\Formatter\SprintfFormatter;
 
 /**
  * I18n handles translation of Text and time format strings.
- *
  */
 class I18n {
 

+ 196 - 0
src/I18n/PluralRules.php

@@ -0,0 +1,196 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         3.0.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\I18n;
+
+/**
+ * Utility class used to determine the plural number to be used for a variable
+ * base on the locale
+ */
+class PluralRules {
+
+/**
+ * A map of locale => plurals group used to determine
+ * which plural rules apply to the language
+ *
+ * @var array
+ */
+	protected static $_rulesMap = [
+		'af' => 1,
+		'am' => 2,
+		'ar' => 13,
+		'az' => 1,
+		'be' => 3,
+		'bg' => 1,
+		'bh' => 2,
+		'bn' => 1,
+		'bo' => 0,
+		'bs' => 3,
+		'ca' => 1,
+		'cs' => 4,
+		'cy' => 14,
+		'da' => 1,
+		'de' => 1,
+		'dz' => 0,
+		'el' => 1,
+		'en' => 1,
+		'eo' => 1,
+		'es' => 1,
+		'et' => 1,
+		'eu' => 1,
+		'fa' => 1,
+		'fi' => 1,
+		'fil' => 2,
+		'fo' => 1,
+		'fr' => 2,
+		'fur' => 1,
+		'fy' => 1,
+		'ga' => 5,
+		'gl' => 1,
+		'gu' => 1,
+		'gun' => 2,
+		'ha' => 1,
+		'he' => 1,
+		'hi' => 2,
+		'hr' => 3,
+		'hu' => 1,
+		'id' => 0,
+		'is' => 1,
+		'it' => 1,
+		'ja' => 0,
+		'jv' => 0,
+		'ka' => 0,
+		'km' => 0,
+		'kn' => 0,
+		'ko' => 0,
+		'ku' => 1,
+		'lb' => 1,
+		'ln' => 2,
+		'lt' => 6,
+		'lv' => 10,
+		'mg' => 2,
+		'mk' => 8,
+		'ml' => 1,
+		'mn' => 1,
+		'mr' => 1,
+		'ms' => 0,
+		'mt' => 9,
+		'nah' => 1,
+		'nb' => 1,
+		'ne' => 1,
+		'nl' => 1,
+		'nn' => 1,
+		'no' => 1,
+		'nso' => 2,
+		'om' => 1,
+		'or' => 1,
+		'pa' => 1,
+		'pap' => 1,
+		'pl' => 11,
+		'ps' => 1,
+		'pt_pt' => 2,
+		'pt' => 1,
+		'ro' => 12,
+		'ru' => 3,
+		'sk' => 4,
+		'sl' => 7,
+		'so' => 1,
+		'sq' => 1,
+		'sr' => 3,
+		'sv' => 1,
+		'sw' => 1,
+		'ta' => 1,
+		'te' => 1,
+		'th' => 0,
+		'ti' => 2,
+		'tk' => 1,
+		'tr' => 0,
+		'uk' => 3,
+		'ur' => 1,
+		'vi' => 0,
+		'wa' => 2,
+		'zh' => 0,
+		'zu' => 1,
+	];
+
+/**
+ * Returns the plural form number for the passed locale corresponding
+ * to the countable provided in $n.
+ *
+ * @param string $locale The locale to get the rule calculated for.
+ * @param integer|float $n The number to apply the rules to.
+ * @return integer The plural rule number that should be used.
+ */
+	public static function calculate($locale, $n) {
+		$locale = strtolower($locale);
+
+		if (!isset(static::$_rulesMap[$locale])) {
+			$locale = explode('_', $locale)[0];
+		}
+
+		if (!isset(static::$_rulesMap[$locale])) {
+			return 0;
+		}
+
+		switch (static::$_rulesMap[$locale]) {
+			case 0:
+				return 0;
+			case 1:
+				return $n == 1 ? 0 : 1;
+			case 2:
+				return $n > 1 ? 1 : 0;
+			case 3:
+				return $n % 10 == 1 && $n % 100 != 11 ? 0 :
+					$n %10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2;
+			case 4:
+				return $n == 1 ? 0 :
+					$n >= 2 && $n <= 4 ? 1 : 2;
+			case 5:
+				return $n == 1 ? 0 :
+					$n == 2 ? 1 : 2;
+			case 6:
+				return $n % 10 == 1 && $n % 100 != 11 ? 0 :
+					$n % 10 >=2 && ($n % 100 <10 || $n % 100 >= 20) ? 2 : 1;
+			case 7:
+				return $n % 100 == 1 ? 0 :
+					$n % 100 == 2 ? 1 :
+					($n % 100 == 3 || $n % 100 == 4) ? 2 : 3;
+			case 8:
+				return $n % 10 == 1 ? 0 : 1;
+			case 9:
+				return $n == 1 ? 0 :
+					$n == 0 || ($n % 100 > 0 && $n % 100 <= 10) ? 1 :
+					$n % 100 > 10 && $n % 100 < 20 ? 2 : 3;
+			case 10:
+				return $n %10 == 1 && $n % 100 != 11 ? 1 : $n == 0 ? 0 : 2;
+			case 11:
+				return $n == 1 ? 0 :
+					$n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2;
+			case 12:
+				return $n == 1 ? 0 :
+					$n == 0 || $n % 100 > 0 && $n % 100 < 20 ? 1 : 2;
+			case 13:
+				return $n == 0 ? 0 :
+					$n == 1 ? 1 :
+					$n == 2 ? 2 :
+					$n % 100 >= 3 && $n % 100 <= 10 ? 3 :
+					$n % 100 >= 11 ? 4 : 5;
+			case 14:
+				return $n == 1 ? 0 :
+					$n == 2 ? 1 :
+					$n == 8 || $n == 11 ? 2 : 3;
+		}
+	}
+
+}