11

Using gettext

Single value

echo gettext( "Hello, world!\n" );

Plurals

printf(ngettext("%d comment", "%d comments", $n), $n);

English homonym?

echo gettext("Letter");// as in mail, for Russian outputs "письмо"
echo gettext("Letter");// as in character, for Russian outputs "буква" 

Same with the english word "character", it can be the character of a person or a letter! How is gettext supposed to identify the right translation for homonyms?

Timo Huovinen
  • 53,325
  • 33
  • 152
  • 143
  • The answer seems to be *contexts.* http://www.gnu.org/software/gettext/manual/html_node/Contexts.html Not sure how they're used in a PHP context though – Pekka Apr 28 '13 at 07:56
  • Related?: http://www.php.net/manual/en/book.gettext.php#89975 – Pekka Apr 28 '13 at 07:57

4 Answers4

9

What you are looking for is contexts for gettext which solves ambiguities like your example. You can find information about in the documentation. Still the needed method pgettext is not implemented in PHP so you might use the helper method stated in a user comment in the php documentation.

if (!function_exists('pgettext')) {

  function pgettext($context, $msgid)
  {
     $contextString = "{$context}\004{$msgid}";
     $translation = dcgettext('messages', contextString,LC_MESSAGES);
     if ($translation == $contextString)  return $msgid;
     else  return $translation;
  }

}

In your case it would be

echo pgettext('mail', 'Letter');
echo pgettext('character', 'Letter');
Radu Maris
  • 5,648
  • 4
  • 39
  • 54
MatthiasLaug
  • 2,924
  • 6
  • 28
  • 43
  • 2
    It would be better to use `textdomain(NULL)` instead of `'messages'` so that this function would behave the same way as C macro equivalent. – RobertT May 05 '14 at 14:31
  • 4
    Moreover it is worth noting that one needs to give `--keyword=pgettext:1c,2` to `xgettext` to let it know about this function existence during fetching of translation strings. – RobertT May 05 '14 at 14:34
  • I have trouble using this function, first of all: the call to `dcgettext` doesn't seems to be correct, I believe that it should be `dcgettext('messages', $contextString, 5)`. Then: the function isn't returning the translation, or maybe there's something wrong with my PO file. I [asked a question about this issue here](http://stackoverflow.com/questions/31994975/gettext-to-work-with-context-pgettext). – Zealot Aug 14 '15 at 14:00
4

While trying to use the GNU xgettext utility to extract the strings from the source code I ran into some trouble with the pgettext() idea above.

At first it looks like it's going to work. Using the --keyword argument I can run the xgettext utility to extract these context and message strings from the test script:

echo pgettext('Letter','mail');
echo pgettext('Letter','character');

and get a .pot file with the expected output:

...
msgctxt "mail"
msgid "Letter"
msgstr ""

msgctxt "character"
msgid "Letter"
msgstr ""
...

But the PHP *gettext() functions don't allow me to pass the context strings - so I can't get the translated text.

Being able to use the GNU utilities makes things easier for me, so the solution for me was to use something like this:

function _c( $txt ) { return gettext( $txt ); }

echo "<P>", _c( "mail:Letter" ), "\n";
echo "<P>", _c( "character:Letter" ), "\n";

Now I run the xgettext utility

xgettext ... --keyword="_c:1" ...

against my test script. This generates a .pot file with simple msgid's that can be accessed via the PHP gettext() function:

...
msgid "mail:Letter"
...
msgid "character:Letter"
...

Next I copy the .pot template to the various LC_MESSAGE folders as a .po file and edit the translated texts:

...
msgid "mail:Letter"
msgstr "Russian outputs for Mail: \"письмо\""

msgid "character:Letter"
msgstr "Russian outputs for Letter of the Alphabet: \"буква\""
...

And my test script works:

...
Russian outputs for Mail: "письмо"

Russian outputs for Letter of the Alphabet: "буква" 
...

The documentation for xgettext is here: http://www.gnu.org/software/gettext/manual/html_node/xgettext-Invocation.html

(I'm still having a problem with poedit and "plural" text but that's another subject.)

Sam Azer
  • 186
  • 3
  • Thank you for sharing your experience, this is definitely an interesting turn of events, I did not expect gettext to cause so much trouble in php – Timo Huovinen Aug 11 '13 at 07:15
3

For the ones using Poedit like me you need to following. First create the function. I'm using one named _x like the one WordPress use:

if (!function_exists('_x')) {

function _x($string, $context)
{
  $contextString = "{$context}\004{$string}";
  $translation = _($contextString);
  if ($translation == $contextString)  
     return $string;
  return $translation;
}
}

Then on poedit you need to enter the following on Sources Keywords tab:

_x:1,2c
_

So when you need to use context translation you use _x function. Eg:

<?php
echo    _x('Letter', 'alphabet');
echo    _x('Letter', 'email');
echo    _('Regular translation');

I took all the info from these links:

Community
  • 1
  • 1
chifliiiii
  • 2,231
  • 3
  • 28
  • 37
1

I have made a package to provide an easy solution to the lack of pgettext in PHP.

See here.

You need to install the package with composer require datalinx/gettext-context and then you can use

echo pgettext('Mail', 'Letter'); // Echoes: письмо
echo pgettext('Character', 'Letter'); // Echoes: буква

Plural and domain override functions (npgettext, dpgettext, dnpgettext) are also implemented.

SlimDeluxe
  • 733
  • 8
  • 18