Medusa multi-language: how translations work and what breaks at scale
Since version 2.12.3 Medusa stores translations natively, which settles where multilingual content lives and none of what actually breaks in bulk translation: markup, brand names, units and field limits. Here is what the Translation Module covers as of 17 August 2026, the six failures that repeat, and the checks that catch them before publication.
Moving a few thousand product pages into a second language rarely fails on language. A product description is structured data in a text field: markup, units, attribute values and proper names have to come back untouched, and only the prose is supposed to change. Blur that line and a translation that reads beautifully still breaks the page layout, the filters and on-site search in the new market.
Key takeaways
- Medusa has had a first-party Translation Module since v2.12.3, released on 17 December 2025, behind a feature flag and scoped to product-related resources. Where translations live is no longer the hard part.
- The module stores whatever you hand it. Nothing checks that the translated HTML carries the same tags, that a model name survived, or that a field still fits a channel limit.
- A missing translation is not an error. Medusa falls back to the original value, so a half-finished batch renders as a working page in the source language and hides from any spot check.
- Six failures repeat regardless of platform: markup, proper nouns, units and number formats, attributes against description, field length, and terminology drift between batches. Each one has a machine check.
On Medusa the ground moved recently. Since version 2.12.3, released on 17 December 2025, a Translation Module ships with the core, so the question of where translations live is settled. What the platform still does not answer is whether the translation you loaded is structurally sound.
Why a catalog is harder than an article
Translating an article means translating sentences. Translating a catalog means pushing three different kinds of content through one pipeline, and only one of them is language.
- Prose: the marketing paragraph, the use case, the care instructions. The only layer a language model should be free to rewrite.
- Data dressed as text: attribute values, units, dimensions, material names. These belong to a controlled list translated once and applied everywhere, not per product.
- Identifiers: brands, model names, part numbers, HTML tags. These must return character for character, because a customer types them into search and a sales channel matches on them.
The three layers arrive mixed into one field. A description with a paragraph of copy followed by a bulleted spec list carries all of them at once, plus the HTML holding them apart. The model receives one string and treats it as one job.
What Medusa gives you today, and what it does not
Facts first, checked in the Medusa documentation on 17 August 2026. The Translation Module is part of the core but is not on by default: the docs require version 2.12.3 or later, an entry in the modules array of medusa-config.ts, the translation feature flag and a database migration.
The data model is deliberately thin. A translation record points at a resource with three fields, the table name, the resource id and a locale code in IETF BCP 47 form, and carries a JSON object of translated fields such as title and description. One resource has one translation per locale.
A storefront asks for a language with a locale query parameter or an x-medusa-locale header, the query parameter taking priority when both are present. Store routes get this automatically, custom routes need the applyLocale middleware. Locales populate themselves the first time the module is used, and supported ones are picked in store settings.
Coverage is product shaped. Products, variants, options, categories, collections, tags and types are translatable, along with regions, shipping options, tax rates and customer groups. The documentation states plainly that support for all Commerce Modules is coming in future versions, so anything outside that list is still yours to solve.
In the admin, translations are edited from an individual resource or in a bulk editor per locale in settings, and an admin can configure which resources and fields are translatable at all. Loading a whole catalog is a different job: the documented path is the module service called from a workflow, so bulk import is your own code.
One behaviour to know before you load anything: when a translation is missing, Medusa serves the original value from the resource. Good for the customer, dangerous for you. A batch that only half succeeded raises no error, it renders a page in the source language. That looks correct in a browser and is invisible to a spot check.
Four years of the request, eight months of the answer
For a sense of how long this was missing: the "Multi-language support" discussion in the Medusa repository was opened on 5 August 2022 and was still open on 17 August 2026, with 111 comments and replies and 65 thumbs-up reactions. The demand was visible for four years.
The practical conclusion is not the reflexive one. It is not that Medusa lacks multi-language support. It is that the answer is young and marked experimental. Check the version yourself before you promise anything to a client: 2.19.0 shipped on 13 August 2026, and a module behind a feature flag moves faster than any article about it.
Six things that break in bulk translation
These failures repeat across platforms and tools, because they come from the shape of the data rather than from the choice of model. Each one has a check a machine can run, which is the point: a human reviewer will only ever see a sample.
- Markup: tags get dropped, renested or duplicated, and attribute values such as alt text quietly turn into translated prose.
- Proper nouns: brands and model names get translated or "corrected", after which no customer finds them in search.
- Units and number formats: separators change, numbers get converted without being asked, and the space between value and unit comes and goes.
- Attributes against description: the same attribute value gets a slightly different wording on every product, so one filter splits into near duplicates.
- Field length: a translated field outgrows a channel limit or a layout that fitted the source language.
- Terminology drift: batch three uses a different word than batch one, because nothing carried the decision between runs.
Markup: compare the tag sequence, not the text
The reliable guard is not a better sentence in the prompt. It is a comparison of input and output at the structural level: the ordered sequence of opening and closing tags with their attributes has to be identical, and only text nodes are allowed to differ.
That check is cheap to write and binary, so it belongs in the pipeline as a gate rather than in the review. Whatever fails goes back for a retry or to a human and never reaches the field. The stricter version parses the HTML, translates text nodes one at a time and reassembles the document, so markup is never in the model output in the first place.
Proper nouns: take them out before the model sees them
A do-not-translate list in the prompt helps and does not survive scale. Substitution does: every protected name is replaced with a placeholder token before the call and restored afterwards. The check then becomes trivial, because every token that went out has to come back exactly once.
The same trick covers part numbers, sizes written as codes and anything else that is an identifier rather than a word. It also turns a silent failure into a loud one, which is the entire purpose of the exercise.
Units and numbers are data, not language
The model converts nothing. Conversion between unit systems is a rule in your data, with a table per market, and it either runs deliberately or it does not run at all. What the translation step owes you is the same numeric tokens it received, in the same order.
Formatting is a separate decision, made once per market: decimal separator, thousands separator, and the space between value and unit. Applied as a rule it stays consistent across the catalog. Left to the model it stays consistent within a batch and changes in the next one.
| What breaks | How it shows up | Check you can automate |
|---|---|---|
| HTML markup | Broken product page layout, a list collapsed into one paragraph | Identical tag and attribute sequence in and out |
| Brands and model names | Customers and channels cannot find the product by name | Every protected token present exactly once |
| Units and numbers | Wrong specification on the page, returns you cannot explain | Numeric tokens preserved, formatting applied by rule per market |
| Attribute values | One filter split into near duplicate values | Values come from a translated list, never from free text |
| Field length | Rejected feed rows, truncated titles in the storefront | Length of each field measured against the limit where it is going |
| Terminology | The same term rendered three ways in one catalog | Term list applied and re-checked on every batch |
A reviewer sees a sample. These six checks see the whole catalog, which is why they run first.
The glossary is a file in the pipeline, not a document in a drive
Every project that ships thousands of translated fields ends up with the same artefact, whatever it gets called: a machine readable list of decisions that travels with every batch. Three parts do the work.
- Do not translate: brands, model names, part numbers, ingredient names you have deliberately kept in the source language. This list becomes your placeholder tokens.
- Approved renderings: one target form per term, including the awkward ones where a dictionary offers three correct options and your category has settled on one.
- Attribute vocabulary: the controlled list of values, translated once and applied as data, so colour and material are never retranslated per product.
Translation memory is the same idea stretched over time. Without it, batch four cannot know what batch one decided, and the catalog drifts in ways nobody notices until a customer asks why two identical products are described differently.
The human half of that loop, who reviews, against which test, and how corrections become rules, we covered separately in AI catalog translation. This article stays on the machine half, because that is the part a platform can enforce.
What to check before anything goes live
Four checks, in this order. The first three are automatic and cover everything. The fourth is human and covers a sample, which is only meaningful once the first three are clean.
- Structural validation: tag parity, placeholder parity, numeric parity. Fail the row rather than the batch, and keep failures visible.
- Coverage report: query translations per locale and per field, then compare against the resources that should have them. Because of the fallback, this cannot be done by browsing the storefront.
- Length report: every translated field measured against the limit of the place it is going, storefront layout and channel feed included. Flag it, do not truncate it quietly.
- Human sample: a reviewer who knows the target market reads a sample from each batch, weighted towards the hard categories rather than the easy ones.
The fallback deserves its own line in the plan. A missing translation renders as the source language, so an English page on a French locale will not arrive as a customer complaint. It is a silent gap. Coverage is a number you query from the database, not something you happen to notice.
We build pipelines like this inside the platform rather than beside it, as the AI Automation stage of BEAM, so the glossary, the validators and the loading step live in the same repository as the store.
When this is not worth automating
Below a certain size the whole apparatus costs more than the work it replaces. A few hundred stable products going into one language is a translation job with a proofread, and a good translator will do it better than a pipeline, because the pipeline has to be built, tuned and maintained first.
The fixed cost is real: the term list, the validators, the loading step, the review loop. Our AI Automation work starts at 6 000 PLN net per workflow, roughly 1 400 EUR at 4.31 PLN to the euro (NBP mid rate, 17 August 2026). That is a range for scoping rather than an offer, and the honest comparison is against translating your catalog manually once.
Automation starts paying when the catalog keeps moving: new products every week, descriptions edited by several people, a second and third market on the plan. Then the cost spreads across every future batch instead of a single one. How we scope and price that work sits on the pricing page.
The second stop condition has nothing to do with size. If nobody in the company can judge whether the result sounds like a store from that market, the pipeline will produce fluent text that no one is able to approve. How much of a market entry is not language at all, we set out in the checklist for entering the German market.
None of this is specific to Medusa, but Medusa is currently the easiest place to get it right, because the core finally has somewhere to put translations and an API that serves them per locale. What we build around that is on AI catalog translations. The platform side sits on Medusa development and eCommerce platforms.
Sources
Every link checked on 17 August 2026. The module is marked experimental and sits behind a feature flag, so check the documentation for your own version before you build on it.
- Medusa, Translation Module documentation: docs.medusajs.com/resources/commerce-modules/translation, including the concepts and storefront sections.
- Medusa, localization in API routes: docs.medusajs.com/learn/fundamentals/api-routes/localization.
- Medusa, admin user guide, translation settings: docs.medusajs.com/user-guide/settings/translations.
- Medusa, release v2.12.3 of 17 December 2025, where translations first appeared: github.com/medusajs/medusa/releases/tag/v2.12.3.
- Medusa, "Multi-language support" discussion opened on 5 August 2022 and still open: github.com/medusajs/medusa/discussions/2003.
FAQ
Does Medusa support multi-language catalogs?
Since version 2.12.3, released on 17 December 2025, yes, for product-related resources plus regions, shipping options, tax rates and customer groups. The Translation Module sits behind a feature flag, needs an entry in your configuration and a database migration, and was described as experimental in the release that introduced it. State checked on 17 August 2026.
Where does Medusa store translations?
In a separate record that points at a resource by table name and id, carries a locale code in IETF BCP 47 form and a JSON object of translated fields. One resource has one translation per locale. A storefront requests a language with a locale query parameter or an x-medusa-locale header.
Why does my French storefront show English descriptions?
Because Medusa does not treat a missing translation as an error. It falls back to the original value stored on the resource, so the page looks correct while the translation is absent. Coverage has to be verified by querying translations per locale and per field, not by clicking through the storefront.
How do I stop bulk translation from breaking HTML in product descriptions?
Either parse the description, translate only the text nodes and reassemble the document yourself, or compare the sequence of tags and attributes before and after and reject every row where it differs. The prompt is guidance here, not a safeguard.
How do I protect brand and model names from being translated?
Most reliably by replacing them with placeholder tokens before the text reaches the model and restoring them afterwards. The check then reduces to confirming that every token came back exactly once. A do-not-translate list in the prompt is enough for a few dozen products, not for a few thousand.
Do I still need an external translation system with Medusa?
Not for storing and serving translations, the core module does that. Consider one when you need a workflow for external translators, a change history, or translations of content outside the product-related models the module does not cover yet.
Journal
Co-founder of Seedlight · eCommerce platforms, AI, SEO and GEO
Newsletter
The Journal, straight to your inbox
New articles and lessons from real builds, every now and then. No spam, unsubscribe with one click.