News:

Want to get involved in developing SMF, then why not lend a hand on our github!

Main Menu

[4822] I18N issue with $txt['members']

Started by ke, August 23, 2011, 07:29:00 AM

Previous topic - Next topic

ke

Thanks for taking care of this, guys.

Quote from: Dzonny on September 07, 2011, 05:07:39 AM
I agree with you all, but the most important for now is to know where exactly issues are. When we know about it we will discuss about how those problem should be resolved. I dont think that all 60 words is used in different cases though. I will test this during the day.

Basically, all $txt elements that consist of a single word (or other fragments) are suspicious. The only exception I can think of is labels for buttons and other navigational elements whose whole label indeed consists of just one word. But whenever even the tiniest message is concatenated from more than one $txt entry, as in the example in my original post, you can be sure that it will create problems for translation into one language or another. Translators may be able to work around these issues in many cases. For example, to answer Angelina's question:

Quote from: AngelinaBelle on August 29, 2011, 08:20:36 AMIn the example you give, would it also be proper to use dative form of the noun "topics" following the preposition "in"?

Yes, in, like von, requires dative case (in this context!). However, unlike Mitglieder/n, the nominative and dative form of Themen happen to be the identical.

But in general, word-by-word translation is not possible.

Therefore, in my opinion, developers should aim for all $txt elements to be complete message templates. Nowhere in the codebase should they enter into concatenation with each other.

Joshua Dickerson

ke, I am not sure if your last statement would hold true for everything, but you're absolutely right about looking in to more cases.
Come work with me at Promenade Group



Need help? See the wiki. Want to help SMF? See the wiki!

Did you know you can help develop SMF? See us on Github.

How have you bettered the world today?

emanuele

Yesterday evening I started a new branch that I would like to integrate into 2.1, and changed some strings to sprintf:
https://github.com/emanuele45/playpen/commits/l10n/
here you can see the list of changes so far:
https://github.com/emanuele45/playpen/compare/master...l10n

I hope to be able to spot more places where something should be changed, and I hope to receive suggestions from you too since I'm sure I'll not be able to find all of the strings that need to be replaced with something else. ;)

Thinking more about the future, keeping in mind SMF translation structure, looking at how drupal does it (just because poolhall posted a link to drupal's api) and looking at how I named the $txts in my changes one possible approach could be:
function define_plural ($string, $count, $find, $replace)
{
    global $txt;

    if (empty($count))
        $return = $txt[$string . '_zero'];
    elseif ($count == 1)
        $return = $txt[$string . '_one'];
    else
        $return = sprintf($string . '_many', $count);

    if (!empty($find) && count($find) == count($replace))
        foreach ($find as $key => $val)
            $return = str_replace($val, $replace[$key], $return;

    return $return;
}


Unfortunately that function should be placed in a language file and adapted by each localizer/translator to match each language plural rule.

At the moment I don't have any other idea, but that's for the future, for now I'd really like to find all the current places where sprintf could give a better result than what we have now. ;)


Take a peek at what I'm doing! ;D




Hai bisogno di supporto in Italiano?

Aiutateci ad aiutarvi: spiegate bene il vostro problema: no, "non funziona" non è una spiegazione!!
1) Cosa fai,
2) cosa ti aspetti,
3) cosa ottieni.

Angelina Belle

In SSI.php,
sprintf($txt['welcome_newest_member'], ' ' . $context['common_stats']['latest_member']['link'])
Code (replace) Select
sprintf($txt['welcome_newest_member'],  $context['common_stats']['latest_member']['link'])

Because
txt['welcome_newest_member'] = 'Please welcome %1$s, our newest member.';

Your work toward better translation of plural is a good start, emanuel, but I think this will need more study before it is added to SMF.  The world plural situation is more complex than that.  Consider polish, which has much more complicated rules than other languages.
http://doc.qt.nokia.com/qq/qq19-plurals.html
Nokia has attempted to provide an easy plural tool for its QT framework. I don't know what the implementation looks like, of course.

Never attribute to malice that which is adequately explained by stupidity. -- Hanlon's Razor

emanuele

That's why I said his function should stay in the language file, so that any translation could have it's own way to handle plural, for example for Polish could be something like:
function define_plural ($string, $count, $find, $replace)
{
    global $txt;

    if ($count == 1)
        $return = $txt[$string . '_one'];
    else
    {
        $last_digit = substr($count, -1);
        if (in_array($last_digit, array(2, 3, 4))
            $return = sprintf($string . '_many_1', $count);
        else
            $return = sprintf($string . '_many_2', $count);
    }

    if (!empty($find) && count($find) == count($replace))
        foreach ($find as $key => $val)
            $return = str_replace($val, $replace[$key], $return;

    return $return;
}


That's not something that I would really make it generic and valid for any language. I think the best option is to allow each language to handle their own set of rules.

Of course it's just an idea, nothing really solid.


Take a peek at what I'm doing! ;D




Hai bisogno di supporto in Italiano?

Aiutateci ad aiutarvi: spiegate bene il vostro problema: no, "non funziona" non è una spiegazione!!
1) Cosa fai,
2) cosa ti aspetti,
3) cosa ottieni.

Angelina Belle

I guess I follow.  Polish is still more complicated than that, of course. The "many_2" form comes back to haunt us every decade, I think.
The nokia idea is to use "%n noun" in strings, and the replacer is smart enough to replace %n with the number, and replace "noun" with the appropriate plural, based on the value of the number.  This requires an entire dictionary, however, which SMF does not have.
Never attribute to malice that which is adequately explained by stupidity. -- Hanlon's Razor

emanuele

The code above will result in exactly the table presented in the page you posted, so:
11 domów
12 domy
13 domy
14 domy
15 domów
16 domów
17 domów
18 domów
19 domów
21 domów
22 domy
23 domy
24 domy
25 domów
26 domów
27 domów
...
101 domów
102 domy
103 domy
104 domy
105 domów
etc.

ETA: and of course, since this would be custom code for each language, each language could code their own grammar rules.
If a language has 3 way to define the "many" then they could introduce such a system without affecting any other language.
I remember Dr. Deejay once reported that Chinese doesn't have Arabic numbers, so for the Chinese the function could be (taking *as example* the easiest version):

function define_plural ($string, $count, $find, $replace)
{
    global $txt;

    $count_number = array(
        0 => 'zero', //the equivalent Chinese version of course
        1 => 'one', //the equivalent Chinese version of course
        2 => 'two', //the equivalent Chinese version of course
        3 => 'three', //the equivalent Chinese version of course
        4 => 'four', //the equivalent Chinese version of course
        5 => 'five', //the equivalent Chinese version of course
        6 => 'six', //the equivalent Chinese version of course
        7 => 'seven', //the equivalent Chinese version of course
        8 => 'eight', //the equivalent Chinese version of course
        9 => 'nine', //the equivalent Chinese version of course
    );

    if (empty($count))
        $return = $txt[$string . '_zero'];
    elseif ($count == 1)
        $return = $txt[$string . '_one'];
    else
        $return = sprintf($string . '_many', $count_number[$count]);

    if (!empty($find) && count($find) == count($replace))
        foreach ($find as $key => $val)
            $return = str_replace($val, $replace[$key], $return;

    return $return;
}


Take a peek at what I'm doing! ;D




Hai bisogno di supporto in Italiano?

Aiutateci ad aiutarvi: spiegate bene il vostro problema: no, "non funziona" non è una spiegazione!!
1) Cosa fai,
2) cosa ti aspetti,
3) cosa ottieni.

Angelina Belle

OK.  I guess I just didn't read it through hard enough.
and it is easy enough to deal with all the different pluralizations of all languages, like Russian and Inuit (or whatever).

So that seems like an excellent proposal. 

Never attribute to malice that which is adequately explained by stupidity. -- Hanlon's Razor

emanuele

Quote from: AngelinaBelle on September 11, 2012, 08:37:27 AM
In SSI.php,
sprintf($txt['welcome_newest_member'], ' ' . $context['common_stats']['latest_member']['link'])
Code (replace) Select
sprintf($txt['welcome_newest_member'],  $context['common_stats']['latest_member']['link'])

Because
txt['welcome_newest_member'] = 'Please welcome %1$s, our newest member.';
Fixed that one and added another series of things more or less related.


Take a peek at what I'm doing! ;D




Hai bisogno di supporto in Italiano?

Aiutateci ad aiutarvi: spiegate bene il vostro problema: no, "non funziona" non è una spiegazione!!
1) Cosa fai,
2) cosa ti aspetti,
3) cosa ottieni.

Bugo

I'm using simple function for this.

Example 1 with BoardIndex.template.php, find
$board['is_redirect'] ? $txt['redirects'] : $txt['posts']
replace with:
rspack_declension($board['posts'], $board['is_redirect'] ? $txt['rspack_redirect'] : $txt['rspack_post'])

Example 2, find
$context['common_stats']['total_posts'], ' ', $txt['posts_made'], ' ', $txt['in'], ' ', $context['common_stats']['total_topics'], ' ', $txt['topics'], ' ', $txt['by'], ' ', $context['common_stats']['total_members'], ' ', $txt['members']
replace with
$context['common_stats']['total_posts'], ' ', rspack_declension($context['common_stats']['total_posts'], $txt['rspack_post']), ' ', $txt['in'], ' ', $context['common_stats']['total_topics'], ' ', rspack_declension($context['common_stats']['total_topics'], $txt['rspack_topic']), ' ', $txt['by'], ' ', $context['common_stats']['total_members'], ' ', rspack_declension($context['common_stats']['total_members'], isset($txt['rspack_user1']) ? $txt['rspack_user1'] : $txt['rspack_user'])

English language file:
$txt['rspack_post'] = 'posts, post';
$txt['rspack_user'] = 'members, member';
$txt['rspack_redirect'] = 'redirects, redirect';


Russian language file:
$txt['rspack_post'] = 'сообщений, сообщение, сообщения';
$txt['rspack_user'] = 'пользователей, пользователь, пользователя';
$txt['rspack_user1'] = 'пользователей, пользователя';
$txt['rspack_redirect'] = 'переходов, переход, перехода';


Ukrainian:
$txt['rspack_post'] = 'повідомлень, повідомлення, повідомлення';
$txt['rspack_user'] = 'користувачів, користувач, користувача';
$txt['rspack_user1'] = 'користувачів, користувача';
$txt['rspack_redirect'] = 'переходів, перехід, переходи';


Subs.php:

function rspack_declension($num, $str)
{
$exp = explode(',', $str);

$num = (($num < 0) ? $num-$num*2 : $num)%100;
$dig = ($num > 20) ? $num%10 : $num;

if (sizeof($exp) == 2) {
        $exp[2] = $exp[0];
    }

return trim((($dig == 1) ? $exp[1] : (($dig > 4 || $dig < 1) ? $exp[0] : $exp[2])));
}

emanuele

I closed the issue.
But since the discussion here is much more complex I'll not move the topic in order to facilitate further discussions.


Take a peek at what I'm doing! ;D




Hai bisogno di supporto in Italiano?

Aiutateci ad aiutarvi: spiegate bene il vostro problema: no, "non funziona" non è una spiegazione!!
1) Cosa fai,
2) cosa ti aspetti,
3) cosa ottieni.

Advertisement: