I’ve been developing PHP applications for years, and I can tell you with absolute certainty that internationalization is no longer optional – it’s essential. PHP i18n (where “i18n” stands for the 18 letters between “i” and “n” in “internationalization”) transforms your local app into a global powerhouse that can speak multiple languages.
Creating multilingual applications opens your product to entirely new markets. And trust me, it’s much easier to implement from the start than to retrofit later!
In this guide, I’ll walk you through everything you need to implement PHP internationalization properly. I’ve used these exact techniques across dozens of projects, including WordPress plugins with multilingual support.
Before diving in, you need to ensure your PHP environment supports i18n. The critical requirement is having the gettext extension installed and enabled.
<?php
// Quick check if gettext is installed
if (function_exists('gettext')) {
echo "Gettext is installed! You're good to go.";
} else {
echo "Gettext is NOT installed. You'll need to enable it first.";
}
// Alternatively, check through phpinfo()
phpinfo();
?>Code language: HTML, XML (xml) If you’re using MAMP, XAMPP, or similar development stacks, gettext is typically enabled by default. For manual PHP installations, you might need to recompile PHP with gettext support according to the PHP documentation.
Let’s build the foundation for our internationalization system. Here’s a practical implementation I’ve used successfully in multiple projects:
<?php
function setLocalization($code) {
// Define supported language codes with their corresponding locale codes
$langCodes = array(
"de" => "de_DE", // German
"fr" => "fr_FR", // French
"es" => "es_ES", // Spanish
"ja" => "ja_JP" // Japanese
);
// Validate requested language code
if(!isset($langCodes[strtolower($code)])) {
return false; <em>// Invalid language code</em>
}
// Base directory for language files
$baseLangDir = './includes/locale';
// Your application's textdomain name
$appName = "myapp";
// Get full locale code
$locale = $langCodes[strtolower($code)];
// Set environment language
putenv('LC_ALL='.$locale);
// Set locale - critical step!
$localeSet = setlocale(LC_ALL, $locale);
// Verify locale was set correctly
if ($localeSet === false) {
// Failed to set locale - check system support
error_log("Failed to set locale to $locale");
return false;
}
// Specify language file location
bindtextdomain($appName, realpath($baseLangDir));
// Set character encoding for translations
bind_textdomain_codeset($appName, 'UTF-8');
// Set default textdomain
textdomain($appName);
return true;
}Code language: PHP (php) This code handles everything needed to set up PHP internationalization. Let me break down the most important parts:
.mo file in a specific structure: {$baseLangDir}/{$locale}/LC_MESSAGES/{$appName}.mosetlocale() function must work correctly. Always check its return value – if it returns false, your system might not support that locale.putenv() function, sometimes using LANG instead of LC_ALL works better depending on your server configuration. Test both if you have issues.bind_textdomain_codeset ensures your translations use the correct character encoding. Always use UTF-8 for modern applications.Once your setup is complete, implementing translations in your code is straightforward. Here are the two main methods:
<?php
// Method 1: Full gettext function
echo gettext("Welcome to our website");
// Method 2: Shorthand function (recommended)
echo _("Welcome to our website");
?>Code language: HTML, XML (xml) In HTML templates, you can use it like this:
<h1><?php echo _("Welcome to our website"); ?></h1>
<p><?php echo _("This text will be translated based on the selected language."); ?></p>Code language: HTML, XML (xml) For more complex translation scenarios, PHP’s gettext also supports pluralization and context:
<?php
// Basic translation
echo _("You have a new message");
// Pluralization with ngettext
$messageCount = 5;
echo ngettext(
"You have one new message",
"You have %d new messages",
$messageCount
);
// With context (for words with multiple meanings)
echo pgettext("verb", "Post");
echo pgettext("noun", "Post");
?>Code language: HTML, XML (xml) The magic of PHP i18n happens through translation files. This is where your translatable strings are mapped to their translations in different languages.
First, we need to extract all translatable strings from our code. The xgettext tool is perfect for this:
xgettext --default-domain=myapp -p ./locale --from-code=UTF-8 -n --omit-header -L PHP /path-to-your-php-files/*.phpCode language: JavaScript (javascript) This generates a template .pot file containing all your translatable strings.
For each language, you’ll create a .po file. Here’s an example for French:
# French translation for myapp
msgid ""
msgstr ""
"Project-Id-Version: myapp\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-05-13 10:46-0500\n"
"PO-Revision-Date: 2024-05-13 12:31-0500\n"
"Last-Translator: Your Name <your.email@example.com>\n"
"Language-Team: French <fr@example.com>\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.1\n"
#: welcome.php:15
msgid "Welcome to our website"
msgstr "Bienvenue sur notre site web"
#: dashboard.php:34
msgid "Hello World"
msgstr "Bonjour le monde"Code language: PHP (php) PHP’s gettext uses binary .mo files for performance. Convert your .po files to .mo using:
bashmsgfmt -cv -o myapp.mo myapp.po While the process above works, modern tools make PHP internationalization much more manageable:
Poedit is a fantastic desktop application for creating and managing translation files. It automatically generates the .mo files when you save.
For team projects, online translation management tools are game-changers:
If you need to generate .mo files programmatically, you can use PHP libraries:
<?php
// Using the gettext/gettext library
use Gettext\Translator;
use Gettext\Translations;
// Load translations from a .po file
$translations = Translations::fromPoFile('path/to/fr.po');
// Generate and save the .mo file
$translations->toMoFile('path/to/fr.mo');
?>Code language: HTML, XML (xml) Implementing internationalization can sometimes be tricky. Here are solutions to common problems I’ve encountered:
If your translations aren’t showing up:
.mo files are in the correct location: {$baseLangDir}/{$locale}/LC_MESSAGES/{$appName}.mosetlocale())If setlocale() returns false, your system might not have the required locale installed. For Linux servers, you can add locales with:
# Generate locale
sudo locale-gen fr_FR.UTF-8
# Update locale configuration
sudo update-locale
# Verify available locales
locale -aCode language: PHP (php) For CentOS specifically:
# Navigate to locales directory
cd /usr/share/i18n/locales/
# Define new locale
sudo localedef -c -i fr_FR -f UTF-8 /usr/share/locale/fr_FR
# Add to archive
cd /usr/share/locale/
sudo localedef --add-to-archive fr_FR
# Verify
sudo localedef --list-archiveCode language: PHP (php) If your translations show up but with garbled characters:
.po files use UTF-8 encodingbind_textdomain_codeset($appName, 'UTF-8')<meta charset="UTF-8">After years of implementing internationalization across projects, here are my top recommendations:
// Instead of this echo _("Hello") . " " . $username; // Do this printf(_("Hello %s"), $username);pgettext() for words with multiple meaningsgettext() callsLet’s put it all together with a complete example:
<?php
// config/i18n.php
function initializeI18n() {
// Get user's preferred language (from session, cookie, browser, etc.)
$userLang = getUserLanguagePreference();
// Set up localization
setLocalization($userLang);
}
function getUserLanguagePreference() {
// Priority: 1. Session, 2. Cookie, 3. Browser language, 4. Default
if (isset($_SESSION['user_language'])) {
return $_SESSION['user_language'];
}
if (isset($_COOKIE['user_language'])) {
return $_COOKIE['user_language'];
}
// Parse Accept-Language header
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
if (isset($langs[0])) {
return substr($langs[0], 0, 2); <em>// Get language code (e.g., 'en' from 'en-US')</em>
}
}
// Default language
return 'en';
}
function setLocalization($code) {
// Implementation from earlier...
}
// Initialize i18n on every page load
initializeI18n();
?>Code language: PHP (php) With this setup, your application will automatically detect and use the user’s preferred language.
Implementing PHP internationalization is absolutely worth the effort. It opens your application to global markets and provides a better experience for non-English speakers. The techniques I’ve shared here have been battle-tested across countless projects.
Remember, the key to successful i18n is planning ahead and maintaining good practices throughout development. Your future self (and your users) will thank you!
Have you implemented PHP i18n in your projects? What challenges did you face? I’d love to hear about your experiences in the comments below!
Learn python file handling from scratch! This comprehensive guide walks you through reading, writing, and managing files in Python with real-world examples, troubleshooting tips, and…
You've conquered the service worker lifecycle, mastered caching strategies, and explored advanced features. Now it's time to lock down your implementation with battle-tested service worker…
Unlock the full potential of service workers with advanced features like push notifications, background sync, and performance optimization techniques that transform your web app into…
This website uses cookies.
View Comments
Now that’s one good tutorial. You should know that it’s also possible to use https://poeditor.com/ to easily translate software online.
Thanks for your comment. I already mentioned about the desktop poedit tool already, which definitely do the work, but can't automate the process. Not sure about this site, can it help in automation? like extract data, translate and give back the mo file?
Hi! I have used the tool POEditor and I can tell you this about how it works: after creating the account, you create a project, import the .po file (or another supported format), translate the strings (just text, no code) by yourself or by collaborating with others (this is a big plus in contrast with a desktop tool like Poedit), and then, when the translation is done, export the file in any format you like that is supported (.mo included).
Besides giving the obvious ability to manage a collaborative translation project, POEditor has other functions that help automate the software translation process, like Automatic Translation (provided by Bing/Google machine translation engines), Translation Memory and API.
There is an error on line , $lang should be $langCodes
Thanks for pointing out! I have corrected it.