PHP Internationalization: How to Speak the World's Language

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Your PHP Website Should Speak Different Languages?

\n\n

Imagine: you've created the perfect product — fast, convenient, solving problems. But there's one catch: your interface only speaks Russian. Potential clients from Germany, Japan, or Brazil simply close the tab, not understanding a single button. This is not just lost profit — it's losing entire markets.

\n\n

Internationalization (i18n — from "internationalization", where 18 letters between i and n) and localization (l10n) are not just a "checkbox" for a startup, but a strategic tool. Many developers fear this word, thinking they'll have to rewrite all the code. In reality, well-organized translations in PHP is an elegant process that makes code cleaner and business more global.

\n\n

In this article, we'll break down three real approaches to internationalizing PHP applications: from simple arrays to the powerful intl extension and the classic gettext. You'll learn not just how to translate text, but how to correctly work with dates, numbers, and plural forms — because Arabic, Polish, or Russian have their own declension rules.

\n\n

Main Approaches to i18n in PHP

\n\n

Before writing code, you need to choose an architecture. Conventionally, all methods fall into three categories. Which one to choose depends on the project's scale and performance requirements.

\n\n

1. Arrays and ini-files (DIY Approach)

\n\n

The simplest way is to store translations in associative arrays or .ini files. Perfectly suited for small projects or MVPs.

\n\n
// lang/ru.php\nreturn [\n    'welcome' => 'Welcome to the website!',\n    'logout' => 'Logout',\n    'cart_empty' => 'Cart is empty'\n];\n\n// lang/en.php\nreturn [\n    'welcome' => 'Welcome to the website!',\n    'logout' => 'Logout',\n    'cart_empty' => 'Cart is empty'\n];
\n\n

Using it is simple: include the required file based on the user's session or cookie.

\n\n
function __($key) {\n    static $lang = null;\n    if ($lang === null) {\n        $locale = $_SESSION['lang'] ?? 'ru';\n        $lang = include "lang/{$locale}.php";\n    }\n    return $lang[$key] ?? $key;\n}\n\necho __('welcome'); // Welcome to the website!
\n\n

Pros: simplicity, requires no extensions, easily cacheable (can even be stored in Redis).
\nCons: no support for plural forms (you'll have to write a workaround), inconvenient for large projects (100500 keys in one file).

\n\n

2. Gettext — The Classic

\n\n

Gettext is the de facto standard for internationalization in the Unix world. In PHP, it's available through the gettext extension. It's a powerful tool used in WordPress, Drupal, and Symfony.

\n\n

First, create .po files (e.g., for Russian):

\n\n
# ru_RU/LC_MESSAGES/messages.po\nmsgid "Hello, %s!"\nmsgstr "Hello, %s!"\n\nmsgid "You have %d new message"\nmsgid_plural "You have %d new messages"\nmsgstr[0] "You have %d new message"\nmsgstr[1] "You have %d new messages"\nmsgstr[2] "You have %d new messages"
\n\n

Then compile it into a .mo file (using the msgfmt tool). In PHP code, it looks like this:

\n\n
putenv('LC_ALL=ru_RU.UTF-8');\nsetlocale(LC_ALL, 'ru_RU.UTF-8');\nbindtextdomain('messages', './locale');\ntextdomain('messages');\n\necho gettext('Hello, %s!', 'Alexey'); // Hello, Alexey!\n\n// Plural forms — magic:\necho ngettext('%d message', '%d messages', 3); // 3 messages
\n\n

By the way, to speed up development, use Poedit — it will highlight untranslated strings.

\n\n

3. Intl Extension (PHP 5.3+)

\n\n

If you need not just to translate text, but to correctly format numbers, dates, or currency according to a country's standards — use Intl. It's a wrapper over the ICU (International Components for Unicode) library.

\n\n
// Number formatting                

Blogs

Book Recommendations