Як скомпілювати файли .po в .mo (4 методи)

Ви провели цілий день, доводячи до досконалості німецький переклад. Кожен рядок у вашому файлі de_DE.po виглядає чудово, плейсхолдери цілі, множинні форми правильні. Ви завантажуєте його на свій сайт, перемикаєте мову на німецьку, і... нічого. Сторінка все ще англійською. Ви двічі перевіряєте ім'я файлу, папку, текстовий домен. Все виглядає правильно. То чому ж WordPress не показує ваш переклад?
У дев'яти випадках із десяти відповідь одна й та сама: ви відредагували .po, але так і не скомпілювали його в .mo. WordPress не читає файли .po під час виконання — він завантажує скомпільований бінарний .mo. Якщо ви хочете, щоб ваші переклади дійсно з'явилися, вам потрібно компілювати po в mo щоразу, коли ви змінюєте текст. .po — це ваш джерело, яке можна редагувати; .mo — це те, що сайт надає.
Цей посібник пояснює, чому існує цей крок компіляції, а потім розглядає чотири надійні способи його виконання: WP-CLI, класична команда msgfmt, Poedit та хмарний інструмент, який автоматично створює .mo для вас. Ми також розглянемо найпоширенішу помилку — забування перекомпілювати — та новіший формат .l10n.php, якому WordPress тепер віддає перевагу для швидкості.
Чому WordPress завантажує .mo, а не .po?
WordPress завантажує файли .mo, оскільки це скомпільовані бінарні файли, оптимізовані для швидкого пошуку, тоді як файли .po є простим текстом, створеним для читання та редагування людьми. Аналіз тексту при кожному завантаженні сторінки був би повільним; читання попередньо створеної бінарної хеш-таблиці відбувається майже миттєво.
Файл .po є рядковим і зручним для людини. Кожен запис поєднує вихідний msgid із перекладеним msgstr, а також коментарі, що вказують, звідки походить рядок. Це чудово для редагування, але жахливо для продуктивності — серверу довелося б повторно аналізувати весь текстовий файл при кожному запиті.
#: includes/cart.php:88
msgid "Your cart is empty"
msgstr "Ihr Warenkorb ist leer"
Файл .mo упаковує ті самі пари рядків у бінарний формат із внутрішньою таблицею пошуку, тому WordPress може перейти безпосередньо до перекладу, не скануючи текст. Компроміс полягає в тому, що .mo нечитабельний для людей і повинен бути повторно згенерований щоразу, коли змінюється .po. Якщо відмінність між .po та .mo все ще нечітка, наш пояснювальний матеріал про файли .po проти .mo проти .pot розбиває кожен формат і пояснює їхній взаємозв'язок.
Чотири способи компіляції po в mo
Не існує єдиного "правильного" інструменту — найкращий вибір залежить від того, як ви вже працюєте. Нижче наведено чотири надійні методи, від однорядкової команди до повністю автоматизованого хмарного робочого процесу. Всі чотири створюють ідентичний бінарний файл .mo, який WordPress завантажує під час виконання.
Метод 1: WP-CLI
Найчистіший сучасний підхід — це WP-CLI, який може скомпілювати цілу папку файлів .po однією командою. Якщо ви вже керуєте WordPress з командного рядка, це природно впишеться у ваш робочий процес.
# Compile every .po file in the languages folder to .mo
wp i18n make-mo languages/
# Compile into a specific destination directory
wp i18n make-mo languages/ build/languages/
Команда make-mo сканує цільову директорію, компілює кожен знайдений .po і записує відповідний .mo поруч із ним (або в вказане вами місце призначення). Вона елегантно обробляє пакети, що робить її ідеальною, коли ви підтримуєте багато мов одночасно. Це рекомендований інструмент для будь-якого проекту, який вже використовує WP-CLI.
Метод 2: msgfmt
Оригінальна утиліта Gettext для цієї роботи — msgfmt, частина пакету GNU gettext. Вона компілює один .po в один .mo і доступна практично на кожній системі Linux та macOS.
# Compile one file
msgfmt my-plugin-de_DE.po -o my-plugin-de_DE.mo
# Add statistics about translated, fuzzy, and untranslated strings
msgfmt --statistics my-plugin-de_DE.po -o my-plugin-de_DE.mo
# Install it first if missing
# macOS: brew install gettext
# Debian: sudo apt-get install gettext
Прапорець -o вказує ім'я вихідного файлу. Прапорець --statistics справді корисний — він повідомляє, скільки рядків перекладено, невизначених або все ще порожніх, тому ви можете виявити неповний переклад до його випуску. Для обробки одного файлу за раз, msgfmt — це надійний, без зайвих функцій вибір.
Оскільки msgfmt є простим інструментом командного рядка, він легко інтегрується в автоматизацію. Ви можете обернути його в цикл оболонки для компіляції цілої папки або підключити його до конвеєра CI, щоб кожен коміт, який зачіпає .po, автоматично створював свіжий .mo. Поширений шаблон — for f in languages/*.po; do msgfmt "$f" -o "${f%.po}.mo"; done, який компілює кожну мову за один прохід. Прапорець --check додає валідацію, позначаючи невідповідності форматних рядків між msgid та msgstr до того, як вони досягнуть виробництва — дешевий запобіжний захід проти помилок із зламаними плейсхолдерами, які мовчки пошкоджують перекладені макети.
Метод 3: Poedit (компілює при збереженні)
Якщо ви редагуєте переклади в графічному редакторі, Poedit компілює для вас автоматично. Щоразу, коли ви зберігаєте файл .po, Poedit записує відповідний .mo поруч із ним — без окремої команди, без додаткового кроку.
Це одна з причин, чому Poedit залишається популярним серед перекладачів, які незручно працюють з командним рядком. Ви відкриваєте .po, вводите свої переклади, натискаєте зберегти, і обидва файли оновлюються одночасно. Ви можете перевірити цю поведінку в налаштуваннях Poedit, де автоматична компіляція .mo при збереженні увімкнена за замовчуванням. Poedit та подібні настільні інструменти розглядаються в статті 5 найкращих безкоштовних інструментів для редагування та перекладу файлів PO на Mac та Windows.
Недолік настільного редактора полягає в тому, що компіляція відбувається лише тоді, коли людина відкриває файл і зберігає його. Це добре для проекту однієї людини, але не масштабується до дюжини мов або команди, яка передає файли туди-сюди. Якщо хтось редагує .po в іншому інструменті і копіює його в репозиторій, не відкриваючи Poedit, .mo ніколи не оновлюється. Для більших або спільних проектів автоматизований метод — командний рядок або хмара — усуває цю залежність від необхідності пам'ятати про натискання кнопки збереження.
Метод 4: Хмарний інструмент, який генерує .mo для вас
Четвертий варіант повністю усуває крок компіляції: використовуйте хмарний сервіс, який повертає скомпільований .mo разом із перекладеним .po. Ви ніколи не запускаєте команду і не зберігаєте файл двічі — ви завантажуєте, а готові, правильно названі файли повертаються.
SimplePoTranslate працює саме так. Ви завантажуєте .po або .pot, він перекладає рядки за допомогою Context-Aware AI, і повертає єдиний ZIP-архів, що містить .po та .mo, згенеровані поруч — вже скомпільовані, вже названі відповідно до вашого текстового домену та локалі. Немає окремого проходу компіляції та жодного шансу забути про нього.
Він також обробляє деталі, які руйнують ручні робочі процеси. Syntax Locking заморожує плейсхолдери, такі як %s, %1$s та {name}, а також HTML-теги перед перекладом, тому ваші змінні зберігаються в .mo неушкодженими. Повна підтримка Gettext plural означає, що складні множинні форми також компілюються правильно — тема, яку варто глибоко зрозуміти, і яку ми розглядаємо в статті розуміння множинних форм Gettext. І оскільки він працює в хмарі, не потрібно встановлювати плагіни та підтримувати інструменти збирання.
Найпоширеніша пастка: ви забули перекомпілювати
Найбільша причина, чому переклади не з'являються, — це редагування .po, але забування перекомпілювати .mo. WordPress продовжує завантажувати старий бінарний файл, тому ваше нове формулювання ніколи не відображається — і немає повідомлення про помилку, яке б пояснило, чому.
Ментальна модель, яку варто запам'ятати: .po — це ваш чернетка, .mo — це те, що публікується. Будь-яка зміна в .po є невидимою для WordPress, доки ви не регенеруєте .mo. Зробіть перекомпіляцію рефлексом після кожної зміни, або використовуйте інструмент, який компілює автоматично, щоб цей крок ніколи не пропускався.
Ця пастка особливо підступна при передачі від стейджингу до продакшену. Розробник редагує та перекомпілює локально, бачить, що переклад працює, потім розгортає лише .po і забуває про .mo — тому продакшен мовчки зберігає старий текст. Щоразу, коли ви переміщуєте файли перекладів між середовищами, переміщуйте .po та щойно скомпільований .mo разом, або компілюйте як частину кроку розгортання, щоб бінарний файл завжди відбудовувався з поточного джерела.
Якщо ваші переклади все ще відмовляються з'являтися після перекомпіляції, проблема зазвичай полягає в невідповідності імен, неправильній папці або шарі кешу, що зберігає старий файл. Повний контрольний список знаходиться в статті чому ваші переклади не відображаються у WordPress.
Примітка щодо новішого формату .l10n.php
Останні версії WordPress представили третій формат виконання: .l10n.php. Замість бінарного .mo переклади зберігаються як простий PHP-масив, який кеш опкодів PHP може зберігати в пам'яті, що робить пошук ще швидшим, ніж .mo на зайнятих сайтах.
<?php
return [
'domain' => 'my-plugin',
'messages' => [ 'Your cart is empty' => 'Ihr Warenkorb ist leer' ],
];
WordPress генерує файли .l10n.php автоматично, коли має відповідний .mo, тому вам не потрібно створювати їх вручну. Наразі компіляція правильного .mo залишається основою — формат продуктивності походить від нього.
Підсумок
Щоб надійно скомпілювати po в mo, оберіть метод, який відповідає вашому способу роботи: WP-CLI для пакетної обробки з командного рядка, msgfmt для окремих файлів зі статистикою, Poedit для автоматичної компіляції при збереженні або хмарний інструмент, який створює .mo для вас, щоб цей крок ніколи не пропускався. Всі чотири створюють той самий бінарний файл, який потрібен WordPress під час виконання.
Який би шлях ви не обрали, пам'ятайте золоте правило: редагуйте .po, потім компілюйте в .mo — щоразу. Ця одна звичка запобігає найрозчаруючішій помилці перекладу в WordPress, коли все виглядає правильно, але сайт вперто залишається англійською.
Готові назавжди пропустити крок ручної компіляції? Спробуйте SimplePoTranslate безкоштовно — кредитна картка не потрібна. Завантажте свій
.poі завантажте готовий до розгортання пакет.po+.moна безкоштовному рівні за лічені хвилини.