Next-Level Code. Nexuvibe Style ...

Hrs
Min
Sec
Gettext Handoff • Agency QA Gates 2026

PO vs MO in WordPress:
What Agencies Should Verify Before Handing a Locale to QA

The PO file is where humans argue about wording. The MO file is what WordPress loads at runtime. Agencies that confuse the two—or ship one without verifying the other—create QA loops where testers report ghosts: strings that were “translated” in Loco yet never compiled, or MO caches that lag behind a PO someone edited elsewhere.

15 min read
Updated 2026
WordPress Localization Guide
PO versus MO gettext files in WordPress Loco Translate agency QA handoff checklist before locale testing WooCommerce multilingual 2026

If you run a WordPress agency, you have watched this failure mode more than once. A developer edits translations in a PO under version control, while another teammate saves different strings inside Loco on staging. QA opens the storefront, still sees stale English, and files a dozen tickets. The root cause is not “translation quality.” It is artifact discipline: which file is authoritative, when it was compiled, and whether the runtime binary the site loads actually reflects the text reviewers approved.

This article is a handoff checklist written for project leads and localization owners. It explains what PO and MO files are responsible for in a WordPress context, what to verify before you invite QA to spend hours clicking flows, and how AI-assisted translation inside Loco still has to obey the same compilation and caching realities as manual work.

When bulk or per-string assistance is part of your workflow, a Loco AI Auto Translator integration that keeps PO edits and compile-ready output aligned for WordPress gettext reduces the chance that speed upstream becomes confusion downstream.

What this guide covers
The division of labor between PO (editable) and MO (runtime) in gettext.
What Loco Translate saves locally versus what PHP’s gettext loader consumes.
Pre-QA verification steps agencies should run for every locale handoff.
Caching, opcode caches, and object caches that mask fresh translations.
How AI-filled catalogs still require the same compile-and-diff discipline.
Artifacts to attach to tickets so QA does not chase non-issues.

PO and MO: two artifacts, one contract with the runtime

A PO file is plain text aimed at humans and diff tools. It lists msgid entries with their msgstr translations, plus comments that help translators understand context. An MO file is a binary message catalog compiled from that PO. WordPress does not “read” the PO on every request in the way a developer reads it in an editor. It loads the MO through gettext APIs, which expect a compiled structure optimized for lookup speed.

That distinction is why “we updated translations” is not a single fact. It is two events unless your toolchain guarantees compilation. Loco Translate can manage both the editable PO and the compiled MO in many setups, but your agency process must still state which environment is canonical and who triggers compilation. Otherwise QA receives contradictory instructions: “translations are done” refers to the PO, while the site still serves yesterday’s MO.

PO: collaborative, auditable

Ideal for review in Git, comments in tickets, and side-by-side comparison during legal sign-off. If your client asks for proof of what changed, the PO diff is the proof.

MO: operational, sensitive to staleness

This is what production uses. If it is stale, customers see stale strings regardless of how polished the PO became in Loco five minutes ago.

The GNU gettext manual explains MO files as compiled message catalogs derived from PO sources. When a technical stakeholder pushes back on “why we need a compile step,” the gettext manual’s description of MO files is a neutral, engineer-friendly citation.

🔗Agencies must also verify how to locate block theme strings in Loco Translate, as Full Site Editing shifts translatable text into JSON and dynamic block patterns. →

Another practical detail agencies should verbalize in kickoff: who is allowed to edit the PO in Loco on production versus staging. If production edits are permitted for hotfixes, your MO compile step must be part of the same change window, not “something we will batch on Friday.” Hotfix culture and gettext discipline can coexist, but only when compile and flush are explicit checklist items beside the deploy note. Otherwise you train the organization to believe the PO is truth while customers still read yesterday’s MO until an unrelated deploy accidentally refreshes caches.

How WordPress actually loads translations (and where agencies get surprised)

WordPress core and well-behaved plugins call translation APIs that ultimately rely on gettext loaders and file paths under wp-content/languages or plugin-specific language directories. The exact pathing depends on the component, text domain, and whether custom locations were registered. That means “we translated the plugin” is not interchangeable with “we translated core WooCommerce strings” unless you verified the text domains and target directories for each bundle.

Agencies also stumble over mixed delivery models. Some teams commit PO files to Git and deploy them with the theme. Others treat Loco’s saved copies as authoritative on the server. Both can work. The failure is hybrid ambiguity: two authorities, no merge strategy. Before QA, pick one story and document it in the runbook.

Handoff note that saves QA time
List each text domain in scope, the directory where its MO should live, and the username or automation account that last compiled it. QA should never guess.

For the broader expectations of how themes and plugins internationalize strings, WordPress developer documentation on internationalization remains the canonical overview to share with engineers who are new to gettext on WordPress.

Multisite and multi-store networks add another surprise: language files may be shared or overridden per site in ways that are invisible from a single Loco screen. A translator working on site ID 3 might compile an MO that site ID 4 never loads because a different upload path or symlink is in play. Network handoffs should name the site ID, URL, and whether language files live in a shared mu-plugins language directory or per-site uploads. QA tickets that omit those identifiers waste time comparing the wrong storefront to the right file.

The pre-QA verification grid: timestamps, hashes, and spot checks

Before you invite QA to execute a thirty-case spreadsheet, run a ten-minute verification grid. First, confirm the MO file’s modification time is newer than the PO you claim to have finished. Second, open a known string in Loco and compare it to what the storefront renders for the same locale. Third, repeat for one admin screen and one email preview if emails are in scope. If those three checks disagree, stop. QA should not be your first debugging layer for compilation problems.

Fourth, verify plural forms and ICU-like messages on at least one representative row per pattern type. Fifth, confirm that placeholder tokens survived compilation. These checks sound tedious; they are cheaper than a rejected release build.

🔗Ensuring consistency between PO edits and runtime MO files requires agencies to implement version-control translation files in Git, especially when AI bulk-translates thousands of strings. →

Sixth, compare file sizes or checksums between environments. Staging MOs that mysteriously shrink often indicate an incomplete compile or a wrong text domain packaged into the binary. Seventh, if you use Git, ensure the MO you think you deployed is the same commit hash QA is testing. “Works on my machine” in localization usually means “works in my working tree,” which is not a release artifact.

Eighth, run one automated smoke script if you have it: load the cart page, the checkout block or shortcode page, and the order-received endpoint with a test product. Capture HTML snippets containing three known strings. Attach those snippets to the ticket. QA can then focus on linguistic quality instead of proving the pipeline functions.

CheckPass signalFail signal
MO newer than POFilesystem mtimes align with handoff noteMO older: compile step skipped
Storefront spot stringRendered text matches approved PO rowEnglish leak or stale phrasing
Cache layerPurged or bypassed on stagingOPcache/page cache serves old PHP paths
Email preview stringTest send shows updated target textTemplate still references old MO

If AI assistance filled hundreds of rows, the verification grid becomes more important, not less. Models do not compile files; people and tooling do. Bulk AI translation in Loco with export-friendly PO workflows for WordPress locales still requires an owner who signs off that the MO on disk matches the approved PO state.

Caching: the invisible reason QA sees “wrong” language

Even when MO files are correct, caches lie. Full-page caches can store HTML from before a translation deploy. Object caches may memoize translation lookups. Opcode caches can delay seeing updated plugin language paths if deployment and symlink patterns are unconventional. Your handoff should name which caches were flushed, by whom, and when.

For WooCommerce flows, also remember customer session and geolocation edge cases. QA should test with a logged-in user in the target locale, not only an anonymous window that might follow different language negotiation rules. Document the test user, billing country, and profile language preference. Small details prevent false negatives.

CDN and edge layers deserve explicit mention. If HTML is cached at the edge, purging only WordPress object cache is insufficient. Your runbook should state whether translation deploys require a CDN purge, a cache tag invalidation, or a short TTL policy during QA week. Teams that forget this step spend days debating gettext when the issue is HTTP caching of rendered markup.

✓ Document
Cache flush checklist item with owner initials and timestamp.
✗ Avoid
“Hard refresh should fix it” as your only staging guidance.

Operational tooling should not pretend caching is someone else’s problem. Loco AI Auto Translator can help you finish gettext catalogs faster on multilingual WooCommerce stores, but your runbook still owns cache invalidation after MO updates.

🔗Agencies often overlook child theme translation duplication when verifying PO files, leading to redundant strings that complicate QA handoffs. →

Text domains, bundle boundaries, and why QA needs a map

A locale is not one file. It is a constellation of domains: woocommerce, your theme, your page builder companion plugin, the membership extension, the CRM bridge. QA tickets that say “German is broken” without naming the surface and domain waste engineering time. Your handoff map should correlate screens to domains and to the PO/MO pair that feeds them.

When AI assistance is used, require the same map. Bulk operations that span domains without explicit boundaries are how you accidentally “fix” a marketing plugin while leaving WooCommerce core leaks untouched, then argue about priorities.

Child themes deserve a special row on the map. Strings may exist in both parent and child domains; translators might fill one while the live site reads the other. Before QA, reconcile duplicates rather than hoping shoppers will not notice contradictory labels between shop archive and single product templates.

Artifacts that belong in every QA ticket packet

Attach artifacts, not vibes. Minimum: the PO export checksum or short hash, the MO path, a three-line summary of bundles touched, and screenshots of the spot checks. If legal reviewed payment strings, include the approval reference. If AI assistance was used, include the model or prompt version and the date range of the run. Future-you will thank present-you when a client asks what happened in March.

Version your handoff packet filename with the sprint number or release tag. “locale-handoff-de-DE-v3.zip” communicates more than “translations.zip.” Inside the archive, prefer text formats QA can open without special tools, plus a short README that explains how to reproduce your spot checks. The goal is to remove interpretive labor from the QA kickoff meeting.

Packet checklist

1. PO export file name + timestamp
2. MO path + timestamp
3. Cache flush log
4. Domain map excerpt for surfaces in test plan

Linking tooling to the packet is straightforward: Loco AI Auto Translator editor actions for per-string gettext review before MO compilation help you generate cleaner PO exports that match what you describe to QA.

When MO is right but UX still feels wrong: duplication and override chains

Sometimes QA is correct that the screen “looks untranslated” even when your MO is fresh. The culprit may be a duplicate string defined in another bundle with higher precedence, a child theme override, a hard-coded English fragment in a template bypassing gettext, or content stored in the database rather than in language files. Your verification grid should include one “deep trace” ticket per release that follows a single problematic label from UI to source.

This is not an argument against MO discipline. It is a reminder that gettext files are one layer in a stack. Agencies that document override chains reduce ping-pong between developers and testers.

When tracing failures, teach QA to capture the DOM snippet and the computed locale, not only a screenshot. Developers can grep templates faster when they see the exact English fragment and the URL. Likewise, teach developers to respond with the file path and gettext call they believe should own the string. That mutual discipline turns emotional debates into addressable tickets.

Git, deploy pipelines, and when the PO in the repo disagrees with Loco on the server

Many agencies keep PO files in Git for themes and custom plugins, then also use Loco on the server for vendor bundles. That split is workable if merges are intentional. It fails when a deploy overwrites a server-side PO with an older repo copy, or when Loco saves to a path Git never tracks. Your handoff should state the direction of truth for each bundle: repo wins, server wins, or explicit two-way sync with a named owner.

CI can compile MO artifacts in the pipeline and attach them as release binaries. That pattern is attractive because it removes “someone forgot to click compile” from the human path. It also requires developers to treat PO merges like code merges: conflicts must be resolved with translator input, not silently chosen by the last committer.

If you are not ready for CI compilation, at minimum block deploys that touch language directories without a paired MO update checklist item. Operations standards sound unrelated to translation quality until a Friday deploy reverts MO files and QA spends a weekend re-validating flows that were already green.

PO and MO alignment is the prerequisite for meaningful QA. Without it, you are testing phantoms. With it, testers can focus on genuine linguistic issues, accessibility of translated copy, and commerce flows that depend on precise wording near money movement. Treat every handoff as a small release: name the build, name the files, and name the caches you cleared. That formality feels heavy until it prevents a production incident that no amount of post facto “we thought it was deployed” narrative can unwind cleanly for the client.

If your team is investing in AI-assisted throughput inside Loco, invest equally in compile-and-handoff hygiene. The Loco AI Auto Translator WordPress plugin combining bulk gettext fills with Loco-native review workflows fits teams that want speed in the PO without sacrificing MO certainty at release time.

Loco AI Auto Translator product thumbnail settings panel for WordPress gettext localization teams

Loco AI Auto Translator
Accelerate PO work inside Loco while your team keeps MO compilation, caching, and QA handoffs disciplined.

Get Loco AI Auto Translator

Picture of Mahdi Jabinpour

Mahdi Jabinpour

As a sales-driven developer and the founder of NexuWP, Mahdi focuses on building WordPress solutions that don't just work—they convert. From AI-powered bulk translation engines to high-efficiency media offloading, he helps business owners automate the "grind" so they can focus on global growth. He is a pioneer in integrating advanced LLMs into the WordPress workflow.

RELATED POSTS

RELATED POSTS

3 Reviews
William Miller 2 months ago

Finally a clear breakdown of PO vs MO! saved my team hours by attaching both files to tickets

Jennifer Rodriguez 3 months ago

The PO vs MO difference here is so real and honestly saved my team from a total QA disaster last sprint. We had two devs updating translations in different spots one in version control, the other in Loco on staging and no matter how many times we "fixed" the PO file, QA kept flagging old English strings. Turns out the MO file never got recompiled after our last edit. not blaming the tool at all, but this guide should've been the first thing we read before diving into localization.

Mansour jabinpour 3 months ago

That's exactly the kind of headache this guide was written to prevent.

Robert Garcia 3 months ago

Hey, this really cleared up the PO vs MO files confusion for me.

Mahdi Jabinpour 3 months ago

Thank you.

Please log in to leave a review.