79584284

Date: 2025-04-21 08:41:15
Score: 5.5
Natty:
Report link

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

Rules of Thumbs

These rules saved me 2 days of troubleshooting:

  1. Always set LC_ALL to the very same language directory.
    For example set LC_ALL=it_IT.utf8 if you have /var/www/myproject/locale/it_IT.utf8/LC_MESSAGES/com.myproject.mo
  2. Always set textdomain() as the very same .mo basename.
    For example if the .mo is named com.myproject.mo the domain is com.myproject
  3. Make sure that your language it_IT.utf8 is available in your system.
    Run locale -a to check it.
  4. Unset LANGUAGE since it may take precedence over LC_ALL
  5. Troubleshoot using the command line tool strace to understand what .mo files PHP is opening.

Example Filesystem Structure

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:

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".

Example .po file

The .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.

Available Locale

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.

Example Code

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').

Troubleshooting

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.

Still not working?

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.

Reasons:
  • Blacklisted phrase (2): Still not working
  • RegEx Blacklisted phrase (2.5): please share
  • RegEx Blacklisted phrase (2): working?
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
Posted by: Valerio Bozz