Create a Translation.io library
(for your own stack)

Translation.io is designed to help developers localize and translate applications that are constantly evolving.

Since we want to offer the best experience to developers, our approach is to create the most integrated library for each stack: Ruby on Rails, Laravel, React & JS, Angular etc. Some of them are officially supported, some are unofficially supported and others are in progress.

— In a nutshell —

Some stacks are not yet fully supported, this page explains the process of creating a library for your stack of choice.

Need help, have a question or found a bug?

Introduction

Only 3 HTTP requests with a JSON body are needed to create a complete Translation.io library:

segments/init: Push existing translations to Translation.io.
segments/sync: Send new keys/strings and get new translations from Translation.io.
source_edits/pull: Get source editions made on Translation.io interface (see here).

segments/init only needs to be called once just after the project configuration (following calls will be denied by the backend). source_edits/pull and segments/sync should ideally be called successively each time the translations are synchronized.

If you create a library for a framework, the command lines should look like this:

task translation:init → calls segments/init

task translation:sync → calls source_edits/pull followed by segments/sync

Authentication

There are three ways to authenticate through Translation API: JSON parameter, URL query parameter and HTTP header.

If several authentications are used at the same time, the priority order is the following:

  • JSON parameter.
  • URL query parameter.
  • HTTP header.

JSON parameter

Add the project API key as api_key parameter in the JSON body of your request.

cURL request
curl -X POST https://translation.io/api/v1/segments/init.json \
  -H 'content-type: application/json' \
  -d '{
        "api_key": "YOUR_API_KEY"
      }'

URL query parameter

Add the project API key as api_key parameter in the request URL:

cURL request
curl -X POST https://translation.io/api/v1/segments/init.json?api_key=YOUR_API_KEY

HTTP header

Add the project API key as x-api-key in the request header.

cURL request
curl -X POST https://translation.io/api/v1/segments/init.json \
  -H 'x-api-key: YOUR_API_KEY'

Errors

Translation.io uses conventional HTTP codes to indicate if a request is successful (2xx) or if it failed (4xx). Errors will be returned with a JSON body warning you about missing params, extra params or erroneous values in params.

errors is an array of strings, so if many errors are triggered at the same time, all of them will be returned in the response.

Example

request (segments/init)
{
  "target_languages": ["nl"],
  "segments": {
    "fr": [],
    "nl": []
  }
}
response
{
  "errors": [
    "Missing param(s): source_language.",
    "'segments' must be a Hash with target_languages as keys and arrays of segments as values."
  ]
}

Segments

segment is the most important model of Translation.io. Each segment corresponds to a single unit of translation from a source language to a target language.

There are two different types of segments: key segments and source segments. Segment types are immutable so an existing key segment can never become a source segment, and vice versa.

As a general rule of thumb, you should use:

  • key segments if you localize in your code using a key: translate("some.custom.key").
  • source segments if you localize in your code using the source text: translate("My source text").

If you have both syntaxes available in your framework, you should use both types at the same time in the HTTP requests.

Key segments

Type for segments that are in the key → translation format in your application. They are usually stored in YAML, JSON, PHP, INI or XML files.

Plural and context information are not part of the key segments. However, depending on the framework conventions, they can sometimes be deducted from the key or a special character in the source text.

They are uniquely identified by their key.

Required parameters

Name Type Description
type string Segment type.
Note: should be "key".
key string Key associated with the text to be translated.
Example: "home.call_to_action.bottom"
source string Source text.
Example: "Click here to subscribe"

Optional parameters

Name Type Description
target string Translated target text.
Example: "Cliquez ici pour vous inscrire"
comment string Comment to help translate this segment.
Example: "Homepage call-to-action (the bottom one)."
references array of strings File(s) where this key is stored or called inside the source code. May provide more context for translators.
Example:  ["config/locales/fr.yml", "app/home/index.html:33"]

Notes

  • Segments are always encapsulated in a specific target language, so the language combination (en → fr in above example) doesn't need to be specified in every segment. See init parameters.

Source segments

Type for segments that are in the source → translation format in your application. They are usually stored in PO (GetText) or XLIFF files that have been specifically designed for translations.

Plural and context information are an integral part of the segments.

They are uniquely identified by the combination of context, source and source_plural.

Required parameters

Name Type Description
type string Segment type.
Note: should be "source".
source string Source text.
Example: "product in the cart"

Optional parameters

Name Type Description
target string Translated target text.
Example: "article dans le panier"
source_plural string Plural form of source text.
Note: only if segment is plural.
Example: "products in the cart"
target_plural string Plural form of target text.
Note: only if segment is plural.
Example: "articles dans le panier"
target_plural_2 string Second plural form of target text.
Note: only if segment is plural and 2 plural forms or more. See list of languages.
target_plural_3 string Third plural form of target text.
Note: only if segment is plural and has 4 plural forms or more (target included). See list of languages.
target_plural_4 string Fourth plural form of target text.
Note: only if segment is plural and has 5 plural forms or more (target included). See list of languages.
target_plural_5 string Fifth plural form of target text.
Note: only if segment is plural and has 6 plural forms or more (target included). See list of languages.
context string Used to differentiate 2 segments that have the same source but need different translations because of their context.
Note: "orange" with context="fruit" and "orange" with context="color" should coexist and have different translations.
comment string Comment to help translate this segment.
Example: "Order summary that is displayed next to the cart."
references array of strings File(s) where this segment is stored or where the segment is used inside the source code. May provide more context for translators.
Example:  ["gettext/fr/app.po", "app/home/index.html:33"]

Notes

  • Segments are always encapsulated in a specific target language, so the language combination (en → fr in above example) doesn't need to be specified in every segment. See init parameters.

Initialization

Populate a new Translation.io project by pushing all source and translated text into the backend. This call should only be executed one time per project.

Translation init schema

Endpoint

POST https://translation.io/api/v1/segments/init(.json)

Parameters

Name Type Description
source_language string Source language code (from here).
Example: "en"
target_languages array Array of target language codes (from here).
Example: ["fr", "es"]
segments hash Hash with the language codes as keys and an array of segments as value.
Example: see below.
Note: keys must match target_languages parameter.

Response

Name Type Description
project hash Project name and URL.
Note: should be displayed back to the user in the console.
Example:
{
  "name": "project_name",
  "url": "https://translation.io/owner_name/project_name"
}
segments hash Hash with the language codes as keys and an array of segments as value.
Example: see below.
Note: keys must match target_languages parameter.

Example

request
{
  "source_language": "en",
  "target_languages": ["fr", "es"],
  "segments": {
    "fr": [segment_1_fr, segment_2_fr, ...],
    "es": [segment_1_es, segment_2_es, ...]
  }
}

The segments could be translated or not, and look like this:

segment_1_fr Translated French segment of type "key"
{
  "type": "key",
  "key": "goodbye.message",
  "source": "Goodbye world",
  "target": "Au revoir le monde"
}
segment_1_es Translated Spanish segment of type "key"
{
  "type": "key",
  "key": "goodbye.message",
  "source": "Goodbye world",
  "target": "Adios al mundo"
}
segment_2_fr Translated French segment of type "source"
{
  "type": "source",
  "source": "Hello world",
  "target": "Bonjour le monde"
}
segment_2_es Untranslated Spanish segment of type "source" | "target" key is optional when empty
{
  "type": "source",
  "source": "Hello world",
  "target": ""
}

The response from Translation.io would be:

response
{
  "project": {
    "name": "project_name",
    "url" : "https://translation.io/owner_name/project_name"
  },
  "segments": {
    "fr": [segment_1_fr, segment_2_fr, ...],
    "es": [segment_1_es, segment_2_es, ...]
  }
}

In this case, segment_1_fr, segment_2_fr, segment_1_es and segment_2_es are the same as above.

For some specific stacks, they may have been pre-translated by Translation.io (see here).

Synchronization

Synchronize your current branch with Translation.io by pushing all source text and receiving new translations from Translation.io. If a new source text is found in the application, it will be added to Translation.io

Translation sync schema

Endpoint

POST https://translation.io/api/v1/segments/sync(.json)

Parameters

Name Type Description
source_language string Source language code (from here).
Example: "en"
target_languages array Array of target language codes (from here).
Example: ["fr", "es"]
segments array Array of segments without translations (no target parameter).
readonly optional boolean If true, synchronize and receive new segments translations from Translation.io, but don't create or update segments on Translation.io interface (it skips steps 2, 3 and 4 from above schema).
Note: Useful if you want to synchronize faster in your CI/CD pipeline. It is also the only way to execute this call concurrently (we use a mutex if readonly is false).
Default: false
purge optional boolean If true, remove unused segments from Translation.io, using segments as reference.
Note: You need it if you want to remove segments from Translation.io that are not anymore in the current state of your application. Make sure to merge your active branches before you purge because it uses the current branch of the application as reference (segments parameter).
Important: Synchronize with purge = false first to be sure the returned unused_segment_ids are really the segments you want to remove from Translation.io.
Default: false

Response

Name Type Description
project hash Project name and URL.
Note: should be displayed back to the user in the console.
Example:
{
  "name": "project_name",
  "url": "https://translation.io/owner_name/project_name"
}
segments hash Hash with the language codes as keys and an array of segments as value.
Example: see below.
Note: keys must match target_languages parameter.
unused_segment_ids array Array of segment identifiers that exist on Translation.io but are not present on the request segment parameter. They are the segments that will be removed from Translation.io if the same request is sent with the purge parameter.

Example

request
{
  "source_language": "en",
  "target_languages": ["fr", "es"],
  "segments": [segment_1, segment_2, ...]
}

Where segments only contain the source (no translation!), and look like this:

segment_1 Segment of type "key"
{
  "type": "key",
  "key": "goodbye.message",
  "source": "Goodbye world"
}
segment_2 Segment of type "source"
{
  "type": "source",
  "source": "Hello world"
}

The response will return the corresponding translated segments for each target language.

response
{
  "project": {
    "name": "project_name",
    "url" : "https://translation.io/owner_name/project_name"
  },
  "segments": {
    "fr": [segment_1_fr, segment_2_fr, ...],
    "es": [segment_1_es, segment_2_es, ...]
  },
  "unused_segment_ids": []
}

Note: an empty unused_segment_ids assumes that every segment from Translation.io is listed on the request.

If everything is translated on Translation.io, the segments in the response would be the following:

segment_1_fr Translated French segment of type "key"
{
  "type": "key",
  "key": "goodbye.message",
  "source": "Goodbye world",
  "target": "Au revoir le monde"
}
segment_1_es Translated Spanish segment of type "key"
{
  "type": "key",
  "key": "goodbye.message",
  "source": "Goodbye world",
  "target": "Adios al mundo"
}
segment_2_fr Translated French segment of type "source"
{
  "type": "source",
  "source": "Hello world",
  "target": "Bonjour le monde"
}
segment_2_es Translated Spanish segment of type "source"
{
  "type": "source",
  "source": "Hello world",
  "target": "Hola mundo"
}

Source Editions

Update your code with the latest source editions that have been made on the Translation.io interface (more info here and here).

This step is only needed for key segments. If you only want to manage source segments, you can safely ignore this HTTP call.

Always call this endpoint before synchronization to always be up to date with the latest source editions.

Translation source-edits schema

Endpoint

GET https://translation.io/api/v1/source_edits/pull(.json)

Parameters

Name Type Description
timestamp integer Timestamp (Unix Time) returned by the previous call (or 0 if it's the first call).
Note: Some HTTP libraries don't work well when GET contains a JSON body, so timestamp is also accepted as a HTTP query parameter.
Example: 1733137891

Response

Name Type Description
project hash Project name and URL.
Note: should be displayed back to the user in the console.
Example:
{
  "name": "project_name",
  "url": "https://translation.io/owner_name/project_name"
}
source_edits array List of source editions created between timestamp parameter and now.
Note: Sorted by ascending creation date.
Example: see below.
timestamp integer Updated timestamp (Unix Time) to save at the application level (ex: in a .translation_io file). This timestamp should be used for the next call.
Note: .translation_io file should be added to the code respository and will coevolve with each branch of the code.

Notes

  • This endpoint is "read-only", it will not trigger any change on the backend.

Example

Let's assume the following source editions have been made in the project:

# Old source New source Key Edition timestamp
1 Your login Your username user.subscription.login 1700000000
2023-11-14 23:13:20
2 Hi everybody Hello everybody home.welcome.intro 1720000000
2024-07-03 11:46:40
3 Term of service Terms of service footer.legal 1730000000
2024-10-27 04:33:20

If the project timestamp stored in .translation_io is 1710000000, then the request should be:

request
{
  "timestamp": 1710000000
}

The response will only contain source editions #2 and #3. Source edition #1 was created before the timestamp from the request and should already have been updated in the project.

response
{
  "project": {
    "name": "project_name",
    "url" : "https://translation.io/owner_name/project_name"
  },
  "source_edits": [
    {
      "key": "home.welcome.intro",
      "old_source": "Hi everybody",
      "new_source": "Hello everybody",
      "created_at": 1720000000
    },
    {
      "key": "footer.legal",
      "old_source": "Term of service",
      "new_source": "Terms of service",
      "created_at": 1730000000
    }
  ],
  "timestamp": 1733145091
}

Need help or have a question?