Import a file containing translations
POST /api/translations/import
Success: 200 OK
- Products: Operator (
FOH) - Features: Front of House Generic Access (
FOHGENERIC)
Overview
Uploads a CSV file of translated text for one language and one translation type, and writes it to the platform. Despite the name, this is a write operation, not a staging or preview step — every accepted row is saved before the response is returned.
It merges; it never replaces. Each row is created or updated against the combination of row ID, translation type, culture and property. A translation that already exists for that combination is overwritten with the value in your file; one that does not is inserted. Rows you do not mention are left exactly as they were, and nothing is ever deleted. There is no way to remove a translation through this endpoint: a blank cell is skipped, not treated as an instruction to clear the existing value. To empty a translation you must overwrite it with some other value, or use the translation write endpoints directly.
The request is multipart/form-data with two parts, both required:
| Part | Contents |
|---|---|
request | A JSON string — not a JSON body — with two properties: Language (the culture code to import into, matched case-insensitively against the platform's culture list) and TranslationType (matched case-insensitively against the configured translation types, for example Site, Product, ActivityGroup, PriceLevel). Both must be present and non-empty. |
file | The CSV. Its Content-Type must be exactly text/csv — it must match exactly, so application/vnd.ms-excel or an omitted type is rejected with 400. |
The CSV shape
Export first. The column count is derived from the translation type's own configuration and is validated strictly against your header row, so hand-building a file is the most common way to fail this call. A type has three columns as standard, five if it carries a name, and seven if it carries both a name and web comments. The exported header labels the read-only source columns (DO NOT CHANGE):
ID (DO NOT CHANGE),Name (DO NOT CHANGE),Translated Name,Description (DO NOT CHANGE),Translated DescriptionOnly the first column and the Translated … columns are read on import. The (DO NOT CHANGE) columns are there so a human editing the file can see the source text; their contents are ignored.
One quirk worth knowing: for a translation type that does not carry a name, the value in the Translated Name column is saved against the description property rather than name. If you read those translations back and find your text under description, that is why.
HTML in translated text
Angle brackets break the CSV parsing, so markup is carried in double square brackets. Export writes <b> as [[b]], and import converts [[b]] back to <b> before saving. Write markup that way in files you build yourself, and never "fix" the brackets by hand in an exported file.
Reading the result
The whole file is validated first — language, translation type, minimum line count, header column count. If any of those fail, nothing is written and you get a 400. Once past those checks the import is per row and partial: valid rows are saved and invalid ones are reported, in a single 200. Always inspect erroredRows rather than treating 200 as success.
Endpoint
POST {base_url}/api/translations/import
{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.
Sample request
curl -X POST '{base_url}/api/translations/import' \
-H 'Authorization: Bearer {accessToken}' \
-H 'X-Use-SSO: true'curl -X POST '{base_url}/api/translations/import' \
-H 'Authorization: Bearer {accessToken}' \
-H 'X-Use-SSO: true' \
-F 'request={"Language":"cy-GB","TranslationType":"Site"}' \
-F 'file=@site-translations.csv;type=text/csv'Response fields
| Field | Type | Description |
|---|---|---|
totalRows | integer (int32) | The number of data rows found in the file — every non-empty line except the header. This is the denominator, not a success count. It does not always equal rowsImported + the length of erroredRows: a row that carries an ID but leaves every Translated … column blank, and a row that is blank throughout, are both skipped silently — counted here, reported nowhere else, and written nowhere. A gap between the three numbers usually means blank cells, not a fault. |
rowsImported | integer (int32) | The number of rows that were written. Note that a single row can write up to three translation records — name, description and web comments — but still counts as one here. When this is 0 nothing is written at all, so an all-blank file is a no-op rather than an error. |
erroredRows | array of string | One human-readable string per rejected row, prefixed with its 1-based line number in the file so you can point a user at it — for example Line 4: Translations for ID "GYM01" have already been provided in the file. The three messages you can get are Incorrect number of columns (that row has a different column count from the header), ID cannot be blank when translations are provided, and Translations for ID "…" have already been provided in the file (the same ID appears twice, compared case-insensitively — only the first occurrence is imported). Empty when every row was accepted or silently skipped. |
Sample response
{
"totalRows": 1,
"rowsImported": 1,
"erroredRows": [
"string"
]
}Errors
Every 400 below is whole-file: nothing is written. Per-row problems do not produce a 400 — they come back as erroredRows inside a 200. The response body is the bare message string, not a JSON error object.
| Status | Meaning | When |
|---|---|---|
400 | Bad request | No request has been supplied — the request form part is missing or empty. |
400 | Bad request | Unable to read request object, possibly invalid JSON format — the request part is not parseable JSON. |
400 | Bad request | The format of the request is incorrect, both Language amd TranslationType must be supplied — the JSON parsed but Language or TranslationType is missing or empty. The typo in amd is present in the live message. |
400 | Bad request | No file has been supplied — the file form part is missing. |
400 | Bad request | File has no content — the file was uploaded but is zero bytes. |
400 | Bad request | File must be in text/csv format — the uploaded part's content type is not exactly text/csv. |
400 | Bad request | Language "{language}" is not a valid language — the Language value does not match any culture configured on the tenant. |
400 | Bad request | TranslationType "{type}" is not a valid translation type — the TranslationType value does not match any configured translation type. Take the value from the translation types endpoint rather than typing it. |
400 | Bad request | File must contain more than one line (the first line is the header) — the file has fewer than two non-empty lines. A header on its own is not enough. |
400 | Bad request | File must contain {expected} columns but actually contains {actual} — the header row's column count does not match what the translation type requires. Export the file first rather than guessing. |
500 | Internal server error | An unexpected server-side failure during parsing or saving. The response body is empty. Note that a translated value containing certain special characters — a lone backslash, for instance — can fail the whole call here rather than being reported as a row error. |