Lokalise APIv2 Node SDK

Node interface for the Lokalise APIv2.

View the Project on GitHub lokalise/node-lokalise-api




Changelog

13.0.0 (12-Dec-2024)

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" }
}

12.8.0 (15-Oct-2024)

const roles = await lokaliseApi.permissionTemplates().list({
  team_id: teamId,
});

const roleDetails = roles.items[0];

roleDetails.id // => 1
roleDetails.role // => "Manager"
roleDetails.tag // => "Full access"
const user_group = await lokaliseApi.userGroups().get(groupId, {
  team_id: teamId,
});

user_group.role_id; // => 5
const contributor = await lokaliseApi.contributors().get(userId, {
  project_id: projectId,
});

contributor.role_id; // => 5

12.7.0 (17-Jul-2024)

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

12.6.0 (01-Jul-2024)

const teams = await lokaliseApi.teams().list();
const team = teams.items[0];

team.quota_allowed.ai_words // => 4000
team.quota_usage.ai_words // => 1234

12.5.0 (14-May-2024)

// 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,
});

12.4.1 (24-Apr-2024)

12.4.0 (25-Mar-2024)

12.3.0 (19-Mar-2024)

12.2.1 (13-Mar-2024)

12.2.0 (13-Mar-2024)

12.1.0 (05-Dec-2023)

12.0.0 (23-Sep-2023)

11.1.0 (19-Sep-2023)

11.0.1 (23-Aug-2023)

11.0.0 (23-Aug-2023)

10.0.0 (5-Jul-2023)

9.8.1 (23-May-2023)

8.5.1 (23-May-2023)

9.8.0 (29-Mar-2023)

8.5.0 (29-Mar-2023)

9.7.0 (16-Mar-2023)

8.4.0 (16-Mar-2023)

9.6.1 (02-Mar-2023)

9.6.0 (28-Jan-2023)

8.3.0 (28-Jan-2023)

9.5.0 (11-Jan-2023)

const response = await lokaliseApi.jwt().create("1234.abcd");

response.jwt // => "eyJ0eXAiOiJKV1QiLCJhbG..."

9.4.0 (30-Dec-2022)

9.3.0 (30-Nov-2022)

const response = await lokaliseApi.jwt().get();

response.jwt // => "eyJ0eXAiOiJKV1QiLCJhbG"

9.2.0 (20-Oct-2022)

9.1.0 (13-Oct-2022)

9.0.0 (05-Oct-2022)

8.2.0 (20-Oct-2022)

8.1.0 (13-Oct-2022)

8.0.2 (03-Oct-2022)

// 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);
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");

8.0.1 (01-Sep-2022)

8.0.0 (01-Aug-2022)

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 }
);
const client = new LokaliseApi({
  apiKey: "123abc",
  host: "https://custom.example.com/api2/",
});

7.3.1 (07-Jun-2022)

7.3.0 (07-Jun-2022)

7.2.0 (08-Mar-2022)

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();

7.1.1 (21-Feb-2022)

7.1.0 (17-Dec-2021)

7.0.1 (10-Nov-2021)

7.0.0 (25-Oct-2021)

lokaliseApi.comments.list_project_comments()

lokaliseApi.files.upload()
lokaliseApi.comments().list_project_comments() // .comments(), not .comments

lokaliseApi.files().upload() // .files(), not .files
const lokaliseApi = new LokaliseApiOAuth({ apiKey: '<apiKeyObtainedViaOauth2>' });

const projects = lokaliseApi.projects().list();

6.3.0 (15-Jul-21)

6.2.2 (13-Jul-21)

6.2.1 (18-May-21)

6.2.0 (28-Apr-21)

6.1.0 (26-Feb-21)

6.0.0 (02-Feb-21)

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:

To 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.

5.3.0 (24-Nov-20)

5.2.2 (09-Nov-20)

5.2.1 (03-Nov-20)

5.2.0 (02-Oct-20)

5.1.0 (09-Sep-20)

5.0.0 (08-Jul-20)

lokaliseApi.branches.merge(34567,
  {project_id: '123.abc'},
  {"force_conflict_resolve_using": "master"}
)

4.0.1 (16-Jun-20)

4.0.0 (18-May-20)

3.0.3 (22-Apr-20)

3.0.0 (27-Mar-20)

2.1.0 (28-Feb-20)

2.0.2 (25-Feb-20)

2.0.1 (09-Dec-19)

2.0.0 (05-Dec-19)

1.5.0-rc.1 (04-Dec-19)

1.4.0 (13-Nov-19)

1.3.0 (30-Oct-19)

1.2.0 (20-Aug-19)

1.1.0 (18-Jul-19)

1.0.1 (12-07-19)

1.0.0 (20-06-19)

Note that this version is a major re-write and has API breaking changes! Check documentation for the specific endpoint to learn more.

0.0.9 (07-06-19)

0.0.4