In this article you will learn what is an API and how to use Lokalise API to define custom workflows and create automation scripts with ease. First we will cover some theory and then proceed to practice and discuss typical examples. To follow this article you don’t need to be a professional developer but having at least a basic programming knowledge is very much recommended.
You might also be interested in checking the second part of this article where we’re discussing APIv2 use cases and see it in action.
So, what’s an API?
I’m glad you asked! API is an acronym that means “application programming interface”. Generally speaking, API allows third-party services to access company data and manage them as needed. This feature can be used by company’s partners or customers, and it allows to establish communication between services. What’s more, third-party developers do not need to know how the API was actually implemented on the company’s side: they just send a properly formed request according to the documentation to achieve the desired result.
If this explanation sounds too broad and technical, let’s approach it from a different perspective. Suppose you are working with a todo web application that allows to create cards, change their statuses, add assignee, delete these cards, and so on. This application provides a graphical user interface and you can perform all these actions with your mouse by clicking and moving things around — that’s what most of the users would do. But what if we wanted to automate the card creation process? For example, you might want to implement the following scenario: when someone has written a new blog post on your own website, a new todo card has to be created. This card should be named “Review blog post X” and it should contain a link to the newly added post. That’s where the API steps in.
If your todo service provides an API then you can write a small script on your website. Whenever a post is created, this script should send a simple request to the todo service:
curl --request POST \ --url https://todoservice.com/api/cards \ --data '{"name":"Review blog post X","body":"Link to the post: your.blog.com/posts/blog-post-x"}'
The service will then process this request and create a new card for you!
So, effectively an API is a tool to perform various actions by writing code, not by clicking your mouse around.
How does the API work?
A typical API flow is quite simple:
- A third-party application sends an API request. This request usually contains some data: for example, a card name and a description. Also, in most cases the request should contain a special API token that identifies the user on whose behalf the request is made. If the corresponding user does not have enough permissions or the token is invalid, the request is rejected. A token acts as a user password therefore it must be kept secure.
- The service receives a request and checks its validity. If the data is properly formed and the API token is correct then the requested operation is executed.
- Then the service sends a response back to the third-party application. Usually the response contains the status code (indicating whether the requested operation has succeeded or not) and the affected data.
- The third-party application receives a response and does something about it: for example, adds a new entry to the event log.
That’s basically it. Note that with the help of API you can not only create but also read, update, and delete resources as needed (of course, if the service actually supports these actions).
Meet Lokalise API!
Now that you know the API basics, let’s proceed to the meat of this post. Lokalise API version 2 provides a rich interface allowing customers to view and manage the following resources:
- Branches
- Comments
- Contributors
- Translation files
- Keys
- Languages
- Orders
- Payment cards
- Projects
- Queued processes
- Screenshots
- Snapshots
- Tasks
- Teams
- Team users
- Team user groups
- Translations
- Translation providers
- Custom translation statuses
- Webhooks
Not bad, eh? You can find the API docs at developers.lokalise.com/reference/lokalise-rest-api. To access the Lokalise API you can send a simple HTTP request by using tools like cURL. However, we’ve also crafted a few API interfaces for different programming languages to make your life easier:
- PHP client
- Ruby interface
- NodeJS client
- Go client
- Python interface
- Elixir interface
- Finally, you can also employ our command line interface tool which also communicates with the API
Additional notes
- An API token must be sent on every API request. Provide it inside the
X-Api-Token
request header (see below for examples). - Some resources are paginated: specifically, the ones returned by the “list” methods (list all projects, all contributors, all translation keys etc). Paginated resources support two common GET parameters:
page
andlimit
. The defaultpage
value is1
. The defaultlimit
value is100
, and the maximum is5000
. - Access to all endpoints is limited to 6 requests per second. This limit is applied per API token and per IP address. If you exceed the limit, a 429 HTTP status code will be returned.
- Only one concurrent request per token is allowed. To ensure data consistency, it is not recommended to access the same project simultaneously using multiple tokens.
- If you are using a project branching feature in Lokalise, simply add branch name separated by semicolon to the project ID in any endpoint to access the branch, i.e.
3002780358964f9bab5a92.87762498:feature/new-release
. - If the request is malformed or cannot be processed, the API will return one of the errors listed in the docs.
Getting started with Lokalise API
To get started with our API, you’ll need a Lokalise account. Obvious, isn’t it? If you don’t have one, grab your free 14-days trial by visiting app.lokalise.com/signup — no credit card is required!
Next, you’ll need to generate an API token. As you already know, a token acts as a password and it will allow to Lokalise to identify who has sent a request. It means that the token must be kept secure at all times: never publicly expose it, do not add it to your version control, and do not share it with anyone else. If the token was exposed, immediately revoke it because otherwise anyone will be able to perform any actions on your behalf!
To generate a new token, proceed to Lokalise, login to the system and click on the avatar in the bottom left corner. Choose Personal profile from the menu:
Next, choose API tokens from the left menu:
On the next page click Generate new token. You’ll see the following dialog:
Choose what type of token would you like to generate: read-only (you’ll be able to view data but not manage them) or read/write (you’ll be able to view and manage data).
After generating a token you’ll be able to copy it:
To revoke a token, simply click Delete token.
Now that you have a token, it’s possible to communicate with the Lokalise API and perform any operations you’d like! Don’t forget, however, that some operations require certain access rights. For example, only team admins, billers, and owners are able to create new projects and translation orders.
For instance, to create a new project you could send the following cURL request:
curl --request POST \ --url https://api.lokalise.com/api2/projects \ --header 'content-type: application/json' \ --header 'x-api-token: YOUR_API_TOKEN_HERE' \ --data '{"name":"TheApp Project","description":"iOS + Android strings of TheApp. https://theapp.com","languages":[{"lang_iso":"en","custom_iso":"en-us"},{"lang_iso":"en_GB","custom_iso":"en-gb"}],"base_lang_iso":"en-us"}'
Lokalise API: Examples
Now let’s take a look at some usage examples of the Lokalise API. These examples will be written in two languages: TypeScript and Ruby. I’ll utilize the corresponding API clients as well.
To get started with the NodeJS client which can be used for TS and JS projects, you’ll need to install NodeJS itself along with npm. Next, run the following command in your terminal:
npm install @lokalise/node-api
Then inside your script add the following lines of code:
const { LokaliseApi } = require('@lokalise/node-api'); const lokaliseApi = new LokaliseApi({ apiKey: '<apiKey>'});
Insert your API key, and that’s it! The lokaliseAPI
object can now be used to send API requests.
To start working with the Ruby interface, you’ll need a Ruby interpreter and a RubyGems subsystem. Next, run:
gem install ruby-lokalise-api
Add the following lines to your code:
require 'ruby_lokalise_api' @client = RubyLokaliseApi.client 'YOUR_TOKEN_HERE'
Provide your API token and use the @client
object to send requests.
Creating translation projects
To create a new translation project you must provide at least one attribute: project name. Also, it’s possible to specify the team id to create the project at (by default the current team of the user will be utilized), project base language, and other parameters.
Here’s a TS sample:
const project = await lokaliseApi.projects().create({ name: "Node.js test", description: "Test description", }); project.project_id // => "123.abc" project.name // => "Node.js test"
A Ruby sample:
@client.create_project name: 'Ruby project', description: 'Demo project' project.name # => 'Ruby project' project.description # => 'Demo project'
You may also be interested in checking out this video tutorial which shows more complex examples with Ruby and Rails:
Uploading translation files
In order to upload a translation file, you’ll have to provide at least the following data:
- Project ID
- Base64-encoded file with the one of the supported formats
- Filename
- Language code of the translations in the file you are importing
It’s important to mention that the file uploading process is always queued and performed in the background. Therefore, the API will return the background process id and it may take some time for this process to complete. You can check the process status by sending its ID to the API.
Here’s an TS example:
const data = "ewogICAgImZydWl0IjogIkFwcGxlIiwKICAgICJzaXplIjogIkxhcmdlIiwKICAgICJjb2xvciI6ICJSZWQiCn0=" // your file contents const project_id = "123.abc" const process = await lokaliseApi.files().upload(project_id, { data: data, filename: "test_async.json", lang_iso: "en", }) process.process_id // => "123456" process.type // => "file-import" process.status // => "queued"
Now you can periodically check the status of the process. Once it changes to “finished”, the file was uploaded successfully:
const process = await lokaliseApi.queuedProcesses.get(process.process_id, { project_id: project_id, }) process.status // => "finished"
A Ruby sample:
project_id = "123.abc" @client.upload_file project_id, data: 'ZnI6DQogIHRlc3Q6IHRyYW5zbGF0aW9u', filename: 'ruby.yml', lang_iso: 'ru' process.status # => 'queued' # ... reloaded_process = process.reload_data # => reload information about the process to check whether it has finished reloaded_process.status # => 'finished'
Downloading translation files
To download your translations in a bundle, you’ll need to specify at least the project ID and the file format but many other parameters are available as well.
Here’s a TS sample:
const response = await lokaliseApi.files().download("123.abc", { format: "json", original_filenames: true, }) response.bundle_url // => https://s3-eu-west-1.amazonaws.com/lokalise-assets/files/export/123.abc/c65/My_Project.zip
A Ruby sample:
response = @client.download_files "123.abc", format: 'json', original_filenames: true response['bundle_url'] # => https://s3-eu-west-1.amazonaws.com/lokalise-assets/files/export/123.abc/c65/My_Project.zip
Creating translation orders
Creating a translation order is a bit more involved operation because it requires you to specify:
- Project ID
- Team ID
- Payment card ID — required only if you have set the payment method to
credit_card
(which is the default value). - Order briefing
- Source language code of the order
- List of the target languages
- List of keys identifiers to include in the order
- Translation provider slug. To get a list of all supported translation provides you can use the corresponding API endpoint.
- Tier of the translation. Tiers depend on the chosen provider.
TS code sample:
const order = await lokaliseApi.orders().create( { project_id: "123.abc", card_id: "1774", briefing: "Informal and friendly tone", source_language_iso: "en", target_language_isos: ["nl", "fr"], keys: [1234, 5678, 0987, 6543], provider_slug: "gengo", translation_tier: "1", }, { team_id: 1469 } ); order.status // => "in progress"
A Ruby sample:
order = @client.create_order "1469", # => this is your team id project_id: "123.abc", card_id: 12345, briefing: 'Friendly tone', source_language_iso: 'en', target_language_isos: [ 'ru', 'fr' ], keys: [ 1234, 5678, 4531 ], provider_slug: 'gengo', translation_tier: '1' order.status # => 'in progress'
Listing project tasks
To list all project tasks, you’ll need to specify the project ID you’re interested in. As long as this resources is paginated, you can also provide the page
and limit
parameters.
Here’s the TS code sample:
const tasks = await lokaliseApi.tasks().list({ project_id: "123.abc", page: 2, limit: 5, }); tasks.items[0].task_id // => 10001 tasks.totalResults // => 15 tasks.totalPages // => 3 tasks.resultsPerPage // => 5 tasks.currentPage // => 2
A Ruby sample:
tasks = @client.tasks "123.abc", limit: 2, page: 2 tasks.collection.first.title # => "Translate English" tasks.total_results # => 3 tasks.total_pages # => 2 tasks.results_per_page # => 2 tasks.current_page # => 2
Creating tasks
To create a new task, provide at least the following data:
- Project ID
- Task title
- List of languages in the task
- List of keys identifiers to include in the task — required if the task has no parent
TS code sample:
const task = await lokaliseApi.tasks().create( { title: "Translate English", keys: [1234, 5678, 0145], languages: [ { language_iso: "en", users: [123, 345, 678], // => an array of task assignee }, ], }, { project_id: "123.abc" } ); task.title // => "Translate English" task.languages[0].language_iso // => "en"
A Ruby sample:
task = @client.create_task "123.abc", title: 'Translate Russian', keys: [1234, 5678, 9123], languages: [ { language_iso: 'ru', users: ['123, 567'] } ] task.title # => 'Translate Russian' task.languages.first['language_iso'] # => 'ru
Adding project contributors
To invite one or more contributors, provide the following info:
- Project ID
- Contributor e-mail
- List of languages accessible to the user — required only if the user is not an admin
Here’s the TS code sample:
const contributors = await lokaliseApi.contributors().create( [ { email: "translator@mycompany.com", fullname: "Mr. Translator", is_admin: false, is_reviewer: true, languages: [ { lang_iso: "en", is_writable: false, }, { lang_iso: "ru", is_writable: true, }, ], }, ], { project_id: "123.abc" } ); contributors[0].email // => "translator@mycompany.com" contributors[0].user_id // => 12345
A Ruby sample:
contributors = @client.create_contributors "123.abc", email: 'sample@example.com', fullname: 'Mr. Translator', languages: [{ lang_iso: 'en' }, { lang_iso: 'ru' }] contributors = contributor.collection.first contributor.fullname # => 'Mr. Translator' contributor.email # => 'sample@example.com' contributor.languages[1]['lang_iso'] # => 'ru
Updating project contributor
To update an existing contributor, you’ll need to provide at least his/her ID and the project ID.
Here’s the TS code sample:
const contributor = await lokaliseApi.contributors().update( "12345", { is_admin: true }, { project_id: "123.abc" } ); contributor.is_admin // => true
A Ruby sample:
contributor = @client.update_contributor "123.abc", "12345", languages: [{lang_iso: 'en'}] contributor.languages[0]['lang_iso'] # => 'en
Listing translation keys
To list all translation keys for the given project, provide at least the project ID. If you would like to list the keys along with their translations, you must set the include_translations
parameter to 1
(the default value is 0
). Please note that we do not provide a content delivery network for your language files. Therefore, please do not engage a request to this endpoint with every website/app visitor. Instead, access the “keys” endpoint from time to time, store the result locally, and serve your visitors with static files or database content.
TS code sample:
const keys = await lokaliseApi.keys().list({ project_id: "123.abc", include_translations: 1, }); keys.items[0].translations // => translations object for the first key in the collection
A Ruby sample:
keys = @client.keys '123.abc', include_translations: 1 keys.collection.first.translations # => All translations for the first key
Merging project branches
To merge project branches, you’ll need to provide at least the source branch ID. If the target_branch_id
is not specified, it’ll default to the master branch.
TS code sample:
const branch_id_merge = 42303 const response = await lokaliseApi.branches().merge( branch_id_merge, { project_id: "123.abc" }, { force_conflict_resolve_using: "master", } ) response.branch_merged // => true response.branch.branch_id // => 42303
A Ruby sample:
branch_id = 12345 response = @client.merge_branch "123.abc", branch_id, force_conflict_resolve_using: 'master' response['branch_merged'] # => true response['branch']['branch_id'] # => 12345
Conclusion
So, in this article we have discussed what an API is, how it works, and how to take advantage of the Lokalise API. Now you can employ our API to build custom workflows and automate routine operations! If you have any additional questions on the topic, please don’t hesitate to reach us out.
I thank you for staying with me today, and see you next time!