raven-rookery

1.0.0 • Public • Published

raven-rookery

raven-rookery is a backend tool to get localizations from the popular POEditor localization service. raven-rookery gets and stores your localizations in memory, refreshing them at a given interval. It also provides an optional customizable API.

You no longer need to worry about throttling, queuing and rate limiting. Instead of making calls to POEditor's API, incorporate raven-rookery in your current project's API or use its built in API.

The API response from POEditor has a bunch of info you probably don't need. Additionally all languages in a project require their own API call. raven-rookery provides a much cleaner response: just key/value pairs describing your content and you can choose which languages you'd like in one call.

Here's a response hitting POEditor's API directly:

{
  "response": {
    "status": "success",
    "code": "200",
    "message": "OK"
  },
  "result": {
    "terms": [
      {
        "term": "GREETING",
        "context": "",
        "plural": "",
        "created": "2013-06-10T11:08:54+0000",
        "updated": "",
        "translation": {
          "content": "Hello",
          "fuzzy": 0,
          "proofread": 1,
          "updated": "2013-06-12T11:08:54+0000"
        },
        "reference": "",
        "tags": [
          "first_upload",
          "second_upload"
        ],
        "comment": ""
      }
      {}
    ]
  }
}

Here's a response using raven-rookery:

{
  "en-us": {
    "GREETING": "Hello",
    "ETC": "..."
  },
  "sp-mx": {
    "GREETING": "Hola",
    "ETC": "..."
  }
}

If you find raven-rockery useful consider using raven-writer on the FE to incorporate markdown and interpolations.

Additionally, raven-rockery is instantiated with your read-only API token once, instead of being used with every API call if hitting POEditor directly. This lessens the risk of it being committed accidentally if you have a larger team or codebase.


Docs

Install

$ npm install raven-rookery -S

Quick start example with starting server

This will start a dedicated express app. This is not required though. See the next example if you want to start your own server and integrate raven-rookery's functionality.

import { initRookery } from "raven-rookery";

const { startServer } = await initRookery({
  token: "<YOUR_READ_ONLY_POEDITOR_API_TOKEN>",
  projectIds: ["MY_POEDITOR_PROJECT_ID", "ETC"]
});

startServer();

When running locally and making the following request:

curl --globoff 'http://localhost:3000/localizations?data={"projectId":"MY_POEDITOR_PROJECT_ID"}'

You'll get back your localizations for your POEDITOR project with the project id MY_POEDITOR_PROJECT_ID.

Quick start example without starting server

In this example you'll be integrating raven-rookery with an already existing express app you've spun up yourself.

Note that of course you'd be setting your endpoint and query params to whatever you'd like.

import express from "express";
import { initRookery } from "./InitRookery/index.js";

const { getLocalizations } = await initRookery({
  token: "<YOUR_READ_ONLY_POEDITOR_API_TOKEN>",
  projectIds: ["MY_POEDITOR_PROJECT_ID", "ETC"]
});

const app = express();
app.use(express.json());

app.get("/some-endpoint", (req, res) => {
  const query = req.query["my-query"];
  const { id, langs } = JSON.parse(query);
  res.json(getLocalizations(id, langs));
});

app.listen(3000, () => {
  console.log("Server is running on port 3000");
});

When running locally and making the following request:

curl --globoff 'http://localhost:3000/some-endpoint?my-query={"id":"MY_POEDITOR_PROJECT_ID","langs":["en-us"]}'

You'll get back your localizations for your POEDITOR project with the project id MY_POEDITOR_PROJECT_ID and for just the language en-us.

initRookery({...})

Gets localizations for a set of POEditor projects, stores them in memory, and refreshes their values per a set amount of time. Returns functions to access those localizations and to start up an express server to access the localizations through a built in API.

Props

Prop Type Required? Description
token String The read only api_token found in your POEditor acct
projectIds Array[String] An array of project ids found in your POEditor acct
keepAlive Integer The refresh frequency in ms to GET localizations from POEditor. Defaults to 600000 (10 minutes)
serverConfig Object Configurations for the server created with startServer(). See the serverConfig table below.

serverConfig prop

Key Type Default value Description
endpoint String "/localizations" The endpoint to request localizations.
port Integer 3000 The port that the express server will run on
requestType String "GET" Can be "POST" OR "GET"
dataKey String "data" Changes the query param
languagesKey String "languages" Changes the languages key in the request
projectIdKey String "projectId" Changes the project id key in the request

Please see: Customizing API endpoint and params for info on changing serverConfig values and general info on making calls.

Returns

A promise that resolves to an object holding three methods:

Usage

See also quick start examples.

The following code snippet gets localization for projects w/ IDs "ID_1" and "ID_2". It will refresh the values of those localizations every 5 minutes. It sets some localizations of the projects into two consts. It starts an express server on port 3000 and will be accessible via the endpoint /api/translations for POST requests.

import { initRookery } from "raven-rookery";

const {
  getLocalizations,
  getLocalizationsByLang,
  startServer,
  killServer
} = await initRookery({
  token: "<YOUR_READ_ONLY_POEDITOR_API_TOKEN>",
  projectIds: ["ID_1", "ID_2"],
  keepAlive: 1000 * 60 * 5,
  serverConfig: {
    endPoint: "/api/translations",
    requestType: "POST"
  }
});

const allLocalizationsForProject1 = getLocalizations("ID_1");
const enUSLocalizationsForProject2 = getLocalizationsByLang("ID_2", "en-us");

startServer();

getLocalizations(id, languages)

Gets localizations for a given POEditor project whose id was used to instantiate initRookery({...}), optionally filtered by an array of languages present on that project.

Props

Prop Type Required? Description
id String The project id of one of the projects used to instantiate initRookery({...})
languages Array[String] Array of ISO 639-1 language codes that exist in the project whose id you passed in. If missing, all language localizations are returned.

Returns

A nest object whose top level keys are ISO 639-1 language codes, each holding that language's localizations in key/value pairs where the key is what POEditor refers to as the term and value is what POEditor refers to as the content. See the POEditor API for more details.

{
  "en-us": {
    "GREETING": "Hello"
  },
  "en-au": {
    "GREETING": "G'day"
  },
  "sp-mx": {
    "GREETING": "Hola"
  }
}

Usage

import { initRookery } from "raven-rookery";

const { getLocalizations } = await initRookery({
  token: "<YOUR_READ_ONLY_POEDITOR_API_TOKEN>",
  projectIds: ["ID_1", "ID_2"]
});

console.log(getLocalizations("ID_1", ["en-us"]));
/*
Logs:
"en-us": {
  "GREETING": "Hello"
}
*/

console.log(getLocalizations("ID_1"))
// logs all localizations for en-us, en-au, and sp-mx

getLocalizationsByLang(id, languages)

Gets localizations of a language for a given POEditor project whose id was used to instantiate initRookery({...}). The language given must be present on the POEditor project whose id is passed here.

Props

Prop Type Required? Description
id String The project id of one of the projects used to instantiate initRookery({...})
language String A ISO 639-1 language code that exists in the project whose id you passed in.

Returns

A flat object with key/value pairs where the key is what POEditor refers to as the term and value is what POEditor refers to as the content. See the POEditor API for more details.

{
  "GREETING": "Hello"
}

Usage

import { initRookery } from "raven-rookery";

const { getLocalizationsByLang } = await initRookery({
  token: "<YOUR_READ_ONLY_POEDITOR_API_TOKEN>",
  projectIds: ["ID_1", "ID_2"]
});

console.log(getLocalizationsByLang("ID_1", "en-us"));
/*
Logs:
{
  "GREETING": "Hello",
  ...
}
*/

console.log(getLocalizationsByLang("ID_1", "sp-mx"));
/*
Logs:
{
  "GREETING": "Hola",
  ...
}
*/

startServer()

Starts an express server with a built in API to get localizations from endpoints. Out of the box it will listen for GET requests at the /localizations but this and other aspects can be customized. Please take a look customizing API endpoint and params.

Props

none

Returns

An object with keys app holding the created express app and server a UNIX socket. You don't have to do anything with these but they are there if you need them.

  { app, server }

Usage

import { initRookery } from "raven-rookery";

const { startServer } = await initRookery({...});

startServer();

/*
const { app, server } = startServer();
if you wanted to access the app and server.
*/

Once this is running you can make API calls to get localizations.

killServer()

Kills the express server started with startServer().

Props

none

Returns

undefined

Usage

import { initRookery } from "raven-rookery";

const { startServer } = await initRookery({...});

startServer();
killServer();

Once called you can no longer make API calls to get localizations.

Customizing API endpoint and params

The following sections outlines how to use the serverConfig object's dataKey, languagesKey, and projectIdKey to customize how you call API endpoints created via startServer(). They are all optional. What follows are comparisons to illustrate their use.

Please refer to Response schema

GET

Note: to construct the URL I recommend using JSON.stringify():

const options = {
  projectId: "ID_1",
  languages: ["en-us"]
};

const url = `'http://localhost:3000/localizations?data=${JSON.stringify(options)}`;
// with all defaults
const { startServer } = await initRookery({token: "MY_TOKEN", projectIds: ["ID_1", "ID_2"]});
startServer();

You'd need to make the following GET request for a single project, returning a 2-D response:

curl --globoff 'http://localhost:3000/localizations?data={"projectId":"ID_1","languages":["en-us"]}'

You'd need to make the following GET request for a multiple projects, returning a 3-D response:

curl --globoff 'http://localhost:3000/localizations?data=[{"projectId":"ID_1","languages":["en-us"]},{"projectId":"ID_1","languages":["en-us"]}]'

Now if we adjust the endpoint, port, dataKey, projectIdKey and languagesKey values:

const { startServer } = await initRookery({
  token: "MY_TOKEN",
  projectIds: ["ID_1", "ID_2"],
  serverConfig: {
    endpoint: "/my/long/endpoint",
    port: 1234,
    dataKey: "query",
    projectIdKey: "id",
    languagesKey: "langs"
  }
});
startServer();

You'd need to make the following GET request to get the same result 2-D response as the previous call:

curl --globoff 'http://localhost:1234/my/long/endpoint?query={"id":"ID_1","langs":["en-us"]}'

Or the following GET to get the same 3-D response as the previous call:

curl --globoff 'http://localhost:1234/my/long/endpoint?query=[{"id":"ID_1","langs":["en-us"]},{"id":"ID_2","langs":["en-us"]}]'

POST

// with all defaults except for requestType being set to "POST"
const { startServer } = await initRookery({
  token: "MY_TOKEN",
  projectIds: ["ID_1", "ID_2"],
  serverConfig: {
    requestType: "POST"
  }
});
startServer();

You'd need to make the following POST request for a single project, returning a 2-D response:

curl --location 'http://localhost:3000/localizations' \
  --header 'Content-Type: application/json' \
  --data '{ "projectId": "ID_1", "languages":["en-us"] }'

You'd need to make the following POST request for a multiple projects, returning a 3-D response:

curl --location 'http://localhost:3000/localizations' \
  --header 'Content-Type: application/json' \
  --data '{ "data": [{"projectId": "ID_1","languages":["en-us"]}, {"projectId": "ID_2","languages":["en-us"]}] }'

Now if we adjust the endpoint, port, dataKey, projectIdKey and languagesKey values:

const { startServer } = await initRookery({
  token: "MY_TOKEN",
  projectIds: ["ID_1", "ID_2"],
  serverConfig: {
    endpoint: "/my/long/endpoint",
    port: 1234,
    dataKey: "query",
    projectIdKey: "id",
    languagesKey: "langs"
  }
});
startServer();

You'd need to make the following POST request to get the same result 2-D response as the previous call:

curl --location 'http://localhost:1234/my/long/endpoint' \
  --header 'Content-Type: application/json' \
  --data '{ "id": "ID_1", "langs":["en-us"] }'

Or the following POST to get the same 3-D response as the previous call:

curl --location 'http://localhost:1234/my/long/endpoint' \
  --header 'Content-Type: application/json' \
  --data '{ "query": [{"id": "ID_1","langs":["en-us"]}, {"id": "ID_2","langs":["en-us"]}] }'

Response schema

The response is a nested object, either 2 or 3 dimensions depending on your request. Both GET and POST calls return the same response. To enable POST requests see initRookery({...}).

2-D API calls

The localizations for one project are returned as a single nested object. Top level keys are ISO 639-1 language codes, each holding that language's localizations in key/value pairs where the key is what POEditor refers to as the term and value is what POEditor refers to as the content. See the POEditor API for more details.

Note to get a 2-D response you're passing an object, to get a 3-D response you're passing an array of objects.

GET

curl --globoff 'http://localhost:3000/localizations?data={"projectId":"MY_POEDITOR_PROJECT_ID"}'

(Note: This GET call integrates well with the raven-writer front end util. To do so, set the url in the POE.fetchLocalizations({...}) method.)

POST

curl --location 'http://localhost:3000/localizations' \
  --header 'Content-Type: application/json' \
  --data '{ "projectId": "MY_POEDITOR_PROJECT_ID" }'

Response

Assuming you have the following languages on your project: en-us, sp-mx and a POE term GREETING.

{
  "en-us": {
    "GREETING": "Hello"
  },
  "sp-mx": {
    "GREETING": "Hola"
  }
}

3-D API calls

Returns one or more projects in a single nested object with the given project ID as the key for each.

GET

curl --globoff 'http://localhost:3000/localizations?data=[{"projectId":"MY_POEDITOR_PROJECT_ID"}]'

POST

curl --location 'http://localhost:3000/localizations' \
  --header 'Content-Type: application/json' \
  --data '{ "data": [{"projectId": "MY_POEDITOR_PROJECT_ID"}] }'

Response

Assuming you have the following languages on your project with id MY_POEDITOR_PROJECT_ID: en-us, sp-mx and a POE term GREETING and

{
  "MY_POEDITOR_PROJECT_ID": {
    "en-us": {
      "GREETING": "Hello"
    },
    "sp-mx": {
      "GREETING": "Hola"
    }
  }
}

Dependents (0)

Package Sidebar

Install

npm i raven-rookery

Weekly Downloads

1

Version

1.0.0

License

ISC

Unpacked Size

27.2 kB

Total Files

9

Last publish

Collaborators

  • 64bit.polygon