Context in translations in Yii

Hi Qiang,

it's cool that Yii supports context for string translations. However, I believe that the method used, prefixing with [tt]<context>#[/tt] as in [tt]Yii:t("yii#The brown fox ate the monkey")[/tt] is not clear and can pose a problem for translators and copyreaders (usually not technical ppl), since all the strings would have "trash" prepended.

IMHO this should be changed to something like this signature:

Yii:t($string, $context='default');

which is cleaner and easier to work with, and makes the context independent from the translated string. This is similar to the way newer KDE and GNOME both use context (with gettext, which is also missing from Yii… will try to work on that :( ) You can read here and here to see what I’m talking about.

Waiting for comments…

The reason that we put the context inside the message is because this makes message extraction tool easy to work.

For translators/copyreaders, they won't see this context in the messages to be translated.

There's also no conflict with messages containing '#' because we always require that the context is specified before the first '#'.

Did you try "yiic message" tool?

Wow, fast answer :)

Quote

The reason that we put the context inside the message is because this makes message extraction tool easy to work.

I guess so. Is there automatic extraction, as in Prado?

Quote

For translators/copyreaders, they won't see this context in the messages to be translated.

How would this work in the case of a gettext message catalog? In Prado what I do is: strings in templates are extracted automatically as templates are parsed, then strings in code are extracted as the code is executed, and finally, strings in code which were not autoextracted are manually extracted with xgettext. Catalogs are then translated using poEdit, having the .po this format:

msgid "Original string"

msgstr "String originale"

Quote

Did you try "yiic message" tool?

Not yet.

Please check with "yiic message" and see if it fits your need.

You may refer to /framework/messages which contains messages extracted using this tool.

Quote

Please check with "yiic message" and see if it fits your need.

You may refer to /framework/messages which contains messages extracted using this tool.

Ok, I found [tt]yiic message[/tt] extracts the strings to separate PHP files, one per category (or context). This doesn’t fit quite well for my needs, since I need the strings (in fact, I already have thousands of them) in gettext format, all of the messages in one file per locale, with or without context, for instance:

msgctxt "print operation status"


msgid "Printing"


msgstr "Imprimindo"





msgid "Editing"


msgstr "Editando"

So the extractor and merger for this needs to be created (it could be done, let me try in PHP, but we already have [tt]xgettext[/tt], which could fit :wink: ). BTW, I'm sorry, but I must insist that the autosave feature from Prado ruled. Do you plan to integrate it in Yii? I mean, keep [tt]yiic message[/tt] but also have autosave :wink:

Another thing I'm finding different from Prado is that:

localize('Hello {w}', array('w'=>'World'));

is now:

Yii:t('demo#Hello {w}', array('{w}'=>'World'));

, notice the [tt]{}[/tt] sorrounding the substitution variable. Is there any reason for this change? I'll try to modify the extractor to work the old way and to work with context as a parameter and not as a prepended string. If this were successful, may you consider commiting my changes? I really think that the way KDE and GNOME work with context is cleaner and more elegant.

Also, if I do this:

Yii:t('demo#Hello {w}', array('w'=>'World'));

I get [tt]Hello {World}[/tt] , so I think there’s a bug somewhere in the regex…  ::)

Now, my newbie mistakes: I’m modifying the hello world demo from the svn, I have created protected/config/main.php: (mistake found :P  :-[ )

Ok, I experimented a bit with xgettext and:

[tt]xgettext -L PHP --from-code=UTF-8 --keyword=t:1,3c -o messages.po SiteController.php[/tt]

where SiteController.php is:

<?php





/**


 * SiteController is the default controller to handle user requests.


 */


class SiteController extends CController


{


	/**


	 * Index action is the default action in a controller.


	 */


	public function actionIndex()


	{


	   $a = 'World';


		echo Yii::t('Hello {a}', array('{a}'=>$a), 'demo');


		$x = 'Moon';


		echo '<b>' . Yii::t('Goodbye, {m}', array('{m}'=>$x), 'demo') . '</b><b>asdad</b>';


		echo 'asdasd';


	}


}

where demo is the context and got:



# SOME DESCRIPTIVE TITLE.


# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER


# This file is distributed under the same license as the PACKAGE package.


# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.


#


#, fuzzy


msgid ""


msgstr ""


"Project-Id-Version: PACKAGE VERSIONn"


"Report-Msgid-Bugs-To: n"


"POT-Creation-Date: 2008-10-23 15:22-0500n"


"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONEn"


"Last-Translator: FULL NAME <EMAIL@ADDRESS>n"


"Language-Team: LANGUAGE <LL@li.org>n"


"MIME-Version: 1.0n"


"Content-Type: text/plain; charset=CHARSETn"


"Content-Transfer-Encoding: 8bitn"





#: SiteController.php:14


msgctxt "demo"


msgid "Hello {a}"


msgstr ""





#: SiteController.php:16


msgctxt "demo"


msgid "Goodbye, {m}"


msgstr ""

where demo is the context. So far so good. [tt]Yii:t[/tt] could be:

public static function t($message, $params=array(), $context=null)

where, if [tt]$context==null[/tt], then you look for # as usual, but if [tt]$context[/tt] is a string, then you take the context directly from that paramenter (for backwards compatibility and compatibility with [tt]yiic message[/tt]).

I'm convinced, and actually changed Yii::t() as follows:

Yii::t($category,$message,$params=array())

Thank you for your suggestion!

Cool, thanks Qiang!  :D