PHP: GNU Gettext - Manual
PHP  
downloads | documentation | faq | getting help | mailing lists | | php.net sites | links | my php.net 
search for in the  
<unregister_tick_functionbind_textdomain_codeset>
view the version of this page
Last updated: Tue, 21 Dec 2004

XXXIX. GNU Gettext

導入

gettext 関数は、NLS (Native Language Support) APIを実装するもので、 PHPアプリケーションを国際化する際に使用することが可能です。 これらの関数の詳細については、GNU gettext ドキュメントを参照下さい。

要件

以下の関数を使用するには、からGNU gettextパッケー ジをダウンロードし、インストールする必要があります。

インストール手順

PHPでGNU gettextサポートを有効にするには、オプション --with-gettext[=DIR]を追加する必要 があります。ただし、DIRはgettextをインストールするディレクトリで、 デフォルトは/usr/localです。

Win32ユーザへの注意: Windows環境でこのモジュールを有効にするには、PHP/Win32バイナリパッ ケージのDLLフォルダからgnu_gettext.dllを 使用するWindowsマシンのSYSTEM32フォルダ(例: C:\WINNT\SYSTEM32または C:\WINDOWS\SYSTEM32)にコピーする必要があります。 PHP 4.2.3以降、この名前はlibintl-1.dllに変更さ れました。

実行用の設定

この拡張モジュールは設定ディレクティブを全く定義しません。

リソース型

この拡張モジュールはリソース型を全く定義しません。

定義済みの定数

この拡張モジュールは定数を全く定義しません。

目次
bind_textdomain_codeset --  DOMAINメッセージカタログからのメッセージが変更される文字エンコー ディングを指定する
bindtextdomain -- ドメインのパスを設定する
dcgettext -- 単一の参照に関するドメインを上書きする
dcngettext --  dcgettext()の複数版
dgettext -- カレントのドメインを上書きする
dngettext -- dcgettext()の複数型です
gettext -- カレントドメインのメッセージの参照する
ngettext -- gettextの複数版
textdomain -- デフォルトドメインを設定する


add a note add a note User Contributed Notes
GNU Gettext
dpatton at confluence dot org
28-Feb-2005 06:47
Make sure you check your webserver configuration before deciding to use gettext, because if you are running in a multi-threaded environment you should not use gettext, as it is not thread-safe.

A future version of gettext(possibly 0.15) may be thread-safe.
Any gettext dependencies, such as glibc would also need to be thread-safe.

Apache 1.3 on Unix generally is non-threaded, but on Windows it is multithreaded.
Apache 2.0 has support for MPMs(Multi-Processing Modules), some of which support multiple threads:
susko at seznam dot cz
24-Feb-2005 05:09
Gettext returning question marks instead of some local characters? Try using bind_textdomain_codeset to change codeset of the translated messages:

bind_textdomain_codeset (domain, codeset);

It worked for me, hope it works for you ..
zixia at zixia dot net
11-Jun-2004 09:42
If gettext does not work with your locale, ie 'zh_CN', just going to see if the output of command "localedef --list-archive" contains your locale('zh_CN' in this example).
If it not, try to use a exist locale or use "localedef" to create one: "localedef -f GBK -i zh_CN zh_CN" in my case.
mikolaj at webgate dot bg
10-Jun-2004 11:54
winXP, PHP 4.3.5 as Apache1.3.29 module

Two hints for Windows users.

I found setting locale is neither sufficient nor nessecery. To get it work I needed to set either LC_ALL or LANG enviroment variable to my locale. Anyway this value must be proper for setlocale so it is good to test with it. In my case it was bgr_BGR for bulgarian according to

gettext checks for files once and keeps them in cashe. Especially it means that if it doesn't find your files it won't search again, so restart Apache after any directory changes!!

My minimal working script:
<?php
// translation file: D:\Apache\htdocs\mypage\locale\bgr_BGR\LC_MESSAGES\messages.mo
putenv("LC_ALL=bgr_BGR");
bindtextdomain('messages', 'D:\Apache\htdocs\mypage\locale\\');
echo
gettext("Hello");
?>
stefan+usenet at froehlich dot priv dot at
05-May-2004 11:30
Reading the line

<? php setlocale(LC_ALL, 'de_DE'); ?>

here over and over again, I have to warn using it, as there are severe caveats. For certain locales, LC_NUMERIC swaps period and comma, which may e.g. lead to decimals silently stripped of numbers, when inserting rows into an SQL database. So DON'T do this, but use

<? php setlocale(LC_MESSAGES, 'de_DE'); ?>

instead, which does exactly what you want, without any nasty side effecs.
kocio at irc dot pl
03-May-2004 10:26
Following three lines take about 0.5 second to execute (Debian, Celeron 2GHz, 256MB RAM):

setlocale(LC_ALL, 'pl_PL');
bindtextdomain('my_domain', '../dir/' . 'locale');
textdomain('my_domain');

I think that such delay is important enough to be mentioned in the documentation. In my particular case, it means more than doubled execution time for the entire script.
dev.php at tfelber.net
27-Aug-2003 02:35
Check your

/etc/locales.aliases for "english en_GB.ISO-8859-1" (mentioned before)

and your

/etc/locales.gen for en_GB.ISO-8859-15 ISO-8859-15

I'm not sure if only this entry solved the problem. In my case this entry was made by an dpkg-reconfigure locales (debian), where i created the locales.

Translation only works with de_GE@euro and  en_GB.ISO-8859-15 (first column in you locales.gen)
wouter at grep dot be
13-Aug-2003 07:28
Of course, translation is only interesting if you provide the user with the language and encoding he asks for. Since there's part of the HTTP protocol that allows you to specify that, it's nice if one can use that information to pick the 'right' translation out of the ones you have available.

I wrote something that does just that -- it parses the 'Accept-Language' and 'Accept-Charset' HTTP/1.1 headers, and tells you which one the user prefers out of a list you provide. You can download it at

Note that even if the user's browser may support this, the user may not know about it; as such, it's probably good practice not to remove links to other-languaged versions, so that people can still get a version of your site in another language if they so prefer.
jc
14-Jul-2003 08:15
I had a lot of problems getting gettext to work (RedHat 7.3). After reading ALL the comments in this manual, I got it to work OK.

In summary, take care that:

1) You use a full locale in the setlocale()
2) Your language_country exists in the /usr/share/locale/locale.alias
3) It seems that Apache needs to be restarted (a "graceful" did the trick for me)
4) Your .mo files must be named after the domain

My code:

$language = "es_ES";
$locale = setlocale(LC_ALL, $language);

$gettext_domain = 'messages';
bindtextdomain($gettext_domain, "/full/path/to/locale");
textdomain($gettext_domain);
anim8
18-Jun-2003 01:15
Even though in some cases setlocale() may require a country code in addition to the language code this does not mean that it is required for gettext.

If setlocale() is set to either es_ES or es_MX gettext() will still get the text from a po file in the 'es' folder.

It probably is not a good idea to go changing a systems alias file(s) just to avoid the verbosity of the ISO standard because:
  a) you might break something
  b) your code just lost it's portability

.
14-Jun-2003 02:41
The way I got gettext to work with just a standard "de" or "fr" instead of "de_DE" was I overwrote my /usr/share/locale/locale.alias with /usr/lib/X11/locale/locale.alias file.  The I restarted Apache.  Reason I did this was it appeared the X11 file was more up to date and more modernised!
Picco
08-Jun-2003 05:45
Note to Chinese programmers....

Took me hours to figure out you cannot use

LANG=zh
but have to use
LANG=zh_TW
on some machines...

a good way to test will be to check the return of setlocale()
robert at klugher dot com
25-Feb-2003 05:03
Sorry, one more info :

the previous post is especially interesting when you have values set on the server for some of the LC_... then, setlocale() output gives you all the LC_... with their value.

BUT do not forget that the priority order for gettext is:

LANGUAGE
LC_ALL
LC_MESSAGES
LANG

Then, if ever you script always translate to the same language, check the value of LANGUAGE ...
robert at klugher dot com
25-Feb-2003 01:24
One trick I found after HOURS of tries :

when you use the setlocale(), PHP will use the locale info it will find in, for example, /usr/share/locale to set the language info for LC_ALL, LC_MESSAGES, ...

You can check the exact info it will use by using putenv() with LANG=.... and looking at the return value of setlocale(LC_ALL, ""). The language value your gettext function will use to look for your translation file is the one given for LC_MESSAGES.

Example :

I was setting the LANG as fr_BE, and placed the translation file in dirxxx/locale/fr_BE/LC_MESSAGES/...
As it was locale info in my system for fr_BE but NOT LC_MESSAGES, PHP choosed to use the LC_MESSAGES settings for fr_FR instead and then, was looking for a translation file in dirxxx/locale/fr_FR/LC_MESSAGES/..., which wasn't found of course.

So, just make sure to look at the return value of setlocale to see what language value is associated to LC_MESSAGES and, then, to know in which subdirectory the translation file will be looked for by gettext.

Robert
zw at matfyz dot cz
05-Feb-2003 06:38
There is a nice tutorial on using gettext with php
php at zpod dot ca
30-Jan-2003 03:24
For those of you just trying to get a script working and your provider doesn't support gettext, you can bypass the international stuff by adding this:

function _($str) {
   return $str;
}
Eneko Lacunza enlar at enlar dot net
16-Jan-2003 04:20
Some tips from my Red Hat Linux 7.3 system.

It didn't work for me until I set a full locale (i.e. es_ES) with setlocale.

I was trying with Michele Manzato's example (thank you!), but as it sets the language without the country, it was failing for me. Here is the example "fixed" with full locale:

// Change to script directory
// (Not needed in RH 7.3)
$path = dirname(getenv(PATH_TRANSLATED));
chdir($path);

// Set the language as full locale 'es_ES'
$language = 'es_ES';
putenv("LANG=$language");
setlocale(LC_ALL, $language);

// Set the text domain as 'mydomain'
$domain = 'mydomain';
bindtextdomain("$domain", "./locale");
textdomain("$domain");

// The .mo file searched is:
// ./locale/es_ES/LC_MESSAGES/mydomain.mo
// or if previous one doesn't exist:
// ./locale/es/LC_MESSAGES/mydomain.mo

echo gettext("Hello world!");

Hope this helps!
Eneko.
yledoare at free dot fr
15-Jan-2003 03:32
Corrections to "hace_x at yahoo dot com" message.

Note : The backslash have been removed in the greetings.po sample code (before the n characters at end of lines).

Same thing for ".includestranslations" to move into "./includes/translations" in php sample.

I used mingw () with gettext package () to make it work under WinXp.

I uncoment also "extension=php_gettext.dll" in php.ini (I am using easy php 1.6.0.0)

Here is my conv.bat to generate french translation :

set path=c:\mingw\bin
msgfmt -v -o greetings.mo greetings.po
pause

That's all !

Yann Le Doar�, Brest, France
ywliu atsign hotmail com
09-Jul-2002 04:39
Hello,

For users with Red Hat GNU/Linux (at least 6.2) to use gettext, I'd like to make some notes here :

1. Calling setlocale() is necessary, where calling putenv('LANG=xx_YY') or putenv('LC_ALL=xx_YY') is not.

2. The country/language code should be in the "language_country" form,such as, "en_US" or "fr_FR", or any entry in /usr/share/locale/locale.aliase . The simple ISO two-letter code, such as "en" , is not valid. You can examine the return value of setlocale to see if the locale setting succeeds.

This took me several hours to debug. I hope my experience can save you some time.

This may apply to other Linux distributions or *BSD systems. I don't know. I hope this helps.

Yen-Wei Liu
php at dynaperl dot com
25-Jun-2002 01:49
�f you install from SuSE Dist. you need glibc-locale.rpm to let gettext work.

mfg ralph.
mgvNOSPAM at fx dot ro
05-Jun-2002 02:47
If you're as clueless as I am, please note the following:
1. Although most comments list setlocal() in the code, that's not actually required for translations - read the docs under "string functions" for details (also, the official gettext() examples don't include it);
2. hace_x's example is really cool, except you need to know that all "n"'s at the end of his strings should have a backslash before - they're actually EOL characters, but they somehow got messed up and I needed two hours to find that out...
hace_x at yahoo dot com
15-Nov-2001 01:40
I had alot of problems to get gettext() to work on my windows2000-php webserver. The following will give those windows-php users something to hold on to:

Note the way you have to use slashes for the bindtextdomain command:

For a 'greetings' domain:

bindtextdomain ("greetings", ".\includes\translations");

(so, TWO slashes instead of one between the folder-names!)

ALSO, I had to change the filename to be 'greetings.mo': This was NOT clear from all the gnu-pages I read. I had named those files: nl.mo (for dutch) and fr.mo (for french etcetera).

I provide my code and folder-structure here for other windows-users:

<?
Header
("Content-type: text/plain");
// Bind a domain to directory
// Gettext uses domains to know what directories to
// search for translations to messages passed to gettext

bindtextdomain ("greetings", "./includes/translations"); // Set the current domain that gettext will use
textdomain ('greetings'); # Make an array

# Use the ISO two-letter codes as keys
# Use the language names as values
$iso_codes = array (
  
'en'=>'English',
 
'fr'=>'French',
  
'it'=>'Italian',
 
'pt'=>'Portuguese',
  
'es'=>'Spanish',
 
'nl'=>'Nederlands'
);
foreach (
$iso_codes as $iso_code => $language) {
  
# Set the LANGUAGE environment variable to the desired language
  
putenv ('LANG='.$iso_code); # Print out the language name and greeting
# Filter the greeting through gettext

printf ("%12s: %s\n", $language, gettext("str_hello")) & "\n";

}
?>

In the windows-webfolder I have the following directory-structure:

==
includes\translations
includes\translationsen
includes\translations\en\LC_MESSAGES
includes\translations\en\LC_MESSAGES\greetings.po
includes\translations\nl\
includes\translations\nl\LC_MESSAGES
includes\translations\nl\LC_MESSAGES\greetings.mo
\includes\translations\nl\LC_MESSAGES\greetings.po
===

To get this working you will need a greetings.po file like this:

(this one is in the 'nl' subdir for dutch language):
===
msgid ""
msgstr ""
"Project-Id-Version: n"
"POT-Creation-Date: n"
"PO-Revision-Date: 2001-11-14 17:11+0100n"
"Last-Translator: Melle Koning <[email protected]>n"
"Language-Team:  <>n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=utf-8n"
"Content-Transfer-Encoding: 8bitn"

msgid "str_hello"
msgstr "hallo"
===

and you have to 'compile' this .po file to a .mo file with the following command-line (go to windows 'command prompt'):

==
msgfmt -o greetings.mo greetings.po
==

To get msgfmt working on your windows machine, you will need to have libiconv.dll, libintl.dll and msgfmt.exe in your path. What I did was put these three files in a new c:utils folder and than run the command:
path=%path%;c:utils

I hope this helps some windows-users like me to get gettext() to work on their systems.......

Cheers,
Melle
[email protected]
Michele dot Manzato at verona dot miz dot it
14-Sep-2001 10:52
Gettext is great, but there are a few caveats you have to consider in order to make it work. Unfortunately the gettext docs isn't so plain and clear...

The .mo file created with the gettext utilities must be:

[bindtextdomain's dir]/[language]/LC_MESSAGES/[domain].mo

otherwise gettext() function will fail to find it (this is true in win32, don't know about Un*ces). By the way you don't get any error message, the strings will simply remain untranslated.

Second, you must make sure which is the current directory if you use a relative path in bindtextdomain. On some systems the script directory isn't the current directory, so you have to chdir() there.

Then, of course, make sure that the appropriate gettext extension are loaded by PHP by looking at the php configuration file.

Here is some sample code:

// Change to the script directory
$path = dirname(getenv(PATH_TRANSLATED));
chdir($path);

// Set the language as 'it'
$language = 'it';
putenv("LANG=$language");
setlocale(LC_ALL, $language);

// Set the text domain as 'mydomain'
$domain = 'mydomain';
bindtextdomain("$domain", "./locale");
textdomain("$domain");

// The .mo file searched is:
// ./locale/it/LC_MESSAGES/mydomain.mo

echo gettext("Hello world!");

Have fun!
Michele
12-Jul-2001 11:59
To get xgettext working with my php code I had to change simple quotes to double quites in my previous example :

print(getText("Welcome"));
/.../
if($err)printf(dGetText("errorMsg","you have an error here"));

I guess that's because strings can not be simple-quoted in C. However I think it is good practice to do as if it was a simple quote, because you do not want to interpolate a string that will end in the catalogue.

Ivan
11-Jul-2001 12:40
It is probably obvious to many of you,  but I thought it was worth mentioning that the domain is the name of the .mo files that contain the string catalogue (without the extension).

so if you have a catalogue myPage.mo for each page in './locale/lg/LC_MESSAGE' and some generic catalogues (e.g. errorMsg.mo) in '/global/locale/lg/LC_MESSAGE', you can do

bindTextDomain("$myPage", './locale');
bindTextDomain('errorMsg','/global/locale' );
textDomain('myPage');
print(getText('Welcome'));
/.../
if($err)printf(dGetText('errorMsg','you have an error here'));

Ivan

<unregister_tick_functionbind_textdomain_codeset>
 Last updated: Tue, 21 Dec 2004
show source | credits | sitemap | contact | advertising | mirror sites 
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: /
Last updated: Mon Mar 14 08:13:06 2005 Local time zone must be set--see zic manual page