Multi-Language Support
How to handle multiple languages in Axiom.
Overview
Use language_code to declare which language the data in your request is written in. It labels the content you are sending — it is not a request to have that content translated into something else.
A product is one record with an English base and any number of translations attached to it, not one record per language. Sending the same product_identifier again with a different language_code adds a translation to the existing product.
When to use
Optional for each product and variant. Omitting language_code is the same as sending en.
Format
Follow these formatting guidelines to make sure that Axiom understands the data that you're submitting.
| Type | ISO 639-1 language code, optionally with an ISO 3166-1 region suffix — for example de, fr, de-CH, pt-BR |
|---|---|
| Limits | Up to 5 characters, and must be a language code Axiom supports |
| Case sensitive | No. DE and de are the same code |
| Repeated field | No. One language per product or variant payload |
| Variant inherits | Yes. A variant takes the product's language_code when the product declares one |
Fetch the supported codes from GET /api/common/language-codes, which returns each code with its name and requires the language-code-list permission. An unrecognised code fails validation.
English is always the base record
Whatever language you submit, the product's own fields end up in English. When you create a product with a non-English language_code, Axiom stores your copy as a translation for that language and machine-translates it into English for the product record itself.
This means a German-only catalogue is searchable and orderable in English as soon as it lands, while German buyers are still served your own wording.
Three details are worth knowing:
- Translation is asynchronous. The product is created immediately; the English
nameanddescriptionappear shortly afterwards. - Only
nameanddescriptionare machine-translated.product_page_urlis kept verbatim on the translation and cleared from the English record, so a product submitted only in German has no Englishproduct_page_urluntil you send one. - A machine-translated
nameis truncated to 188 characters.
Note
Machine translation only ever fills the English base record. If you have already supplied a translation for the language you're submitting, Axiom will not overwrite it with a machine translation.
Adding a translation
To add a language to an existing product, send it again with the same product_identifier — and the same variant_identifier for variants — and the new language_code. Matching identifiers are what tie the languages together, so they must be identical across every language of the same product.
What is stored per language
Only language-specific fields are held per language. Everything else is shared by every language of the product, which means the last payload to touch a shared field wins, whichever language it declared.
| Field | Scope |
|---|---|
name | Per language |
description | Per language |
product_page_url | Per language |
properties | Per language |
categories | Per language |
document_urls | Per language |
Variant options (name and value) | Per language |
codes | Shared |
image_urls | Shared |
prices | Shared |
stocks | Shared |
sku, brand, manufacturer, unit_size, unit_label | Shared |
Updating a single language
On an update, the language_code decides where the language-specific fields land:
enor omitted — the product record itself is updated.- Any other code —
name,descriptionandproduct_page_urlare written to that language's translation, and the rest of the payload updates the shared fields on the product.
So an update sent as de never changes the English wording, but it will change the shared sku, prices or codes if you include them.
Reading data back
Pass languageCode to the product detail endpoints to get a product back in a given language. Language-scoped fields resolve to that language, and shared fields are returned as-is.
The product list endpoint takes languageCode too, and applies the translation to the fields that have one:
curl --location --request GET 'https://api.axiomdata.io/api/suppliers/products?languageCode=de'
Where a product has no translation for the code you ask for, that product's fields fall back to the English base record, so a mixed-language catalogue comes back with the translations it has rather than failing.
GET /api/suppliers/products/languages returns the codes a product already exists in. It takes product_type (product or variant) and product_identifier, and requires the supplier-product-languages permission.
Regional dialects and fallback
Language codes may carry a region suffix, such as de-CH (German, Switzerland) or pt-BR (Portuguese, Brazil). Use them when your wording genuinely differs by market; use the plain code when it doesn't.
When a buyer's language is resolved against a country, Axiom promotes the request to the matching dialect if that dialect exists, then falls back down the chain.
You do not need to supply every dialect. A single de translation serves Germany, Austria and Switzerland unless you add de-AT or de-CH to override it.
Duplicate identifiers are merged
If the same product_identifier ends up on more than one product record — for example an older catalogue loaded before translations were in use — Axiom merges them into one product automatically:
- The oldest record is kept, along with its
uuid. - English content from the most recently updated English record becomes the base.
- Other languages are folded in as translations of that record.
- For codes and properties the most recent value per type or name wins, and for stock the most recent entry per country wins.
- The redundant records are deleted.
You do not need to do anything to trigger this, but it is a reason to keep identifiers stable rather than minting a new one per language.
Examples
Create a product in German
curl --location --request POST 'https://api.axiomdata.io/api/suppliers/products' \
--header 'Content-Type: application/json' \
--data-raw '{
"language_code": "de",
"product_identifier": "testproduct",
"type": "simple",
"name": "Automatischer Immunoblot-Prozessor",
"description": "Automatisiert das Protokoll für die meisten streifenbasierten Assays.",
"sku": "1234",
"brand": "BeeBlot",
"manufacturer": "Gold Standard Diagnostics",
"unit_label": "EA",
"unit_size": "1 x each"
}'
The product is created with the German copy stored as its German translation, and its English name and description follow once translation completes.
Add a French translation
Reuse the identifier and change the language:
curl --location --request PUT 'https://api.axiomdata.io/api/suppliers/products/update' \
--header 'Content-Type: application/json' \
--data-raw '{
"language_code": "fr",
"product_identifier": "testproduct",
"name": "Processeur automatisé pour immunoblot",
"description": "Automatise le protocole de la plupart des tests sur bandelettes."
}'
Read a product back in German
curl --location --request GET 'https://api.axiomdata.io/api/suppliers/products/testproduct?languageCode=de'
Check which languages a product has
curl --location --request GET 'https://api.axiomdata.io/api/suppliers/products/languages?product_type=product&product_identifier=testproduct'
Importing translations from a CSV
The products CSV has a Language Code column, and the importer expects it to be mapped. Add one row per product per language, keeping product_identifier the same across those rows.
A file cannot contain two rows with the same product identifier and language code — the importer reports There is more than one entry for the same product identifier and language code combination. Only the first entry will be processed. and skips the later rows.
Guidelines
Minimum requirements
These are the requirements that you'll need to meet to show your product. If you don't follow these requirements, we could reject your product.
- Declare the language you are actually sending. Submitting German copy without
language_codelabels it as English, which leaves untranslated German on the English record and offers nothing to German buyers. - Use the same identifiers in every language. Different identifiers create different products rather than translations. See identifiers for the full rules.
- Use a supported code. Anything not in the language list is rejected.
Best practices
These best practices can help you go beyond the basic requirements to optimise your product data for performance.
- Supply your own translations for copy that matters. Machine translation is a safety net that keeps products sellable in English, not a substitute for reviewed marketing or regulatory wording.
- Keep shared fields consistent. Because
sku,prices,codesand stock are shared, sending different values on different language payloads will overwrite each other rather than coexist. - Only add a dialect when the wording differs.
decovers every German-speaking market; reach forde-CHwhen Switzerland genuinely needs different copy.
- Overview
- When to use
- Format
- English is always the base record
- Adding a translation
- What is stored per language
- Updating a single language
- Reading data back
- Regional dialects and fallback
- Duplicate identifiers are merged
- Examples
- Create a product in German
- Add a French translation
- Read a product back in German
- Check which languages a product has
- Importing translations from a CSV
- Guidelines
- Minimum requirements
- Best practices