Gettext
- Введение
- Установка и настройка
- Предопределенные константы
- Функции gettext
- bind_textdomain_codeset — Устанавливает кодировку, в которой будут возвращаться сообщения из каталога сообщений домена
- bindtextdomain — Устанавливает путь для домена
- dcgettext — Переопределяет одно сообщение в домене
- dcngettext — Версия dcgettext для множественного числа
- dgettext — Позволяет переопределить текущий домен
- dngettext — Версия dgettext для множественного числа
- gettext — Ищет сообщение в текущем домене
- ngettext — Версия gettext для сообщений во множественном числе
- textdomain — Устанавливает домен по умолчанию
Коментарии
To get this working properly on debian, install the locales-all package. I just spent a few hours finding a bug where it wouldn't work because that package is missing
My PHP app was made for UTF-8 but i had a problem that gettext always returned all texts in ISO-8859-2 instead of UTF-8.
Then i found out that you have to set locale in PHP exactly to encoding you request. So when i wanted czech UTF-8 i used:
setlocale(LC_ALL, "cs_CZ.UTF-8");
Now it works...
And what about pgettext and npgettext? They are there in the gettext documentation, but there aren't in PHP. They're very useful if you have the same messages for translation, but in different contexts, so they should be translated separately and probably differently.
Fortunately, there is a simple work-around, which may help:
From the gettext.h header one can find out that pgettext() is only a macro calling dcgettext() internally with properly mangled parameters - msgctxt and msgid are glued together with use of ASCII char 4 [EOT, End Of Text]. The same way they're written in .mo files, so it's possible to refer them this way.
Here's my "emulated" pgettext() function:
<?php
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;
}
}
?>
By default, xgettext doesn't support pgettext function for PHP source files. But there is a parameter which can work-around it. Here's how I call xgettext:
xgettext --force-po --keyword="pgettext:1c,2" -c -o messages.po sourceFile.php
In sourceFile.php I use the following test code:
pgettext('menu', 'Open'); //Substitute "Otwórz"
pgettext('forum', 'Open'); //Substitute "Otwarty", different context
Generated .po file fragment:
msgctxt "menu"
msgid "Open"
msgstr "Otwórz"
msgctxt "forum"
msgctxt "Open"
msgstr "Otwarty"
I've tested it out and everything works fine :-) If anyone have some further suggestions or fixes, please write ;-)
Warning for Linux (Ubuntu) users! Your system will *only* support the locales installed on your OS, in the *exact* format given by your OS. (See also the PHP setlocale man page.) To get a list of them, enter locale -a, which will give you something like this:
C
en_US.utf8
ja_JP.utf8
POSIX
So this machine only has English and Japanese! To add eg. Finnish, install the package:
sudo apt-get install language-pack-fi-base
Rerun locale -a, and "fi_FI.utf8" should appear. Make sure you're using the same name in your PHP code:
setlocale(LC_ALL, "fi_FI.utf8");
Adjust your po paths so that they match, e.g. "./locale/fi_FI.utf8/LC_MESSAGES/messages.po".
Now restart Apache, and it should finally work. Figuring this out took quite a while...
*An important thing to keep in mind*:
Do not forget to set the charset in .po file!
For example:
"Content-Type: text/plain; charset=UTF-8\n"
Then PHP will be able to find the .mo file you generated, using msgfmt, from the .po file WITH CHARSET SET.
Because of this I've wasted a lot of time debugging my code, testing every single little changes people suggested over this manual and Internet:
<?php
//this:
setlocale( LC_MESSAGES, 'pt_BR')
//or this:
setlocale( LC_MESSAGES, 'pt_BR.utf8')
//or this:
setlocale( LC_MESSAGES, '')
//this:
putenv("LANG=pt_BR.utf8");
//or this:
putenv("LANGUAGE=pt_BR.utf8");
//this:
bindtextdomain('mydomain', dirname(__FILE__).'/locale');
//or this:
bindtextdomain("*", dirname(__FILE__).'/locale');
//or this:
bindtextdomain('*', dirname(__FILE__).'/locale');
//setting or not "bind_textdomain_codeset()":
bind_textdomain_codeset("mydomain", 'UTF-8');
?>
As well as what locale directory name to set:
./locale/pt_BR.UTF8/LC_MESSAGES/mydomain.mo
or
./locale/pt_BR/LC_MESSAGES/mydomain.mo
or
./locale/pt/LC_MESSAGES/mydomain.mo
Finally, the code which brought the right translated strings (also with the correct charset) was:
<?php
$directory = dirname(__FILE__).'/locale';
$domain = 'mydomain';
$locale ="pt_BR.utf8";
//putenv("LANG=".$locale); //not needed for my tests, but people say it's useful for windows
setlocale( LC_MESSAGES, $locale);
bindtextdomain($domain, $directory);
textdomain($domain);
bind_textdomain_codeset($domain, 'UTF-8');
?>
And the three directory's names worked out, using the pt_BR.utf8 locale. (My tests were made restarting Apache then trying each directory).
I hope to help someone else not to waste as much time as I've wasted... =P
Using:
Ubuntu 8.04 (hardy)
Apache 2.2.8
PHP 5.2.4-2ubuntu5.6
Please also be noticed that the server will cache the .mo file on first loading and then "seldom" reload it, so your update to .mo file will not be revealed. Some solution to clear the cache from web is to restart the apache server, or to use another name for the textdomain everytime. These are tedious. I cannot find better solution yet.
for all they try to use a non-alpha-char in a domain name: DONT TRY THIS !!! we have search some hours to realized that "foo-bar" is not a good idea for a domain name. sometimes we got a correct translation, and sometimes not. so just use only the characters A-Z for a domain name!
Soo.... It was pretty hard)
Finaly:
1)Working if dir is "en", not "en_GB" or "en_GB.utf8". Only "en".
2)But use setlocale(LC_MESSAGES, "en_GB.utf8");
How to use gettext on Windows.
If you use Linux start from the step 2 and consider cmd as linux shell.
1] First you have to download and install this
https://mlocati.github.io/articles/gettext-iconv-windows.html
Check all options during the installation and go on.
2] Create a index.php file into your website directory with this code inside:
<?php
echo _("Good Morning");
?>
3] Open cmd and move into your website folder using cd
4] Now create the .mo files directly from the php files using this command
xgettext -n index.php
Use xgettext -help to see how to include more php files.
5] Once finished will be generate a file called messages.mo. Now you have to set the language and the charset. Open messages.mo with notepad and edit the lines:
- "Language: \n" BECOMES "Language fr\n"
- "Content-Type: text/plain; charset=CHARSET\n" BECOMES "Content-Type: text/plain; charset=UTF-8\n"
6] Remember to translate every line where is present msgstr "", translating the instance msgid into language you have chosen. For instance:
#: index.php:2
msgid "Good Morning"
msgstr "Bonjour"
7] Once finished open cmd and move into your website folder using cd and then type
msgfmt messages.po
This will make a file called messages.mo . Is a binary version of the messages.po file
8] Now you have to create a folder structure like this into your website folder. Do this for each language you want to add.
website/locale/fr_FR/LC_MESSAGES
9] Move messages.mo and messages.po in locale/fr_FR/LC_MESSAGES
10] Now edit the index.php as follows
<?php
$locale = "fr_FR";
if (defined('LC_MESSAGES')) {
setlocale(LC_MESSAGES, $locale); // Linux
bindtextdomain("messages", "./locale");
} else {
putenv("LC_ALL={$locale}"); // windows
bindtextdomain("messages", ".\locale");
}
textdomain("messages");
echo _("Good Morning");
?>
11] Open index.php in your browser and if you will see "Bonjour" it means everything is okay. If not, start from the step 2 again.
If it was usefull for you vote up!
Visit my github profile https://github.com/TheoRelativity/
I have some problems setting geettext.
I ahve tried all the above example in noted, but none work.
However, i found a nice trick here and it work!!:
My platform is freebsd.
below is the post:
function.gettext
Gettext translations are cached. If you change *.mo files your page may not be translated as expected. Here's simple workaround which does not require restarting webserver (I know, this is just a dirty hack):
<?php
function initialize_i18n($locale) {
putenv('LANG='.$locale);
setlocale(LC_ALL,"");
setlocale(LC_MESSAGES,$locale);
setlocale(LC_CTYPE,$locale);
$domains = glob($locales_root.'/'.$locale.'/LC_MESSAGES/messages-*.mo');
$current = basename($domains[0],'.mo');
$timestamp = preg_replace('{messages-}i','',$current);
bindtextdomain($current,$locales_root);
textdomain($current);
}
?>
to make this work you have to put your locale inside file messages-[unix_time].mo and use this name (without .mo) as your domain to fool caching mechanism (domain names differ)
msgfmt messages.po -o messages-`date +%s`.mo
for me this works fine (although this is not very elegant solution)
<?php
// read directly .po files
function T_($contenido) {
global $language;
if ($language == "en") { $translation_file = "langs/en.po"; }
if ($language == "es") { $translation_file = "langs/es.po"; }
if (file_exists("$translation_file")) {
$IDIOMA_CONTENT = file("$translation_file");
$num_lineas = count($IDIOMA_CONTENT);
} else {
return $contenido;
}
for ($i = 0; $i <= $num_lineas; $i++) {
$linea1 = $IDIOMA_CONTENT[$i];
$linea1 = rtrim($linea1);
$string6 = substr($linea1, 0, 6);
if ($string6 == "msgid ") {
$orig = str_replace($string6, "", $linea1);
$orig = str_replace("\"", "", $orig);
if ("$orig" == "$contenido") {
$linea2 = $IDIOMA_CONTENT[$i + 1];
$linea2 = rtrim($linea2);
$string7 = substr($linea2, 0, 7);
if ($string7 == "msgstr ") {
$trad = str_replace($string7, "", $linea2);
$trad = str_replace("\"", "", $trad);
return("$trad");
}
} else {
$i = $i + 3;
}
}
}
return("$contenido");
}
$language = "es";
print T_("I on puc comprar el meu domini ?");
print T_("Aquí tens alguns links...");
?>