aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--phpBB/includes/session.php170
-rw-r--r--phpBB/language/en/common.php5
-rw-r--r--tests/user/lang_test.php18
3 files changed, 192 insertions, 1 deletions
diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php
index 497aaf1141..cd1975b9d3 100644
--- a/phpBB/includes/session.php
+++ b/phpBB/includes/session.php
@@ -1868,12 +1868,15 @@ class user extends session
{
if (is_int($args[$i]))
{
+ $use_plural_form = $this->get_plural_form($args[$i]);
$numbers = array_keys($lang);
foreach ($numbers as $num)
{
- if ($num > $args[$i])
+ if ($num > $use_plural_form)
{
+ // This is basically just some lazy backwards compatible stuff.
+ // If the key we need to use does not exist, it takes the previous one.
break;
}
@@ -1896,6 +1899,171 @@ class user extends session
}
/**
+ * Determine which plural form we should use.
+ * For some languages this is not as simple as for English.
+ */
+ function get_plural_form($number, $force_rule = false)
+ {
+ if ($number == 0)
+ {
+ // We use special language strings for 0, so it's "no users" instead of "0 users"
+ return 0;
+ }
+
+ // Default to english system
+ $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
+ $plural_rule = max(0, min($plural_rule, 15));
+
+ switch ($plural_rule)
+ {
+ case 0:
+ /**
+ * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao
+ * 1 - everything: 1, 2, ...
+ */
+ return 1;
+
+ case 1:
+ /**
+ * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan)
+ * 1 - 1
+ * 2 - everything else: 2, 3, ...
+ */
+ return ($number == 1) ? 1 : 2;
+
+ case 2:
+ /**
+ * Families: Romanic (French, Brazilian Portuguese)
+ * 1 - 1 normaly this would also apply to 0
+ * 2 - everything else: 2, 3, ...
+ */
+ return ($number == 1) ? 1 : 2;
+
+ case 3:
+ /**
+ * Families: Baltic (Latvian)
+ * 1 - ends in 1, not 11: 1, 21, ... 101, 121, ...
+ * 2 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2;
+
+ case 4:
+ /**
+ * Families: Celtic (Scottish Gaelic)
+ * 1 - is 1 or 11: 1, 11
+ * 2 - is 2 or 12: 2, 12
+ * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19
+ * 4 - everything else: 20, 21, ...
+ */
+ return ($number == 1 || $number == 11) ? 1 : (($number == 2 || $number == 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4));
+
+ case 5:
+ /**
+ * Families: Romanic (Romanian)
+ * 1 - 1
+ * 2 - ends in 01-19: 2, 3, ... 19, 101, 102, ... 119, 201, ...
+ * 3 - everything else: 20, 21, ...
+ */
+ return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 6:
+ /**
+ * Families: Baltic (Lithuanian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 0 or ends in 10-20: 10, 11, 12, ... 19, 20, 30, 40, ...
+ * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ...
+ */
+ return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 7:
+ /**
+ * Families: Slavic (Croatian, Serbian, Russian, Ukrainian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ...
+ * 3 - everything else: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ...
+ */
+ return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3);
+
+ case 8:
+ /**
+ * Families: Slavic (Slovak, Czech)
+ * 1 - 1
+ * 2 - 2, 3, 4
+ * 3 - everything else: 5, 6, 7, ...
+ */
+ return ($number == 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3);
+
+ case 9:
+ /**
+ * Families: Slavic (Polish)
+ * 1 - 1
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ...
+ * 3 - everything else: 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ...
+ */
+ return ($number == 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3);
+
+ case 10:
+ /**
+ * Families: Slavic (Slovenian, Sorbian)
+ * 1 - ends in 01: 1, 101, 201, ...
+ * 2 - ends in 02: 2, 102, 202, ...
+ * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ...
+ * 4 - everything else: 5, 6, 7, 8, 9, 10, 11, ...
+ */
+ return ($number % 100 == 1) ? 1 : (($number % 100 == 2) ? 2 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 3 : 4));
+
+ case 11:
+ /**
+ * Families: Celtic (Irish Gaeilge)
+ * 1 - 1
+ * 2 - 2
+ * 3 - is 3-6: 3, 4, 5, 6
+ * 4 - is 7-10: 7, 8, 9, 10
+ * 5 - everything else: 0, 11, 12, ...
+ */
+ return ($number == 1) ? 1 : (($number == 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5)));
+
+ case 12:
+ /**
+ * Families: Semitic (Arabic)
+ * 1 - 1
+ * 2 - 2
+ * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ...
+ * 4 - ends in 11-99: 11, ... 99, 111, 112, ...
+ * 5 - everything else: 100, 101, 102, 200, 201, 202, ...
+ */
+ return ($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)));
+
+ case 13:
+ /**
+ * Families: Semitic (Maltese)
+ * 1 - 1
+ * 2 - ends in 01-10: 2, 3, ... 9, 10, 101, 102, ...
+ * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ...
+ * 4 - everything else: 20, 21, ...
+ */
+ return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4));
+
+ case 14:
+ /**
+ * Families: Slavic (Macedonian)
+ * 1 - ends in 1: 1, 11, 21, ...
+ * 2 - ends in 2: 2, 12, 22, ...
+ * 3 - everything else: 3, 4, ... 10, 13, 14, ... 20, 23, ...
+ */
+ return ($number % 10 == 1) ? 1 : (($number % 10 == 2) ? 2 : 3);
+
+ case 15:
+ /**
+ * Families: Icelandic
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ...
+ * 2 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2;
+ }
+ }
+
+ /**
* Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
*
* @param mixed $lang_set specifies the language entries to include
diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php
index 44a63a6acb..57c9d916a2 100644
--- a/phpBB/language/en/common.php
+++ b/phpBB/language/en/common.php
@@ -45,6 +45,11 @@ $lang = array_merge($lang, array(
'DATE_FORMAT' => '|d M Y|', // 01 Jan 2007 (with Relative days enabled)
'USER_LANG' => 'en-gb',
+ // You can define different rules for the determination of plural forms here.
+ // See http://wiki.phpbb.com/Plural_Rules for more information
+ // or ask the translation manager for help.
+ 'PLURAL_RULE' => 1,
+
'1_DAY' => '1 day',
'1_MONTH' => '1 month',
'1_YEAR' => '1 year',
diff --git a/tests/user/lang_test.php b/tests/user/lang_test.php
index 6c60583a7b..11e981bb7b 100644
--- a/tests/user/lang_test.php
+++ b/tests/user/lang_test.php
@@ -54,5 +54,23 @@ class phpbb_user_lang_test extends phpbb_test_case
// Bug PHPBB3-9949
$this->assertEquals($user->lang('ARRY', 1, 2), '1 post');
$this->assertEquals($user->lang('ARRY', 1, 's', 2), '1 post');
+
+ // Bug PHPBB3-10345
+ $user = new user;
+ $user->lang = array(
+ 'PLURAL_RULE' => 13,
+ 'ARRY' => array(
+ 0 => '%d is 0', // 0
+ 1 => '%d is 1', // 1
+ 2 => '%d ends with 01-10', // ending with 01-10
+ 3 => '%d ends with 11-19', // ending with 11-19
+ 4 => '%d is part of the last rule', // everything else
+ ),
+ );
+ $this->assertEquals($user->lang('ARRY', 0), '0 is 0');
+ $this->assertEquals($user->lang('ARRY', 1), '1 is 1');
+ $this->assertEquals($user->lang('ARRY', 103), '103 ends with 01-10');
+ $this->assertEquals($user->lang('ARRY', 15), '15 ends with 11-19');
+ $this->assertEquals($user->lang('ARRY', 300), '300 is part of the last rule');
}
}