Software Localization Projects in Smartcat
In addition to regular document-based projects, Smartcat offers a different way of managing keys (strings) that is more suitable for software localization projects.
Key Benefits
- Software keys (strings) are managed on the platform (Smartcat becomes the source of truth for all of your software copy)
- UX writers and product managers change the copy by themselves, without distracting developers
- Developers act as content consumers by exporting the needed subset of keys in a format of their choice
- Developers can import source strings and translations in various developer file formats, and export translations in various file formats as well
- REST API and CLI offer easy integration with CI/CD pipelines
Workflow
Here is a typical workflow for a software localization process:
- Create collections that will contain keys with unique identifiers
- Import keys via API into an existing or new collection (JSON, YAML, iOS Strings, Android XML and LocJSON). You can do this in the beginning only to populate the initial project data.
- Keys with ICU MessageFormat syntax can be converted to individual segments with plural forms or imported as is
- You can add labels to all imported segments
- Create or modify keys (segment source and identifiers) inside the CAT editor
- You can create new keys with plural forms right in the editor
- You can add labels to segments in the editor
- Upload screenshots or provide additional context information for segments right from the editor
- Translate content, assign suppliers using tasks as with usual projects
- Export keys via API or UI from the Editor (JSON, YAML, iOS Strings, Android XML). Plural forms will be converted to ICU MessageFormat syntax
Supported Import File Formats
- JSON
- YAML
- Android XML
- iOS Strings
- LocJSON (see below)
LocJSON is a JSON-based file format that Smartcat uses for integration purposes. It is extendable, and allows external integrations to pass a list of units (keys + source text + optional translations), and associate metadata with each unit, like comments or maximum string length per each unit. Smartcat will automatically identify this format by file extension, .locjson
.
See LocJSON file format reference for more information →
Supported Export File Formats
- JSON (flat or structured)
- YAML (flat or structured)
- Android XML
- iOS Strings
Creating a Software Localization Project
On the home page, click on the Create software localization project option.
Enter project name, e.g. My App, and specify one source language and a list of target languages, and press Create project.
Once the project is created, you will see a project Overview page. A default collection called main will be created and selected automatically.
Importing and Exporting Keys
Smartcat supports the following ways to import your existing keys from various file formats:
- Using Smartcat CLI
- Using our public API (and standard tools like curl)
- Directly through Smartcat UI.
Similarly, the same methods are support for exporting:
- Using Smartcat CLI
- Using our public API (and standard tools like curl)
- Directly through Smartcat UI.
Using CLI
Smarcat CLI (command-line interface) is a tool available for all popular platforms (Windows, MacOS, Linux) that you can run from command line (console) and from CI/CD scripts to perform certain actions automatically. Read more about the CLI here: Smartcat CLI.
Per-Folder Configuration File
As a matter of convenience, you can create a file called .smartcat
in the folder you will be runnung Smartcat CLI from. In this file you can put information about your Smartcat server, workspace, project, and API key (all fields are optional).
Example file
{
"Server": "https://smartcat.com",
"Workspace": "fd104ef5-cbe7-1459-c8ac-237d99a3c614",
"Project": "446dfcf0-e699-4c91-a7ee-40e1237a9f81",
"ApiToken": "1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
Once you do so, this information will override your user settings.
Such a configuration file will allow you to skip specifying --project xxxxxxxx
in every CLI command invocation.
Import
smartcat import en/strings.json --language en --label android
Importing keys is done with the smartcat import
command. This example shows the actual project identifier, and you can use it as a starting point. If you have a file called en/strings.json (paths can be relative to your current directory), then the following command will import all the keys from that JSON file into your newly created project into the main collection (which is the default collection name), while also giving the android label to all imported keys.
smartcat import zh-Hans/strings.json --language zh-Hans
Similarly, you can import translations from an existing file that has the same keys:
Export
Exporting is performed through smartcat export
command. The following example will export specified target languages and give them file names as defined in the output template.
smartcat export --languages es,zh-Hans --output-file-path-template 'strings-{LANGUAGE}.json'
Using API
Please find all the API methods for the import/export key feature in the Postman collection below.
Postman Collection with API Examples
For your convenience, we have created a Postman collection of API requests that you can easily experiment with:
V2 Software localization workflow.postman_collection.json
Before using the examples, you need to update values for several variables using in this collection:
- accountID can be obtained from your Smartcat workspace (see Settings > API)
- apiToken can be generated on the same Settings > API page
- apiServer is one of the servers your workspace is located on (you can look up the domain you see when working with your workspace). It can be one of the following:
- smartcat.com (Europe)
- us.smartcat.com (USA)
- ea.smartcat.com (Asia)
- projectID is the ID of the project you will be running import/export against. Once you create a project, it’s URL will be something like https://smartcat.com/projects/6c58e1f5-61c6-43dc-9b83-8d635edbd50c/overview. Here, 6c58e1f5-61c6-43dc-9b83-8d635edbd50c is the project ID.
Step 1. Use the import API call (see the provided Postman example called Import keys) to import the following document into a newly created project:
This will automatically create a collection called main in that project.
Step 2. Open the Files tab in your project, where you will see main collection. Click on its name to open in the editor. Here you can add new keys, and edit or delete existing ones.
Step 3. Import one of these files using the same import API call to add or update keys (this way you will merge changes from those files into your collection of keys):
incremental_add_one_key.locjson
incremental_update_one_key.locjson
Step 4. Export translated keys back. Export is a two-step process:
- Export request (see the provided Export keys Postman example). Here you specify the needed set of languages and the output file format. This request returns the ID of the asynchronous export task, which will be automatically captured by the Postman automation script.
- Download request (see the provided Download export results Postman example). This will return the contents of your file. If you request just one language, the document will be returned as is in the response body. If you request multiple documents, you will get a ZIP file with multiple files inside.
API Reference
Import
Code samples
POST /api/integration/v2/project/{projectId}/import` HTTP/1.1
Content-Type: multipart/form-data
Accept: text/plain
POST /api/integration/v2/project/{projectId}/import
Starts async import multiple files to given project and branch. The body consists of a number of parts with the following headers:
Content-Disposition: form-data; name="file"; filename="path/to/file"
Content-Type: text/plain
Parameters
Name | In | Type | Required | Description |
---|---|---|---|---|
projectId | path | string(uuid) | true | Project identifier |
collection | query | string | false | Target collection (optional, "main" as default) |
language | query | string | false | Language of the imported files |
target-languages | query | string | false | Comma separated list of target languages |
format | query | string | false | Specifies the file format used to import the file (optional). |
completion-state | query | string | false | Imported translation confirmation mode |
labels | query | string | false | Comma-separated labels that will be attached to the created/updated segments (even if the text is not changed) |
path-separator | query | string | false | Path separator string (optional) |
skip-conflicting-values | query | boolean | false | Specifies how to deal with situations when the same key has a different |
overwrite-conflicting-values | query | boolean | false | When the same key has a different value in the imported file and in Smartcat - use the value from the file |
auto-file-labels | query | boolean | false | Should Smartcat automatically create labels after file names? |
delete-missing-keys | query | boolean | false | Delete keys that are not present in the imported files |
body | body | UploadedFile | true | Files for import |
Detailed descriptions:
format
— specifies the file format used to import the file. Smartcat will try to guess the file format from its extension:
json
— flat key-value formatstructured-json
— tree-like format; see also:path-separator
yaml
— flat key-value formatstructured-yaml
— tree-like format; see also:path-separator
ios-strings
— iOS .strings resource file formatandroid-xml
— Android XML resource file format
path-separator
— path separator string, used to construct keys for nested JSON objects (defaults to “/”). Consider the following example JSON file - when the “value” string will be imported, it’s key name will be “object/my-key”.
target-languages: Comma separated list of target languages (optional, all target languages of the project by default, can only be specified when importing the source).
- Empty list of languages produces a 400 bad request error with an appropriate reason text
- An incorrect language code produces a 400 bad request error with an appropriate reason text
- If any language didn't exist in the project, it will be created (but not added as a target to any existing collections)
- If any language didn't exist in the collection (the target collection existed before), it will be added as a target to the collection
completion-state: Imported translation confirmation mode
- draft - no confirmation
- intermediate - confitm on the first project stage
- final - confirm on all project stages
Example JSON file
{
"object": {
"my-key": "My value"
}
}
Responses
Status | Meaning | Description | Schema |
---|---|---|---|
200 | OK | Request has been successfully completed | Response with the import ID |
400 | Bad Request | See the detailed description below | None |
403 | Forbidden | See the detailed description below | None |
Detailed descriptions
HTTP 400 returns if:
Required 'language' parameter missing
The input (request body) contains no files
'skip-conflicting-values' and 'overwrite-conflicting-values' parameters are specified at the same time. Choose one option
Passed language is completely unrecognizable by Smartcat
Passed language is neither a source language nor one of target languages
The 'format' value is invalid. Allowed values are: 'json', 'yaml', 'ios-strings', 'android-xml', 'locjson'.`
The 'path-separator' parameter is specified for any file format other than 'json' or 'yaml'
HTTP 403 returns if:
The requested project does not belong to the authenticated account
Trying to import into a non-developer project
Trying trying to import into a personal account
Get Import Result
GET api/v1/project/import-result/{importId}` HTTP/1.1
Accept: text/plain
GET api/v1/project/import-result/{importId}
Returns current import status if the import task exists.
Result model
{
"status": "pending" | "inprogress" | "completed" | "failed",
"errors": { "error": "string", "fileName": "string" }[],
"keysCreated": 0,
"keysUpdated": 0,
"keyValuesNotChanged": 0,
"keysWithoutSource": 0,
"conflictingKeyValues": {
"key1": ["valueA", "valueB"],
"key2": ["valueC"],
}
}
Responses
Status | Meaning | Description | Schema |
---|---|---|---|
200 | OK | Request has been successfully completed | Returns current import status |
404 | Not Found | The export ID doesn't exist | None |
Export
POST /api/integration/v2/project/{projectId}/export` HTTP/1.1
Content-Type: multipart/form-data
Accept: text/plain
POST /api/integration/v2/project/{projectId}/export
Starts async export multiple files to given project and branch. Returns HTTP 200 with export ID if export has started.
Parameters
Name | In | Type | Required | Description |
---|---|---|---|---|
languages | query | string | false | Comma-separated list of languages to export (allow multiple, all target languages as default) |
collections | query | string | false | Export from one collection (main as default) |
path-separator | query | string | false | Path separator string, used to reconstruct nested JSON objects (defaults to “/”) |
completion-state | query | string | false | Minimal key completion state (final by default) |
fallback-to-default-language | query | string | false | Incomplete translations: download segments that passed through all translation stages (default) |
export-incomplete-as-blank | query | string | false | Incomplete translations: export blank values when no translation is ready |
skip-incomplete-keys | query | string | false | Incomplete translations: do not export keys that have no translations (will be used as a default for "android-xml" export file type) |
format | query | string | false | Export format (json by default) |
include-default-language | query | string | false | Should the default language be included in the export? |
output-file-path-template | query | string | false | output file path template |
zip | query | string | false | Force export in a ZIP archive, even when downloading a single file |
modified-since | query | string(date-time) | false | Export keys that were changed after the datetime |
labels | query | string | false | Comma-separated list of labels to export keys that are marked with labels |
Detailed descriptions
path-separator
— path separator string, used to reconstruct nested JSON objects (defaults to “/”). If there’s a key “object/my-key” with the value of “My value”, then exporting a structured JSON file would give the result you can see to the right.
Structured JSON file export result
{
"object": {
"key": "value"
}
}
completion-state
— minimal key completion state (final
by default):
final
— download segments that passed through all translation stages (default)intermediate
— download segments at the last confirmed stagedraft
— download any translations, even unconfirmed ones
What to do with incomplete translations:
fallback-to-default-language
— return default language values instead of translations (default)export-incomplete-as-blank
— export blank values when no translation is readyskip-incomplete-keys
— do not export keys that have no translations (will be used as a default for "android-xml" export file type)
format
— export format (json
by default):
json
— flat key-value format (default)structured-json
— tree-like format; see also:path-separator
yaml
— flat key-value formatstructured-yaml
— tree-like format; see also:path-separator
ios-strings
— iOS .strings resource file formatandroid-xml
— Android XML resource file format
Responses
Status | Meaning | Description | Schema |
---|---|---|---|
200 | OK | Request has been successfully completed | Returns export ID |
400 | Bad Request | See detailed description below | None |
403 | Forbidden | The requested project does not exist im the authenticated account | None |
Detailed descriptions
Returns HTTP 400 if:
Required 'language' parameter missing
The 'path-separator' parameter can be specified only for any formats other than 'structured-json' or 'structured-yaml'
Passed language is completely unrecognizable by Smartcat
Passed language is neither a source language nor one of target languages
Any passed label is empty
The 'completion-state' value is invalid. Allowed values are: 'final', 'intermediate', 'draft'.
The 'format' value is invalid. Allowed values are: 'json', 'structured-json', 'yaml', 'structured-yaml', 'ios-strings', 'android-xml'.
'fallback-to-default-language', 'export-incomplete-as-blank' or 'skip-incomplete-keys' are specified at the same time. Choose one option.
File path template
output-file-path-template
- Output file path template.
Specifies how the output files should be named and located. You can use the {LANGUAGE} and {LABEL:PREFIX} placeholders to customize the output.
The ability to specify {LABEL:PREFIX} placeholder allows you to export keys that have the PREFIX value of label prefix and use the label suffix to determine the file name.
For example:
Segment A has a label file:main.json
Segment B has a label file:errors.json
Specifying "resources/{LABEL:file}" as the path template and JSON as the export format would result in a ZIP file with the following structure:
resources/
main.json -> this file contains segment A
errors.json -> this file contains segment B
Defaults:
strings-{LANGUAGE}.json
for "json" file formatstrings-{LANGUAGE}.yaml
for "yaml" file format{LOCALE:IOS}.lproj/values.strings
for "ios-strings" file formatsrc/main/res/values-{LOCALE:ANDROID}/strings.xml
for "android-xml" file format
Get Export Result
GET /api/integration/v1/document/export/{exportId}` HTTP/1.1
Accept: text/plain
GET /api/integration/v1/document/export/{exportId}
Returns export result file.
Responses
Status | Meaning | Description | Schema |
---|---|---|---|
200 | OK | Request has been successfully completed | Returns export result file — single file if export started with one target language, zip archive otherwise |
204 | No Content | Export is not available yet | None |
Add New Target Languages
POST /api/integration/v1/project/{projectId}/software-localization/targets` HTTP/1.1
Accept: text/plain
POST /api/integration/v1/project/{projectId}/software-localization/targets
Adds target langauges to the software localization project. If any of the specified target languages doesn't exist in the project, it will be created, but not added as a target to any existing collections. If any of the specified languages doesn't exist in the collection (the target collection existed before), it will be added as a target to the collection.
Parameters
Name | In | Type | Required | Description |
---|---|---|---|---|
target-languages | query | string | true | Comma-separated list of target languages to add. See the list of language codes here. |
Status | Meaning | Description | Schema |
---|---|---|---|
200 | OK | Request has been successfully completed | None |
400 | Bad Request | Bad request | None |
Detailed descriptions
Returns HTTP 400 if:
- The list of languages is empty
- Any one of the language codes is incorrect
Importing/Exporting Using curl
As Smartcat offers similar import/export functionality via its REST API (more on that below), you can also use curl
or equivalent tools readily available in your operating system, to do basic automation tasks without installing Smartcat CLI. This may be a preferred option in organizations that have strict security requirements.
Below is an example of a Shell script that uses curl and zip to export keys from Smartcat:
#!/bin/sh
auth="Authorization: Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
task=$(curl --silent --location --request POST 'https://smartcat.com/api/integration/v1/project/446dfcf0-e699-4c91-a7ee-40e1237a9/export' \
--header "$auth" --header 'Content-Type: application/json' --data-raw '{
"languages": ["es", "zh-Hans"]
}' | tr -d '"')
echo "Export task ID: $task"
sleep 2 # wait till export is done
curl --silent --location --request GET "https://smartcat.com/api/integration/v1/document/export/"$task --header "$auth" -o product-a.zip
unzip product-a.zip
Plural Support
Smartcat supports two way of handling plurals:
- Natively (as independent segments in the editor)
- Via ICU MessageFormat syntax
When you open a collection of keys in the editor, you can add new keys, and when you do so, specify if the key needs to be created with all plural forms. When exporting keys, plural forms will be converted into an ICU MessageFormat-compatible string.
When importing a LocJSON file, you can specify if keys containing ICU MessageFormat syntax should be parsed and converted into individual segments in Smartcat, or kept as is (so that you can edit the raw string.
In case of raw ICU MessageFormat strings, you can plug in an interactive previewer/validator for this format.