Pluralisation of language strings

177 views
Skip to first unread message

Andrew Eddie

unread,
Apr 15, 2010, 9:16:28 AM4/15/10
to joomla-...@googlegroups.com
Soooo... JM and Dennis Hermatski and I have been throwing around some
ideas about how to handle pluralisation correctly. It's not as simple
as testing for 1 or more than one. There are cases where 0 is
different from 1 which is different from 2, 3 and 4, which is
different from 5 or more ... and the variation differs per language.

What we've come up with is a simple variant on JText::sprintf which
covers most cases easily and gives Russian or similar languages a
workaround. The new function is:

JText::__('KEY', $count [, $arg2])

That's a double underscore there (easy to remember, want plural
support, use a plural underscore).

The first argument is the key, the second is the count. The method
looks for a key like:

KEY_$count which could be something like:

KEY_0
KEY_1
KEY_2
KEY_42

If the key is found, that key will be used. If not, the original KEY
is used. A real example could be:

COM_WEBLINKS_N_ITEMS_DELETED="%d weblinks successfully deleted"
COM_WEBLINKS_N_ITEMS_DELETED_1="%d weblink successfully deleted"

where usage is:

$this->setMessage(JText::__('COM_WEBLINKS_N_ITEMS_DELETED', count($ids)));

As you can see, a zero case can easily be supported, as can any other
number variants. The rule of thumb is to make the main key suit the
broad plural case (usually >1 but sometime >=5 in some languages) and
use the KEY_1, KEY_? for the exceptions.

Seems to be working satisfactorily at the moment.

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer

Ian MacLennan

unread,
Apr 15, 2010, 9:53:18 AM4/15/10
to joomla-...@googlegroups.com
In principal I'm fine with that.  However, note the warning from php.net: PHP reserves all function names starting with __ as magical. It is recommended that you do not use function names with __ in PHP unless you want some documented magic functionality.  (http://ca3.php.net/manual/en/language.oop5.magic.php).  I don't have a good alternative suggestion though.

Ian


--
You received this message because you are subscribed to the Google Groups "Joomla! CMS Development" group.
To post to this group, send an email to joomla-...@googlegroups.com.
To unsubscribe from this group, send email to joomla-dev-cm...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/joomla-dev-cms?hl=en-GB.


Niels Braczek

unread,
Apr 15, 2010, 10:01:45 AM4/15/10
to joomla-...@googlegroups.com
Andrew Eddie schrieb:

> Soooo... JM and Dennis Hermatski and I have been throwing around some
> ideas about how to handle pluralisation correctly.

> [...]


> If the key is found, that key will be used. If not, the original KEY
> is used. A real example could be:
>
> COM_WEBLINKS_N_ITEMS_DELETED="%d weblinks successfully deleted"
> COM_WEBLINKS_N_ITEMS_DELETED_1="%d weblink successfully deleted"

Great solution. Please ensure, that also definitions like

COM_WEBLINKS_N_ITEMS_DELETED="%d weblinks were successfully deleted"
COM_WEBLINKS_N_ITEMS_DELETED_0="No weblink was deleted"
COM_WEBLINKS_N_ITEMS_DELETED_1="The weblink was successfully deleted"

will work with the implementation (i.e., the %d placeholder may or may
not be present).

Niels

Artyom Bisyarin

unread,
Apr 15, 2010, 11:26:34 AM4/15/10
to joomla-...@googlegroups.com
On Thu, 15 Apr 2010 16:16:28 +0300, Andrew Eddie <mamb...@gmail.com>
wrote:

You are read my thoughts? I was thinking about this today.
But, IMHO, your solution is not ideal. As a russian and ukrainian speaker
I found that it is not convenient to specify "count" literally, as a
number.
Instead of "count" we should specify a rule by which words are changing
depending on "count".

For example, I want to print a message which informs a user how much books
were found by its search query.
The word "book" in russian will be "kniga".
The word "found" in russian will be "naidena".

So:
0 knig naideno.
1 kniga naidena.
2-4 knigi naideny.
5-20 knig naideno.
21 kniga naidena.
22-24 knigi naideny.
25-30 knig naideno.
...
100 knig naideno.
101 kniga naidena.
112-114 knigi naideny.
115-120 knig naideno.
121 kniga naidena.

...and so on.


The rule here is that we should print:
- "$count kniga naidena" if `($count % 10 == 1 && $count != 11 && $count
% 100 != 11)`
- "$count knigi naideny" if `($count % 10 > 1 && $count % 10 <= 4 &&
!in_array($count, array(12, 13, 14) && !in_array($count % 100, array(12,
13, 14))`
- "$count knig naideno" in all other cases


How I can use this rule now?
Only from PHP-code. But localization should not touch it. Right?

So I propose to discuss this subject here more thoroughly.

PS:
See how the symfony guys made this:
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/19#chapter_19_sub_translations_with_arguments

--
Artyom

infograf768

unread,
Apr 15, 2010, 12:35:37 PM4/15/10
to Joomla! CMS Development
@Ian
I guess it could easily be changed to JText::plural (on the model of
sprintf)

@Niels
COM_PLUGINS_N_ITEMS_UNPUBLISHED_1="A plugin was successfully disabled"
is working OK.

As well as
MOD_STATUS_MESSAGES="%d Messages"
MOD_STATUS_MESSAGES_0="No message"
MOD_STATUS_MESSAGES_1="A message for you"

with the code
$output[] = "<span class=\"$inboxClass\"><a href=\"$inboxLink\">".
JText::__('MOD_STATUS_MESSAGES', $unread) . "</a></span>";

On 15 avr, 17:26, "Artyom Bisyarin" <arts...@ukr.net> wrote:
> On Thu, 15 Apr 2010 16:16:28 +0300, Andrew Eddie <mambob...@gmail.com>  

> See how the symfony guys made this:http://www.symfony-project.org/jobeet/1_4/Doctrine/en/19#chapter_19_s...
>
> --
> Artyom

Niels Braczek

unread,
Apr 15, 2010, 3:11:56 PM4/15/10
to joomla-...@googlegroups.com
infograf768 schrieb:

> @Niels
> COM_PLUGINS_N_ITEMS_UNPUBLISHED_1="A plugin was successfully disabled"
> is working OK.

Great.

Niels

--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · e-Commerce · Joomla! Content Management |
------------------------------------------------------------------

Niels Braczek

unread,
Apr 15, 2010, 4:11:47 PM4/15/10
to joomla-...@googlegroups.com
Artyom Bisyarin schrieb:

> But, IMHO, your solution is not ideal. As a russian and ukrainian speaker
> I found that it is not convenient to specify "count" literally, as a
> number.

Maybe it is time to refactor the Russian language ;-)

> Instead of "count" we should specify a rule by which words are changing
> depending on "count".
>
> For example, I want to print a message which informs a user how much books
> were found by its search query.
> The word "book" in russian will be "kniga".
> The word "found" in russian will be "naidena".

> [...]


> The rule here is that we should print:
> - "$count kniga naidena" if `($count % 10 == 1 && $count != 11 && $count
> % 100 != 11)`
> - "$count knigi naideny" if `($count % 10 > 1 && $count % 10 <= 4 &&
> !in_array($count, array(12, 13, 14) && !in_array($count % 100, array(12,
> 13, 14))`
> - "$count knig naideno" in all other cases

> [...]

This would lead to definitions like this:

COM_EXAMPLE_N_BOOKS_FOUND="{n: n%10==1 && n%100!=11}%d kniga naidena|{n:
n%10>1 && n%10<5 && (n%100<12 || n%100>14)}%d knigi naideny|[0,+Inf]%d
knig naideno"

The last entry stands for "else", assuming that evaluation is stopped on
the first matching entry.

Parsing such constructs are very time consumpting, but I see the need
for a solution.

Just an idea:
How about defining suffices for the rules in the general xx_XX.ini file,
if needed, since the rules will be the same througout a given language?

COUNT_RULES="{n: n%10==1 && n%100!=11}_1|{n: n%10>1 && n%10<5 &&
(n%100<12 || n%100>14)}_234|[0,+Inf]"

defines suffix _1 for values matching {n: n%10==1 && n%100!=11},
suffix _234 for {n: n%10>1 && n%10<5 && (n%100<12 || n%100>14)} and no
suffix for [0,+Inf], i.e., everything else. In the language file we'd have

COM_EXAMPLE_N_BOOKS_FOUND="%d knig naideno"
COM_EXAMPLE_N_BOOKS_FOUND_1="%d kniga naidena"
COM_EXAMPLE_N_BOOKS_FOUND_234="%d knigi naideny"

If COUNT_RULES is empty or missing, the suffices are interpreted as
literals, as originally proposed.

With this, the rules would be parsed only once (into a string that will
be eval()uated or using lambda functions, with $count as argument. The
language file layout would not change from Andrew's proposal, and
Russian and Ukrainian language can be reflected.

Niels

Mark Dexter

unread,
Apr 15, 2010, 4:31:06 PM4/15/10
to Joomla! CMS Development
Would something like this work?

KEY_0to4="Between 0 and 4"
KEY_5="Five"
KEY_6to10="Between 6 and 10"
KEY="None of the above"

Probably not much performance difference between parsing KEY_5 to be
"$x == 5" and parsing KEY_0to4 to be "$x >= 0 and $x <=4". Mark

On Apr 15, 1:11 pm, Niels Braczek <nbrac...@bsds.de> wrote:
> Artyom Bisyarin schrieb:
>
> > But, IMHO, your solution is not ideal. As a russian and ukrainian speaker  
> > I found that it is not convenient to specify "count" literally, as a  
> > number.
>
> Maybe it is time to refactor the Russian language ;-)
>
>
>
> > Instead of "count" we should specify a rule by which words are changing  
> > depending on "count".
>
> > For example, I want to print a message which informs a user how much books  
> > were found by its search query.
> > The word "book" in russian will be "kniga".
> > The word "found" in russian will be "naidena".
> > [...]
> > The rule here is that we should print:
> >    - "$count kniga naidena" if `($count % 10 == 1 && $count != 11 && $count  
> > % 100 != 11)`
> >    - "$count knigi naideny" if `($count % 10 > 1 && $count % 10 <= 4 &&  
> > !in_array($count, array(12, 13, 14) && !in_array($count % 100, array(12,  
> > 13, 14))`
> >    - "$count knig naideno"  in all other cases
> > [...]
> > See how the symfony guys made this:

> >http://www.symfony-project.org/jobeet/1_4/Doctrine/en/19#chapter_19_s...

Andrew Eddie

unread,
Apr 15, 2010, 6:21:56 PM4/15/10
to joomla-...@googlegroups.com
Thanks Artyom

That was helpful, though daunting to think about :)

Well, my only suggestion is that we keep the current solution for the
easier languages but we add in a rules parser as a special case. This
could be:

FOOBAR_N_ITEMS_DELETED="?{rule1}text1{rule2}text2{else}text3"

So what would happen is that we'd look at the first char of the string
and if we find an ? character (short for 'what the heck is going on
here'), we parse the string for rules. Each rule would just be a
valid PHP conditional test that we run through an eval() (though I
think I would try to disallow function calls, ie, in_array). How does
that sound to everyone?

Mark, that solution won't work because you don't know how many
combinations are in the language keys, and it's not always an easy
range calculation as we've found out.

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer

Niels Braczek

unread,
Apr 15, 2010, 7:10:14 PM4/15/10
to joomla-...@googlegroups.com
Mark Dexter schrieb:

> Would something like this work?
>
> KEY_0to4="Between 0 and 4"
> KEY_5="Five"
> KEY_6to10="Between 6 and 10"
> KEY="None of the above"

This will not solve the repetitive patterns, Artyom mentioned.

Here is a scetch of what could be in JText:

private static function ruleSuffix( $count )
{
static $suffices = null;

if ( is_null( $suffices ) ) {
$suffices = self::getRules();
}
return eval( $suffices );
}

private static function getRules()
{
$ruleSet = self::_( 'COUNT_RULES' );
if ( $ruleSet == 'COUNT_RULES' || empty( $ruleSet ) ) {
return 'return "_".(int)$count;';
}
$rules = explode( '|', $ruleSet );

$suffices = '';
foreach ( $rules as $rule ) {
if ( preg_match( '~^\{\s*(\w+)\:\s*(.*?)\}(.*)$~', $rule, $m ) ) {
// {n: expr(n)}
// $m[1]: var name
// $m[2]: expression
// $m[3]: suffix
$suffices.= 'if ('.preg_replace( '~\b'.$m[1].'\b~',
'$count', $m[2] ).') { return "'.$m[3].'"; }';
} elseif ( preg_match( '~^\{\s*(\w+)\s*\}(.*)$~', $rule, $m ) ) {
// {n,...,m}
// $m[1]: list of values
// $m[2]: suffix
$suffices.= 'if (in_array($count, array('.$m[1].')) { return
"'.$m[2].'"; }';
} elseif ( preg_match(
'~^(\(\[)\s*(.+?)\s*,\s*(.+?)\s*(\)\])(.*)$~', $rule, $m ) ) {
// (n,m), (n,m], [n,m), or [n,m]
// $m[1]: ( or [
// $m[2]: left boundary
// $m[3]: right boundary
// $m[4]: ) or ]
// $m[5]: suffix
$condition = array();
if ( $m[2] != '-Inf' ) {
$condition[] = $m[2].($m[1] == '(' ? '<' : '<=').'$count';
}
if ( $m[3] != '+Inf' ) {
$condition[] = '$count'.($m[4] == ')' ? '<' : '<=').$m[3];
}
$suffices.= 'if ('.implode( '&&', $condition ).') { return
"'.$m[5].'"; }';
} elseif ( preg_match( '~^\[\s*(.+?)\s*\](.*)$~', $rule, $m ) ) {
// [n]
// $m[1]: value
// $m[2]: suffix
$suffices.= 'if ($count=='.$m[1].') { return "'.$m[2].'"; }';
} else {
// unknown rule syntax
}
}
$suffices.= 'return ""; ';
return $suffices;
}

public static function __()
{
...
$key = $args[0].$this->ruleSuffix( $count );
if ( !$lang->hasKey( $key ) ) {
$key = $args[0];
}
...
}

It is not tested, just the approach I would make...

Niels

--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · e-Commerce · Joomla! Content Management |
------------------------------------------------------------------

Niels Braczek

unread,
Apr 15, 2010, 7:14:19 PM4/15/10
to joomla-...@googlegroups.com
Andrew Eddie schrieb:

> That was helpful, though daunting to think about :)
>
> Well, my only suggestion is that we keep the current solution for the
> easier languages but we add in a rules parser as a special case. This
> could be:
>
> FOOBAR_N_ITEMS_DELETED="?{rule1}text1{rule2}text2{else}text3"

Then you have to parse the rules over and over again for each key. I
proposed a solution (as answer on Mark's post), which reduces the
parsing to just once.

Niels

Andrew Eddie

unread,
Apr 15, 2010, 7:18:47 PM4/15/10
to joomla-...@googlegroups.com
I was assuming that the rules could be different for different words.
If that's not the case, then we could just have "one" rule per
language and that would indeed be a lot easier.

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer




Andrew Eddie

unread,
Apr 15, 2010, 7:20:37 PM4/15/10
to joomla-...@googlegroups.com
Hang on, you are still going to have different phrases, so each key is
going to have to be parsed anyway. No?

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer




Niels Braczek

unread,
Apr 15, 2010, 7:30:51 PM4/15/10
to joomla-...@googlegroups.com
Andrew Eddie schrieb:

> Hang on, you are still going to have different phrases, so each key is
> going to have to be parsed anyway. No?

In the general xx_XX.ini file you'll have this:

COUNT_RULES="{n: n%10==1 && n%100!=11}_1|{n: n%10>1 && n%10<5 &&
(n%100<12 || n%100>14)}_234"

The rules are compiled into an eval()uable string.
The component's language file will look like this:

COM_EXAMPLE_N_BOOKS_FOUND="%d knig naideno"
COM_EXAMPLE_N_BOOKS_FOUND_1="%d kniga naidena"
COM_EXAMPLE_N_BOOKS_FOUND_234="%d knigi naideny"

as you originally proposed.

Andrew Eddie

unread,
Apr 15, 2010, 7:32:59 PM4/15/10
to joomla-...@googlegroups.com
Ah, I see. Did that code come from the Symphony code base?

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer




Niels Braczek

unread,
Apr 15, 2010, 7:42:48 PM4/15/10
to joomla-...@googlegroups.com
Andrew Eddie schrieb:

> Ah, I see. Did that code come from the Symphony code base?

No, I just wrote it down to see if the approach would work.

Christophe Demko

unread,
Apr 16, 2010, 5:51:03 AM4/16/10
to Joomla! CMS Development
We can use the same behavior as we use for transliterate: adding a
function in a php file which returns an integer from the number of
items

Rename the file called transliterate.php to localise.php.

In that file consider there is a class called str_replace('-', '',
$lang.'Localise')

in that class, implement two static functions:

-one transliterate (if needed) for transliteration
-the other
publis static function countRule($count)
{
// Return an integer for the rule to be used
}


The integer returned by the countRules function will be used as a
suffix to keys.

Artyom Bisyarin

unread,
Apr 16, 2010, 7:16:47 AM4/16/10
to joomla-...@googlegroups.com
Firstly, thanks for the very interesting ideas.
Andrew and Niels with Christophe have proposed good solutions for the
subject.

I want to say that it's still too risky to define only one rule for a
whole language. It will work with Russian and Ukrainian despite the fact
that they do have many exceptions from general pluralization rule. Simply
this exceptions is simpler then the general rule and count "boundaries" of
when a noun is changing is the same (in the exceptions a noun can
sometimes stay unchanged despite of count). But I know nothing about
languages like Arabic, Chinese, Japanese or Hindi. Maybe we should to
invite speakers of at least these languages to the discussion? I'll try to
do that. If somebody can do that, please, do that.

Also I have few friends with linguistic education and I'll try to talk
with them. But I don't know what it will give for us because one of them
is knower of English and other is a translator from west-slavic languages.
But I think their general linguistic knowledges is better then my.

Here is comparison of the solutions:

Pluralization with dynamic rules (by Andrew)
--------------------------------------------
Usage:
For each string in which we want to properly handle plurals we should
integrate a rule into the translation string.

How it works:
After parsing of this rule we will have a needed string.

Features:
Universality: YES
Optimized for speed: NO
Translation strings readability: NO
Translation strings clarity: YES (because we see a rule immediately)

Pluralization with a common rule (by Niels and Christophe)
--------------------------------------------
Usage:
We should define one rule for all strings of a particular language.
For each string in which we want to properly handle plurals we should
define additional strings for each type of plural form
(TEST_STR_{PLURAL_FORM_SFX}).

How it works:
The rule returns a type of plural form of a noun basing on "count"
variable. To find needed string we add the returned plural form name as a
suffix to translating string name.

Features:
Universality: ???
Optimized for speed: YES
Translation strings readability: YES
Translation strings clarity: NO (because we must know where a rule resides)

--
Artyom

Christophe Demko

unread,
Apr 16, 2010, 8:49:43 AM4/16/10
to Joomla! CMS Development
For having more local rules (but not really trully local), may be the
countRules function could returned an ordered array of potential
suffixes, i.e.:

<?php
abstract class en_GBLocalise {
public static function countRules($count) {
$return = array();
$return[] = (string)$count;
if ($count == 1) {
$return[] = 'UNIQUE';
}
else {
if ($count < 100) {
$return[] = 'TENS';
}
else if ($count < 1000) {
$return[] = 'HUNDREDS';
}
$return[] = 'SEVERAL';
}
return $return;
}
}
var_dump(en_GBLocalise::countRules(1));
var_dump(en_GBLocalise::countRules(25));
var_dump(en_GBLocalise::countRules(150));
var_dump(en_GBLocalise::countRules(1150));

produces

array(2) {
[0]=>
string(1) "1"
[1]=>
string(6) "UNIQUE"
}
array(3) {
[0]=>
string(2) "25"
[1]=>
string(4) "TENS"
[2]=>
string(7) "SEVERAL"
}
array(3) {
[0]=>
string(3) "150"
[1]=>
string(8) "HUNDREDS"
[2]=>
string(7) "SEVERAL"
}
array(2) {
[0]=>
string(4) "1150"
[1]=>
string(7) "SEVERAL"
}

For example, for a given key "KEY_", if the count is 150, the "plural"
function will choose the first defined key between "KEY_150,
KEY_HUNDREDS, KEY_SEVERAL, KEY_"

Note the underscore at the end of KEY_: it will denote for Translation
Team a "plural" string to translate in language files.

Niels Braczek

unread,
Apr 16, 2010, 2:20:06 PM4/16/10
to joomla-...@googlegroups.com
Christophe Demko schrieb:

> We can use the same behavior as we use for transliterate: adding a
> function in a php file which returns an integer from the number of
> items
> Rename the file called transliterate.php to localise.php.
> [...]
> In that file consider there is a class called str_replace('-', '',
> $lang.'Localise')

Ok so far - this would eliminate the parsing totally. Would this file be
part of the basic language pack?

Christophe Demko

unread,
Apr 16, 2010, 2:46:36 PM4/16/10
to Joomla! CMS Development
If we choose this way, we have to put it in the language/xx-XX folder.
If it does not exists, we have to consider that no suffixes will be
added to the keys.

By the way, we also have to deal with multi-plural strings where there
can be two or more plural in the same string.

So the first parameter to the 'plural' function should be a string
(classical case) or an array of strings (multi-plural strings)

Ch.D

Artyom Bisyarin

unread,
Apr 16, 2010, 5:43:10 PM4/16/10
to joomla-...@googlegroups.com
On Fri, 16 Apr 2010 21:46:36 +0300, Christophe Demko <chd...@gmail.com>
wrote:

> By the way, we also have to deal with multi-plural strings where there
> can be two or more plural in the same string.

Thanks for pointing out it. It's very interesting question.

With this even in English phrase with 2 plurals we will end up with 4 keys
in a ini-file:
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_SINGLE_SINGLE = "A book was
found in a second"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL_SINGLE = "%d books was
found in a second"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_SINGLE_PLURAL = "A book was
found in %d seconds"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL_PLURAL = "%d books was
found in %d seconds"

For Russian (9 keys):
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_SINGLE_SINGLE = "Kniga byla
naidena za secundu"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL234_SINGLE = "%d knigi
bylo naideno za secundu"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL_SINGLE = "%d knig bylo
naideno za secundu"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_SINGLE_PLURAL234 = "Kniga byla
naidena za %d secundy"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_SINGLE_PLURAL = "Kniga byla
naidena za %d secund"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL234_PLURAL = "%d knigi
bylo naideno za %d secund"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL234_PLURAL234 = "%d knigi
bylo naideno za %d secundy"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL_PLURAL234 = "%d knig
bylo naideno za %d secundy"
COM_EXAMPLE_N_BOOKS_WAS_FOUND_IN_N_SECONDS_PLURAL_PLURAL = "%d knig bylo
naideno za %d secund"

I think we no doubt should support multi-plural strings, but also an
extension's author should keep in mind that support of multi-plural
strings is a tedious task. But, in any way, is there another ways to do
this? No, I think.

--
Artyom

Niels Braczek

unread,
Apr 16, 2010, 9:28:31 PM4/16/10
to joomla-...@googlegroups.com
Christophe Demko schrieb:

> If we choose this way, we have to put it in the language/xx-XX folder.

Ok. That will work.

> If it does not exists, we have to consider that no suffixes will be
> added to the keys.

Then Andrew's original proposal should be used. It allows plurals in
simple cases without a localise.php.

> By the way, we also have to deal with multi-plural strings where there
> can be two or more plural in the same string.

I think, this will be too complicated (for the first step). In most
cases it will be possible to split multi-plural strings into reasonable
chunks, which again can be combined into one string using
JText::sprintf(). So I suggest to drop this problem for now.

On the other hand it would be useful to be able to override that class.
In German for example, a very simple pluralisation is used (0, 1, more).
*But* readability rules say, that numbers from 1 to 12 should be written
in words instead of numbers. To make it more difficult, there are
exceptions, when combining several numbers within a sentence. Such a
rule surely does not belong to the core or basic packages; but it would
be nice, if it were possible to implement the rule for a specific site.

Christophe Demko

unread,
Apr 17, 2010, 5:49:58 AM4/17/10
to Joomla! CMS Development

> On the other hand it would be useful to be able to override that class.
> In German for example, a very simple pluralisation is used (0, 1, more).
> *But* readability rules say, that numbers from 1 to 12 should be written
> in words instead of numbers. To make it more difficult, there are
> exceptions, when combining several numbers within a sentence. Such a
> rule surely does not belong to the core or basic packages; but it would
> be nice, if it were possible to implement the rule for a specific site.
>

We can imagine a setCountRules function and a getCountRules function
in the same spirit as the getTransliterator and setTransliterator
function

Hannes Papenberg

unread,
Apr 17, 2010, 6:07:13 AM4/17/10
to joomla-...@googlegroups.com
Don't get me wrong, but this all seems extremely complicated to me. I
mean, this sounds like at some point we are going to spend most of the
time calculating the right string to use... Yes, in german you could
write the number in words up to twelve, like you do in english, too. But
nobody would start crying if you just used the number instead. Nobody
would even say a word if you wrote something like "Deleted articles: 8"
instead of "We deleted 8 articles for you". I just don't want to see
people complaining that Joomla is slow, because we created a second
scripting language just to implement pluralisation...

Hannes

Artyom Bisyarin

unread,
Apr 17, 2010, 6:42:08 AM4/17/10
to joomla-...@googlegroups.com
On Fri, 16 Apr 2010 15:49:43 +0300, Christophe Demko <chd...@gmail.com>
wrote:

> For having more local rules (but not really trully local), may be the
> countRules function could returned an ordered array of potential
> suffixes, i.e.:
>
> <?php
> abstract class en_GBLocalise {
> public static function countRules($count) {
> $return = array();
> $return[] = (string)$count;
> if ($count == 1) {
> $return[] = 'UNIQUE';
> }
> else {
> if ($count < 100) {
> $return[] = 'TENS';
> }
> else if ($count < 1000) {
> $return[] = 'HUNDREDS';
> }
> $return[] = 'SEVERAL';
> }
> return $return;
> }
> }

This method does not contain rules. It contain a rule for a whole language.
It returns a noun's plural form name depending on $count.

When I was saying "rules" in my previous posts, I meant that they should
be "$count AND $word" dependent (if we deal with too complex language). In
this case I think we should use something like Andrew's dynamic rules
solution.

But I don't know an example of such a complex language. Thus, so far, your
method is a best solution. Just rename it to "countRule()".

I think that if we would need dynamic rules in the future, then we will
can easily add support for them.

PS:
I had a talk with a west-slavic languages translator. She, preliminary,
said that one rule is enough for those languages. More thorough answer she
can give in Tuesday. But we don't need waiting for it, because "a rule for
a language" solution needed in anyway.

Christophe Demko

unread,
Apr 17, 2010, 7:09:36 AM4/17/10
to Joomla! CMS Development

> But I don't know an example of such a complex language. Thus, so far, your  
> method is a best solution. Just rename it to "countRule()".
>
Only Translation Teams can give an answer to this question.

Ch.D

Artyom Bisyarin

unread,
Apr 17, 2010, 7:18:07 AM4/17/10
to joomla-...@googlegroups.com
On Sat, 17 Apr 2010 14:09:36 +0300, Christophe Demko <chd...@gmail.com>
wrote:

>
>> But I don't know an example of such a complex language. Thus, so far,
>> your method is a best solution. Just rename it to "countRule()".
>>
> Only Translation Teams can give an answer to this question.

Of course. How we can invite them into the discussion?

As a start, I have posted a message to the Chinese forum:
http://forum.joomla.org/viewtopic.php?f=98&t=508161

But no results yet.

--
Artyom

Niels Braczek

unread,
Apr 17, 2010, 7:25:07 AM4/17/10
to joomla-...@googlegroups.com
Hannes Papenberg schrieb:

> Don't get me wrong, but this all seems extremely complicated to me. I
> mean, this sounds like at some point we are going to spend most of the
> time calculating the right string to use...

Well, the plural issue has to be solved. Christoph's solution is the
fastest, I can think of.

> Yes, in german you could
> write the number in words up to twelve, like you do in english, too. But
> nobody would start crying if you just used the number instead. Nobody
> would even say a word if you wrote something like "Deleted articles: 8"
> instead of "We deleted 8 articles for you".

That's why I said, that this should not be a core functionality. But it
should be possible.

> I just don't want to see
> people complaining that Joomla is slow, because we created a second
> scripting language just to implement pluralisation...

There is 1(!) extra overrideable method, which will be very simple
(i.e., empty) for most languages, but has the power to reflect the most
complicated pluralisation rules you can think off. No scripting at all.
Anythimg else is exactly as Andrew proposed. So what you'll see is
people *stopping* complaining that there is no pluralisation.

Niels

Niels Braczek

unread,
Apr 17, 2010, 7:29:38 AM4/17/10
to joomla-...@googlegroups.com
Christophe Demko schrieb:
> I wrote:

>> On the other hand it would be useful to be able to override that class.

> We can imagine a setCountRules function and a getCountRules function
> in the same spirit as the getTransliterator and setTransliterator
> function

Where would the rules be set? From a component?
When using special (individual) rules, it must be througout the site. So
the override has to be installation specific, not component specific.

Niels

Christophe Demko

unread,
Apr 17, 2010, 12:56:08 PM4/17/10
to Joomla! CMS Development
The rule set has to be initially set from the language.

i.e.

<?php
class JLanguage extends JObject {
/**
* Name of the countRules function for this language
*/
protected $_countRules = null;
public function __construct($lang = null, $debug = false) {
$this->_strings = array();
if ($lang == null) {
$lang = $this->_default;
}
$this->setLanguage($lang);
$this->setDebug($debug);
$filename = JPATH_BASE . DS . 'language' . DS . 'overrides' . DS .
$lang . '.override.ini';
if (file_exists($filename) && $contents = $this->_parse($filename))
{
if (is_array($contents)) {
$this->_override = $contents;
}
unset($contents);
}

// Look for a language specific localise class
$class = str_replace('-', '', $lang . 'Localise');
if (!class_exists($class)) {

// Class does not exist. Try to find it in the Site Language Folder
$localise = JPATH_SITE . "/language/$lang/$lang.localise.php";
if (file_exists($localise)) {
require_once $localise;
}
}
if (!class_exists($class)) {

// Class does not exist. Try to find it in the Administrator
Language Folder
$localise = JPATH_ADMINISTRATOR . "/language/$lang/
$lang.localise.php";
if (file_exists($localise)) {
require_once $localise;
}
}
if (class_exists($class)) {
if (method_exists($class, 'countRules')) {
$this->_countRules = array($class, 'countRules');
}
if (method_exists($class, 'transliterate')) {
$this->_transliterator = array($class, 'transliterate');
}
}
}
public function countRules($count) {
if ($this->_countRules !== null) {
return call_user_func($this->_countRules, $count);
}
else {
return array((string)$count);
}
}

/**
* Getter for countRules function
*
* @return string|function Function name or the actual function for
PHP 5.3
* @since 1.6
*/
public function getCountRules() {
return $this->_countRules;
}

/**
* Set the countRules function
*
* @return string|function Function name or the actual function for
PHP 5.3
* @since 1.6
*/
public function setCountRules($function) {
$previous = $this->_countRules;
$this->_countRules = $function;
return $previous;

Christophe Demko

unread,
Apr 19, 2010, 7:16:18 AM4/19/10
to Joomla! CMS Development
Hi Folks,

Can you test the patch here http://joomlacode.org/gf/download/trackeritem/20182/49221/plural.diff

How to test:
-Select the xx-XX lang in the admin
-In the administrator/index.php?option=com_modules&view=modules view,
publish/unpublish 1, 5, 9 modules

The strings used are ~line 42 in administrator/language/xx-XX/xx-
XX.com_modules.ini.

Ch.D

infograf768

unread,
Apr 19, 2010, 9:21:25 AM4/19/10
to Joomla! CMS Development
It does work indeed and consolidate ignore.php and transliterate.php
into a unique file localise.php.
As it is only fired on demand, I see this as a nice addition.
+1, Christophe.

On 19 avr, 13:16, Christophe Demko <chde...@gmail.com> wrote:
> Hi Folks,
>
> Can you test the patch herehttp://joomlacode.org/gf/download/trackeritem/20182/49221/plural.diff

Artyom Bisyarin

unread,
Apr 19, 2010, 1:22:22 PM4/19/10
to joomla-...@googlegroups.com
Very good. I like the new "xx_XXLocalise" class too.

And, you know, I have created "coutRules" method for Russian language and
I am very-very happy now because it works very good.
Thank you very much! :-)

On Mon, 19 Apr 2010 16:21:25 +0300, infograf768 <infog...@gmail.com>
wrote:

> It does work indeed and consolidate ignore.php and transliterate.php
> into a unique file localise.php.
> As it is only fired on demand, I see this as a nice addition.
> +1, Christophe.
>
> On 19 avr, 13:16, Christophe Demko <chde...@gmail.com> wrote:
>> Hi Folks,
>>
>> Can you test the patch
>> herehttp://joomlacode.org/gf/download/trackeritem/20182/49221/plural.diff
>>
>> How to test:
>> -Select the xx-XX lang in the admin
>> -In the administrator/index.php?option=com_modules&view=modules view,
>> publish/unpublish 1, 5, 9 modules
>>
>> The strings used are ~line 42 in administrator/language/xx-XX/xx-
>> XX.com_modules.ini.
>>
>> Ch.D
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Joomla! CMS Development" group.
>> To post to this group, send an email to joomla-...@googlegroups.com.
>> To unsubscribe from this group, send email to
>> joomla-dev-cm...@googlegroups.com.
>> For more options, visit this group
>> athttp://groups.google.com/group/joomla-dev-cms?hl=en-GB.
>


--
Artyom

Andrew Eddie

unread,
Apr 19, 2010, 7:22:34 PM4/19/10
to joomla-...@googlegroups.com
Thanks Christophe. Good work.

Couple of suggestions.

Rename countRules to getPluralSuffix ?
Rename ignoreSearchWords to getIgnoreSearchWords ?

Add the doc blocks for all the methods in the localise class.

Remove the _ prefix from the protected variables in JLanguage (the
PEAR standard is _ only for private vars and we generally don't use
them).

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer




Christophe Demko

unread,
Apr 20, 2010, 5:37:44 AM4/20/10
to Joomla! CMS Development
> Rename countRules to getPluralSuffix ?
> Rename ignoreSearchWords to getIgnoreSearchWords ?
>
We need 3 function by feature:
-pluralSuffixes (give effectively an array of potential suffixes)
-getPluralSuffixes (return the function which computes the array of
potential suffixes)
-setPluralSuffixes (set the function which computes the array of
potential suffixes)

and
-ignoreSearchWords (give effectively an array of ignored search words)
-getIgnoreSearchWords (return the function which computes the array of
ignored search words)
-setIgnoreSearchWords (set the function which computes the array of
ignored search words)

So we cannot name the function getPluralSuffixes or
getIgnoreSearchWords (as they are getters for the functions)

Christophe Demko

unread,
Apr 20, 2010, 7:21:13 AM4/20/10
to Joomla! CMS Development
This is now in trunk

Niels Braczek

unread,
Apr 20, 2010, 7:24:14 AM4/20/10
to joomla-...@googlegroups.com
Christophe Demko schrieb:

> So we cannot name the function getPluralSuffixes or
> getIgnoreSearchWords (as they are getters for the functions)

Since the getters and setters refer to callbacks, wouldn't it make sense
to call them
getPluralSufficesCallback()
setPluralSufficesCallback()
getIgnoreSearchWordsCallback()
setIgnoreSearchWordsCallback()
?

Niels

Christophe Demko

unread,
Apr 20, 2010, 12:36:04 PM4/20/10
to Joomla! CMS Development
It makes sense.
What are the thoughts of the community ?

Artyom Bisyarin

unread,
Apr 20, 2010, 4:27:44 PM4/20/10
to joomla-...@googlegroups.com
On Tue, 20 Apr 2010 19:36:04 +0300, Christophe Demko <chd...@gmail.com>
wrote:

> It makes sense.
> What are the thoughts of the community ?
>
> On 20 avr, 13:24, Niels Braczek <nbrac...@bsds.de> wrote:
>> Christophe Demko schrieb:
>>
>> > So we cannot name the function getPluralSuffixes or
>> > getIgnoreSearchWords (as they are getters for the functions)
>>
>> Since the getters and setters refer to callbacks, wouldn't it make sense
>> to call them
>> getPluralSufficesCallback()
>> setPluralSufficesCallback()
>> getIgnoreSearchWordsCallback()
>> setIgnoreSearchWordsCallback()
>> ?

I also think that "[gs]etXXX" and "[gs]etXXXCallback" is much better names
for the methods. These names telling to the programmer what they are do.

--
Artyom

Christophe Demko

unread,
Apr 22, 2010, 8:16:41 PM4/22/10
to Joomla! CMS Development
It's now in the trunk

On 20 avr, 22:27, "Artyom Bisyarin" <arts...@ukr.net> wrote:
> On Tue, 20 Apr 2010 19:36:04 +0300, Christophe Demko <chde...@gmail.com>  

klas....@gmail.com

unread,
Apr 23, 2010, 12:07:42 PM4/23/10
to joomla-...@googlegroups.com
This and similar language operations should be disabled by default in the core - echo of them is adding overhead to provide something that will be needed only by a small % of people.

Simple solution is to offer this and all other language improvements as an option that must be activated in configuration so that some high traffic english language site does not need to run them. Please turn anything that is not needed by majority of users off by default.

Regards,
Klas


Dne 23. apr. 2010 02:16 je Christophe Demko <chd...@gmail.com> napisal:

JM Simonet

unread,
Apr 24, 2010, 1:59:19 AM4/24/10
to joomla-...@googlegroups.com
Klas,
have you measured the impact of this so that we balance the overhead?
Which similar language operations are you talking about?

Jm

klas....@gmail.com

unread,
Apr 24, 2010, 5:02:16 AM4/24/10
to joomla-...@googlegroups.com
Optionality should be a general rule for anything that happens on the fly and is not needed for all users (not just languages) as any php function that must be performed and is not necessary adds little (or a lot) something to execution time and uses resources. Little by little things get slow even if each one does not add much. I hope it sounds reasonable.

Perhaps make this, transliteration, language switching etc. a system plugin that can be turned on/off (e.g. put empty functions in the core and then overload them in the plugin)?

Regards,
Klas

Dne 24. apr. 2010 07:59 je JM Simonet <infog...@gmail.com> napisal:

Andrew Eddie

unread,
Apr 24, 2010, 6:24:27 AM4/24/10
to joomla-...@googlegroups.com
Hi Klas.

Most of the features are opt-in. That is, there is a check to see if
a function or something is available, and if it is, it's used. In the
case of plural rules or transliteration, you either need them or you
don't, it's not something you need to think about switching on and
off. So the check to see if functionality exists is virtually no
difference than have a switch (you still have an if-statement). In
fact, it's less trouble to do things implicitly than explicitly. I
could be wrong but I think what the guys have done is actually fairly
efficient.

Regards,
Andrew Eddie
http://www.theartofjoomla.com - the art of becoming a Joomla developer




Artyom Bisyarin

unread,
Apr 24, 2010, 8:37:33 AM4/24/10
to joomla-...@googlegroups.com
On Fri, 23 Apr 2010 19:07:42 +0300, <klas....@gmail.com> wrote:

> This and similar language operations should be disabled by default in the
> core - echo of them is adding overhead to provide something that will be
> needed only by a small % of people.

If we will talk about strings with plurals, then the pluralization logic
works only when somebody calls "JText::plural()" method in the code. So,
this logic don't applied to every string.

Also the overhead depends on language. For example, in English we have
very simple rule (in Russian it is much complicated):

public static function getPluralSuffices($count) {
if ($count == 0) {
$return = array('0');
}
elseif($count == 1) {
$return = array('1');
}
else {
$return = array('MORE');
}
return $return;
}

> Simple solution is to offer this and all other language improvements as
> an
> option that must be activated in configuration so that some high traffic
> english language site does not need to run them. Please turn anything
> that
> is not needed by majority of users off by default.

I think that a vast majority of people need to know by default how much
items is in their plural string -- "0", "1" or "MORE". This will help to
create a user's feeling that a real human talks with him through a site,
not a robot.

Moreover, it's up to a language team how friendly to a user they want to
be. It is possible to completely remove
"language/xx-XX/xx-XX.localise.php" file. Then plural, transliteration and
ignoreSearchWords logic will not working. Also you can selectively turn
off one of this logics by removing one of corresponding methods from
xx_XXLocalise's methods.

klas berlič

unread,
Apr 26, 2010, 8:48:22 AM4/26/10
to joomla-...@googlegroups.com
Hi Andrew,

Yes, agree, an implicit way like this is even better. Well thought.

Regards,
Klas

2010/4/24 Andrew Eddie <mamb...@gmail.com>
Reply all
Reply to author
Forward
0 new messages