This endpoint commits a translation value for one key in one target language. It is the API equivalent of the save translation action in the editor: it creates a new translation version from the value you send, and it does not machine-translate. To generate a value instead of supplying one, see Translation Suggestions.
Submit a translation #️⃣
[POST] /projects/{projectId}/keys/{id}/translations/{lang}| Description | Value |
|---|---|
| Accessible with project token | true |
| Accessible with organization token | true |
| Need write permission | true |
| Available from role | translator |
| API level | normal |
Params
{projectId}- Your projectidorslug. Use the value from the projects endpoint.{id}- The key (phrase) id. Use the value from the file content endpoint.{lang}- The target language, as a language code (e.g.pt_BR,cs) or its numeric language id (e.g.112,60).
Language codes may contain a #, for example zh#Hans. Percent-encode it as zh%23Hans when building the URL, otherwise everything after the # is treated as a URL fragment and never reaches the server.
Request Body #️⃣
A JSON object with a single required field, value, whose shape must match the key’s form.
| Key form | value shape |
Example |
|---|---|---|
| Singular | A string | {"value": "Save changes"} |
| Array | An array of strings | {"value": ["First", "Second"]} |
| Plural | An object keyed by CLDR plural class | {"value": {"one": "1 item", "other": "%d items"}} |
For plural keys, include one entry per plural class supported by the target language. Valid classes are zero, one, two, few, many and other.
Plural classes here are written without the @ prefix. That differs from importing content and from the file content endpoint, where plural forms are @-prefixed to distinguish them from nested keys. No prefix is needed here because the key is already identified in the URL, so its form is known.
If value is missing or null, the request fails with 400 (bad_request).
Sample Request #️⃣
Singular key
curl --request POST \
--url https://api.localazy.com/projects/{projectId}/keys/{keyId}/translations/cs \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"value": "Uložit změny"
}'Plural key
curl --request POST \
--url https://api.localazy.com/projects/{projectId}/keys/{keyId}/translations/cs \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"value": {
"one": "1 položka",
"few": "%d položky",
"other": "%d položek"
}
}'Sample Response #️⃣
{
"result": true,
"versionId": "_a6422547079022246667"
}Response Object
| Field | Required | Description |
|---|---|---|
result |
required | true when the translation was stored. |
versionId |
optional | Id of the translation version that was created. Present when result is true. |
message |
optional | Explains why the value was not applied. Present when result is false. |
Always check result. Some requests are answered with HTTP 200 and result: false — nothing is stored, and no error is raised. This happens when the target is the project’s source language, or when the project is momentarily locked. A resolved request is not by itself proof that the translation was saved.
How the version is applied #️⃣
Whether the submitted value becomes the current (published) version or is filed as a candidate awaiting review depends on the caller’s project role.
| Role | Result |
|---|---|
| Reviewer, manager, owner, trusted translator | The value is set as the current version. |
| Translator | The value is stored as a candidate version to be approved later. |
If the submitted value is identical to an existing version, that version is reused instead of creating a duplicate.
Validation #️⃣
Submitted values are stored as-is. This endpoint does not run the project’s translation checks — placeholder consistency, plural completeness, length limits, or custom rules. Sending well-formed values is the caller’s responsibility.
Source language #️⃣
The project’s source (base) language cannot be edited through this endpoint. A request targeting it returns 200 with result: false and an explanatory message; nothing is stored. To change source content, import it instead.
Language-level permissions #️⃣
When the project uses language-level permissions, a translator assigned to specific languages may submit only for those languages; a request for any other language returns 401 (unauthorized). Managers and owners are not restricted.
While an import is running #️⃣
While a string import is running for the project, translation submissions are temporarily refused with 400 (import_in_progress). Retry once the import finishes.
Error responses #️⃣
| Status | Error | When |
|---|---|---|
400 |
unknown_lang |
{lang} is not a recognised language. |
400 |
bad_request |
The value field is missing. |
400 |
import_in_progress |
A string import is currently running for the project. |
401 |
unauthorized |
The token’s role is too low, the key does not exist in this project, or language-level permissions deny the target language. |


