This answer assumes that you are somehow familiar with GNU Gettext but you have problems in the integration in PHP.
https://www.php.net/manual/en/function.gettext.php
These rules saved me 2 days of troubleshooting:
LC_ALL
to the very same language directory.LC_ALL=it_IT.utf8
if you have /var/www/myproject/locale/it_IT.utf8/LC_MESSAGES/com.myproject.mo
textdomain()
as the very same .mo
basename..mo
is named com.myproject.mo
the domain is com.myproject
it_IT.utf8
is available in your system.locale -a
to check it.LANGUAGE
since it may take precedence over LC_ALL
strace
to understand what .mo
files PHP is opening.Adopt this filesystem structure:
/var/www/myproject/locale/com.myproject.pot
/var/www/myproject/locale/it_IT.utf8
/var/www/myproject/locale/it_IT.utf8/LC_MESSAGES
/var/www/myproject/locale/it_IT.utf8/LC_MESSAGES/com.myproject.mo
/var/www/myproject/locale/it_IT.utf8/LC_MESSAGES/com.myproject.po
The important part is the location of the .mo
binary files.
Glossary:
/var/www/myproject/locale
com.myproject
it_IT.utf8
Note for newcomers: if you don't know how to generate the .mo
or .po
, read the official documentation of GNU Gettext. Look for questions like "how to generate a .po file" and "how to generate a .mo file".
.po
fileThe .po
file should contain Language: it_IT
(without utf8) and the GNU Gettext domain. Minimal example:
msgid ""
msgstr ""
"Project-Id-Version: com.myproject\n"
"Language: it_IT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: template/header.php:20
msgid "Italy"
msgstr "Italia"
...
Important: do not create the .po
manually. Read "how to generate a .po file with GNU Gettext" (msgmerge).
Important: if you change a .po
file, always re-generate the related .mo
files (msgfmt).
Important: if your .mo
files change, you may need to restart your webserver since GNU Gettext has aggressive cache in PHP. This is good for your performance but not good for testing. There are workarounds for this (e.g. a special 'nocache' symlink) but it's a bit off-topic.
Use locale -a
to check if the list of your available locales contains the expected ones (like it_IT.utf8
). Example output:
C
C.utf8
en_US.utf8
it_IT.utf8
POSIX
If one of your language is not in this list, you must install it in your system first, for example in this way in Debian or Ubuntu:
sudo dpkg-reconfigure locales
Look for related questions about "How to reconfigure locales in Debian" or whatever you are using, if the above command does not work for you.
Create a simple function that activates a language:
<?php
// GNU Gettext domain.
define('LOCALE_DOMAIN', 'com.myproject');
// GNU Gettext locale pathname, containing languages.
define('LOCALE_PATH', '/var/www/project/locale');
/**
* Apply the desired language.
*
* @param $lang string Language, like 'it_IT.utf8' or 'C' for native texts.
*/
function apply_language(string $lang): void
{
// Unset this env since this may override other env variables.
putenv("LANGUAGE=");
// Set the current language.
// In some systems, setlocale() is not enough.
// https://www.php.net/manual/en/function.gettext.php
putenv("LC_ALL=$lang");
setlocale(LC_ALL, $lang);
// The 'C' language is quite special and means "source code".
// You can stop here to save some resources.
if ($lang === 'C') {
return;
}
// Set the location of GNU Gettext '.mo' files.
// This directory should contain something like:
// /locale/it_IT.utf8/LC_MESSAGES/$domain.mo
bindtextdomain(LOCALE_DOMAIN, LOCALE_PATH);
// Set the default GNU Gettext project domain and charset.
bind_textdomain_codeset(LOCALE_DOMAIN, 'UTF-8');
// Set the GNU Gettext domain.
textdomain(LOCALE_DOMAIN);
}
Then try everything:
...
// Set desired language.
apply_language('it_IT.utf8');
// Try language.
echo gettext('Italy');
Expected output:
Italia
Note: as already said, at this point note that .mo
files are aggressively cached. Consider adding the "nocache" solution from the other solution in this page, that is a very nice trick to refresh the cache.
Note: the function _('Italy')
is a short alias for gettext('Italy')
.
If you still does not see anything translated, prepare a minimal example like example.php
with minimal GNU Gettext tests and run it like this from your command line:
strace -y -e trace=open,openat,close,read,write,connect,accept php example.php
In this way you can see the .mo
files that are opened by PHP.
Example output line:
openat(AT_FDCWD</home/user/projects/exampleproject>, "/home/user/projects/exampleproject/locale/it_IT.utf8/LC_MESSAGES/org.refund4freedom.mo", O_RDONLY) ...
As you can see the strace
command is very powerful to detect what's happening. So you can detect if a configuration is wrong.
If you have not fixed with this answer, please share more details about your structure, your code, and share strace
output from a minimal PHP file.