Node interface for the Lokalise APIv2.
View the Project on GitHub lokalise/node-lokalise-api
due_date might be null)use_tm_as_context from task creation params, added mark_verified boolean parameter (as per recent API changes)content_integration should be marketing_integrationscontent_integration as the support project typeproject_language_uuid for the Language modelsave_ai_translation_to_tm, apply_ai_tm100_matches, and use_tm_as_context during task creation.marketing as a supported project typefilenames into the key field (project.translations.updated webhook)silent option for LokaliseApi to supress warning messages (default is false):const client = new LokaliseApi({
// other config ...
silent: true,
});
projectId attribute for glossary items:const termObject = await lokaliseApi.glossaryTerms().get(termId, {
project_id: projectId,
});
termObject.projectId; // => "123.abc"
team_uuid to Project for internal purposesresponseTooBig attribute to paginated responses and file download responses. For example:const response = await lokaliseApi.files().download(projectId, params);
response.responseTooBig; // false
const keys = await lokaliseApi.keys().list({ project_id: projectId });
keys.responseTooBig; // true
uuid fields to contrbiturs and projects for internal purposes/me endpoint (contributors) for internal purposesES2024 as targettranslations field from UpdateKeyData as the Update key endpoint does not allow updating translations directlyauthHeader when instantiating LokaliseApiconst process = await lokaliseApi
.files()
.async_download(projectId, params);
console.log(process.process_id);
The process is a QueuedProcess. Then you can simply fetch information about the process and grab the bundle URL:
const processInfo = await lokaliseApi
.queuedProcesses()
.get(process.process_id, { project_id: projectId });
processInfo.type; // => "async-export"
processInfo.status; // => "finished"
processInfo.details.total_number_of_keys; // => 14
processInfo.details.download_url // => "https://lokalise-live-lok-s3-fss-export.s3.eu-central-1.amazonaws.com/..."
const client = new LokaliseApi({
apiKey: "API_KEY",
requestTimeout: 5e3, // the value is in milliseconds
});
try {
await client.projects().list();
} catch (e) {
console.error(e);
console.log(e.message); // "Request timed out after 5000ms"
console.log(e.code); // 408
console.log(e.details); // { reason: "timeout" }
}
PermissionTemplates endpoint:const roles = await lokaliseApi.permissionTemplates().list({
team_id: teamId,
});
const roleDetails = roles.items[0];
roleDetails.id // => 1
roleDetails.role // => "Manager"
roleDetails.tag // => "Full access"
role_id attribute to the user group object. For example:const user_group = await lokaliseApi.userGroups().get(groupId, {
team_id: teamId,
});
user_group.role_id; // => 5
role_id attribute to the contributor object. For example:const contributor = await lokaliseApi.contributors().get(userId, {
project_id: projectId,
});
contributor.role_id; // => 5
tm_leverage field for the languages of the Task object:const task = await lokaliseApi.tasks().get(taskId, {
project_id: projectId,
});
const language = task.languages[0];
language.tm_leverage.status; // => "completed"
language.tm_leverage.value["50%+"]; // => 31
tm_leverage are “0%+”, “50%+”, “75%+”, “85%+”, “95%+”, and “100%”. Please note that the usage of initial_tm_leverage is deprecated.ai_words parameter under the quota_usage and quota_allowed field of the Team object:const teams = await lokaliseApi.teams().list();
const team = teams.items[0];
team.quota_allowed.ai_words // => 4000
team.quota_usage.ai_words // => 1234
// This approach is also applicable for `lokaliseApi.translations().list()`
const keys = await lokaliseApi.keys().list({
project_id: projectId,
limit: 2, // The number of items to fetch. Optional, default is 100
pagination: "cursor",
cursor: "eyIxIjo1MjcyNjU2MTd9", // The starting cursor. Optional, string
});
const key = keys.items[0]; // Accessing items as with regular pagination
const hasNext = keys.hasNextCursor(); // Returns a boolean
const nextCursor = keys.nextCursor; // Returns the next cursor as a string, empty if unavailable
const keysNextPortion = await lokaliseApi.keys().list({
project_id: projectId,
limit: 2,
pagination: "cursor",
cursor: nextCursor,
});
WebhookProjectTranslationsProofread webhook event type according to the documentationclose_language attribute to languages of UpdateTaskParams (thanks, @FelixGraf)close_language attribute to languages of UpdateTaskParams (thanks, @FelixGraf)compact attribute to FileDownloadParams interfacecompact attribute to FileDownloadParams interfaceDownloadFileParams and UploadFileParams) are stricter now and accept only the values that are actually supported by the API.DownloadFileParams and UploadFileParams) are stricter now and accept only the values that are actually supported by the API.jwt().get() with jwt().create(). The create() method accepts a mandatory project_id parameter:const response = await lokaliseApi.jwt().create("1234.abcd");
response.jwt // => "eyJ0eXAiOiJKV1QiLCJhbG..."
const response = await lokaliseApi.jwt().get();
response.jwt // => "eyJ0eXAiOiJKV1QiLCJhbG"
upvoting attribute from the settings object was removed from the response body of the following endpoints:
KeyParamsWithPagination, CreateKeyData, and others.require anymore). What can you do about it?
upvoting attribute from the settings object was removed from the response body of the following endpoints:
KeyParamsWithPagination interfacesApiError, Comment, File, and so on. For example, now you can say:// We can import the Contributor interface easily:
import { LokaliseApi, Contributor } from '@lokalise/node-api';
const lokaliseApi = new LokaliseApi({ apiKey: '123xyz' });
const contributors = await lokaliseApi.contributors().create([
{
// ...
}
], { project_id: '123.abc' });
const contributor: Contributor = contributors[0];
console.log(contributor.email, contributor.user_id);
RequestTokenResponse and RefreshTokenResponse interfaces:import {
RequestTokenResponse,
RefreshTokenResponse,
LokaliseAuth
} from '@lokalise/node-api';
const lokaliseAuth = new LokaliseAuth("123abc", "456zyx");
const token_resp: RequestTokenResponse = await lokaliseAuth.token("secret_code");
const refresh_resp: RefreshTokenResponse = await lokaliseAuth.refresh("refresh_token");
keys().create() when use_automations param was ignored. Please note that now keys have to be created in a slightly different way:const keys = await lokaliseApi.keys().create(
{
keys: [
{
key_name: "welcome_web",
description: "Index app welcome",
platforms: ["web"],
filenames: {
web: "my_filename.json",
},
translations: [
{
language_iso: "en",
translation: "Welcome",
},
],
},
{
key_name: "welcome_ios",
description: "Welcome apple",
platforms: ["ios"],
is_plural: true,
translations: [
{
language_iso: "en",
translation: {
one: "I have one apple",
other: "I have a lot of apples",
},
},
],
},
],
},
{ project_id: project_id }
);
// Per-platform key names:
const keys = await lokaliseApi.keys().create(
{
keys: [
{
key_name: {
ios: "name_for_ios",
web: "name_for_web",
android: "android_name",
other: "other_name",
},
platforms: ["web", "ios"],
translations: [
{
language_iso: "en",
translation: "Per-platform key names",
},
],
},
],
},
{ project_id: project_id }
);
const keys = await lokaliseApi.keys().bulk_update(
{
keys: [
{
key_id: key_id,
description: "Bulk node",
platforms: ["web"],
},
{
key_id: second_key_id,
description: "Second bulk",
},
],
},
{ project_id: project_id }
);
"https://api.lokalise.com/api2/" (for API endpoints) and "https://app.lokalise.com/oauth2/" (for OAauth 2 flow) but you can override these by providing an optional host param:const client = new LokaliseApi({
apiKey: "123abc",
host: "https://custom.example.com/api2/",
});
const { LokaliseAuth } = require('@lokalise/node-api');
// Provide your client id and client secret
const lokaliseAuth = new LokaliseAuth("client id", "client secret");
// Generate an authentication url
const url = lokaliseAuth.auth(
["read_projects", "write_team_groups"],
"http://example.com/redirect",
"random123"
);
// Generate an authentication and refresh tokens
const response = await lokaliseAuth.token("secret code");
const token = response["access_token"];
const refresh_token = response["refresh_token"];
// Refresh an access token once it expires
const new_token = await lokaliseAuth.refresh(refresh_token)["access_token"];
// Perform requests on the user's behalf
const { LokaliseApiOAuth } = require('@lokalise/node-api');
const lokaliseApi = new LokaliseApiOAuth({ apiKey: new_token });
const projects = lokaliseApi.projects().list();
TeamUserBillingDetails endpointSegments endpointlanguage_mapping for DownloadFileParams (thanks, @dhensby)lokaliseApi.comments.list_project_comments()
lokaliseApi.files.upload()
lokaliseApi.comments().list_project_comments() // .comments(), not .comments
lokaliseApi.files().upload() // .files(), not .files
LokaliseApiOAuth class:const lokaliseApi = new LokaliseApiOAuth({ apiKey: '<apiKeyObtainedViaOauth2>' });
const projects = lokaliseApi.projects().list();
enableCompression option: new LokaliseApi({ apiKey: "123abc", enableCompression: true }). The default value for this option is false. When set to true, it will add an Accept-Encoding=gzip,deflate header to the request. It can be very useful when requesting a large amount of data.UploadFileParams interface to comply with the API paramstypescript to devDependencies (thanks, @omonk)task_id for Translationpayment_method field (string) for the OrderApiRequest (thanks, @Tenga)This is a major release that contains quite a lot of changes mostly aimed towards pagination and typings system. Also the docs were updated, and various fixes were introduced.
Breaking change: pagination data is now attached directly to the collection returned by the request. Previously the following code was not working because pagination was stored in a separate object unrelated to the collection:
const projects = lokaliseApi.projects.list({team_id: team_id, page: 2, limit: 10});
projects.totalResults; // => undefined
Therefore, you had to do the following inconvenient trick (for example, see #53):
lokaliseApi.projects.list().totalResults;
This is not the case anymore! Paginated collections now have the following attributes and functions:
projects.totalResults; // => 30
projects.totalPages; // => 3
projects.resultsPerPage; // => 10
projects.currentPage; // => 2
projects.hasNextPage(); // => true
projects.hasPrevPage(); // => true
projects.isLastPage(); // => false
projects.isFirstPage(); // => false
projects.nextPage(); // => 3
projects.prevPage(); // => 1
However to get the actual data from the paginated response, you must use the .items attribute now:
const projects = lokaliseApi.projects.list({team_id: team_id, page: 2, limit: 10});
// CORRECT:
const project = projects.items[0]; // .items will fetch all projects data and [0] will get the first project
project.name
// INCORRECT:
const project = projects[0]; // this will not work anymore!
project.name
// And pagination can be fetched in the following way:
projects.totalResults; // => 30
projects.hasNextPage(); // => true
Breaking change: potential errors returned by the API when performing bulk create or bulk update operations are not swallowed anymore. For example, Lokalise APIv2 allows to create translation keys in bulk. If one of the key names is already taken, it won’t be created and the corresponding error message will be added to the errors response attribute. However, the whole operation will not fail and all other valid keys will still be created. The response has the following structure:
{
"project_id": "300abc.877xyz",
"keys": [
// keys that were successfully created
],
"errors": [
{
"message": "This key name is already taken",
"code": 400,
"key": {
"key_name": "button.ok" // this key name cannot be created because of the duplicating name
}
}
]
}
Previously such errors were silently swallowed, however that’s not the case anymore. Specifically, changes were made to the following methods:
keys.createkeys.bulk_update (note that keys.update is unaffected by this change)languages.createscreenshots.createTo fetch the actual data returned by these methods you now have to use the .items attribute. To fetch the errors, use .errors:
const keys = await lokaliseApi.keys.create(
[
{
key_name: "valid.key.name",
platforms: ["web"],
filenames: { web: "%LANG_ISO%.yml", },
translations: [
{
language_iso: "en",
translation: "Valid key",
},
],
},
{
key_name: "duplicate.key",
platforms: ["web"],
translations: [
{
language_iso: "en",
translation: "Duplicate!",
},
],
},
],
{ project_id: '123.abc' }
);
keys.errors[0].message // => "This key name is already taken" -- this key was not created
keys.items[0].key_name.ios // => "valid.key.name" -- this key was created
Update: added auto_close_items boolean attribute for Task.
use_automations flag to UploadFileParams (default is true)source_language_iso for the TaskKey and File.queue parameter doesn’t have any effect anymore. Therefore, removed all code and docs related to sync uploading.merge method for the Branches endpoint. It now accepts the branch ID to merge, the project ID and the optional list of additional parameters:lokaliseApi.branches.merge(34567,
{project_id: '123.abc'},
{"force_conflict_resolve_using": "master"}
)
QueuedProcess with the job status will be returned as a result. Synchronous uploading is still supported by the API but will be removed in the near future (use version 3 to upload synchronously).QueuedProcess endpointwebhook_id type for Webhooks endpointUploadFileParamslokaliseApi.webhooks.regenerate_secret(webhook_id, {project_id: project_id});totalResults, totalPages, resultsPerPage, currentPagenoImplicitAny and strictNullChecks to true in tsconfig.jsonmerge method for the branches endpoint allowing to perform mergesBranch endpointWebhook endpointTranslationStatus endpointNote that this version is a major re-write and has API breaking changes! Check documentation for the specific endpoint to learn more.
TranslationProvider, Order, PaymentCard