npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

translations-cli

v0.1.8

Published

A small script created as an attempt to make work with `react-intl` generated translation files a bit convenient

Readme

translations

Description

Installation

npm install -g translations-cli

Usage

Let's say your project already supports Spanish language and uses format.js as an internationalization tool.

So there are two JSON files in src/languages folder - one for English (en.json) and one for Spanish (es.json) locale:

src/languages
├── en.json
└── es.json

es.json content looks like:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  ... and 100 more lines
}

And in your code you have declared new messages to be translated:

intl.formatMessage({ id: 'Home.home', defaultMessage: 'Home' })

After you have extracted messages in some src/languages/extracted-messages.json file you got mix of previously and newly translated messages in it:

src/languages
├── en.json
├── es.json
└── extracted-messages.json

The extracted-messages.json now contains:

{
  "Home.home": {
    "defaultMessage": "Home",
    "description": "Home page title"
  },
  ... and 100 more lines
}

Now only newly declared messages (untranslated yet) have to be sent to your translation vendor. To get them you could write next command in you terminal:

translations get-from src/languages/extracted-messages.json --exclude src/languages/es.json

This command writes all the messages from extracted-messages.json which ids not in es.json file yet. If no output file explicitly provided with -o or --output flag - it will create untranslated-messages.json file in the same folder as the first command's argument (src/languages):

src/languages
├── en.json
├── es.json
├── extracted-messages.json
└── untranslated-messages.json

now the untranslated-messages.json contains:

{
  "Home.home": {
    "defaultMessage": "Home",
    "description": "Home page title"
  },
  ... and 20 more lines
}

Now you can send them to your translation vendor and they will give you back the translated raw-fresh-es.json JSON file of the same format:

{
  "Home.home": {
    "defaultMessage": "Inicio",
    "description": "Home page title"
  },
  ... and 20 more lines
}

You have to compile this into a react-intl consumable JSON file. So you compiled it into fresh-es.json:

src/languages
├── en.json
├── es.json
├── extracted-messages.json
├── fresh-es.json
└── untranslated-messages.json

The fresh-es.json contains:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.email": "Dirección de E-mail",
  "Login.password": "Contraseña",
  ... and 17 more lines
}

After this you have to merge newly translated messages from the fresh-es.json into previously translated messages in the es.json. In this point you may have two scenarios:

  1. add to es.json new messages only (new by id value) and preserve from overriding messages with already existing ids but with a new value (e.g. if translations for message with corresponding id was changed in fresh-es.json recently).
  2. to update all messages despite of the fact that their ids already exist in the es.json and gonna be overridden with messages from the fresh-es.json.

So currently es.json is:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  ... and 100 more lines
}

and fresh-es.json:

{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.email": "Dirección de E-mail",
  "Login.password": "Contraseña",
  ... and 17 more lines
}

We can see that in the fresh-es.json the message with id "Home.home" was modified and "Login.email" was added. Let's check next commands results.

  1. Command:
translations update src/languages/es.json --with src/languages/fresh-es.json --action update-existing
  1. es.json:
{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña"
  ... and 100 more lines
}
  1. Command:
translations update src/languages/es.json --with src/languages/fresh-es.json --action append-missing
  1. es.json:
{
    "Home.home": "Inicio",
    "Login.login": "Iniciar Sesión",
    "Login.password": "Contraseña",
    "Login.email": "Dirección de E-mail"
    ... and 100 more lines
}
  1. Command:

If -a (--action) flag wasn't provided explicitly:

translations update src/languages/es.json --with src/languages/fresh-es.json

is the same as:

translations update src/languages/es.json --with src/languages/fresh-es.json --action update-all
  1. es.json:
{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  "Login.email": "Dirección de E-mail"
  ... and 100 more lines
}

And finally manually clean up the src/languages:

src/languages
├── en.json
└── es.json