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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@polingo/node

v0.0.3

Published

Node.js loader for Polingo translation system

Downloads

8

Readme

@polingo/node

npm version

Node.js adapter that loads gettext catalogs from disk, watches for changes, and plugs into web frameworks.

@polingo/node combines a filesystem loader, optional hot-reload watcher, and helper utilities so you can bootstrap Polingo in backend services, CLIs, Electron apps, or server-rendered frameworks.

Contents

  1. What it does
  2. Installation
  3. Quick start
  4. Directory layout
  5. API overview
  6. Framework recipes
  7. Hot reload & deployment tips
  8. Troubleshooting
  9. Related packages
  10. License

What it does

  • Parses .po and .mo catalogs with gettext-parser.
  • Provides createPolingo for one-call setup (loader, cache, preload, optional watcher).
  • Exposes NodeLoader if you need to wire things manually.
  • Ships an Express/Fastify-compatible polingoMiddleware with locale detection.
  • Includes TranslationWatcher for chokidar-based hot reloading during development.
  • Designed for TypeScript with rich types carried through from @polingo/core.

Installation

npm install @polingo/core @polingo/node
# or
pnpm add @polingo/core @polingo/node
# or
yarn add @polingo/core @polingo/node

Quick start

import { createPolingo } from '@polingo/node';

const polingo = await createPolingo({
  locale: 'en',
  locales: ['en', 'es'],
  directory: './locales',
  fallback: 'en',
  cache: true,
  watch: process.env.NODE_ENV === 'development',
});

polingo.t('Hello, world!');
polingo.tn('{n} file', '{n} files', 3, { n: 3 });

Call polingo.stopWatching?.() on shutdown if you enabled watch: true.

Directory layout

The loader accepts either of the common gettext layouts:

locales/
├── en/
│   ├── messages.po
│   └── errors.po
└── es/
    └── LC_MESSAGES/
        ├── messages.mo
        └── errors.mo

Internally the loader first tries <locale>/<domain>.po and falls back to <locale>/<domain>.mo.

API overview

createPolingo(options: CreatePolingoOptions)

Convenience helper that configures the loader, cache, domain, preload list, and optional watcher in one await.

interface CreatePolingoOptions {
  locale: string; // current locale
  locales: string[]; // locales to preload during init
  directory: string; // root folder that holds locale subfolders
  fallback?: string; // defaults to 'en'
  domain?: string; // defaults to 'messages'
  cache?: boolean; // MemoryCache when true, NoCache when false
  watch?: boolean; // enables chokidar watcher
  debug?: boolean; // console logging for missing catalogs, watcher events
}

Returns a Translator from @polingo/core extended with an optional stopWatching() method.

NodeLoader

Low-level loader if you prefer constructing translators yourself:

import { NodeLoader } from '@polingo/node';
import { Translator, MemoryCache } from '@polingo/core';

const loader = new NodeLoader('./locales');
const translator = new Translator(loader, new MemoryCache(), {
  locale: 'en',
  fallback: 'en',
});

await translator.load(['en', 'es']);

polingoMiddleware(options: MiddlewareOptions)

Drop-in Express/Fastify middleware that attaches a translator to req.polingo.

  • Detects the locale from req.query.locale or the Accept-Language header by default.
  • Supports perLocale: true to keep individual translator instances per locale.
  • Accepts the same preload, directory, cache, and watch options as createPolingo.
app.use(
  polingoMiddleware({
    locales: ['en', 'es'],
    directory: './locales',
    fallback: 'en',
    debug: process.env.NODE_ENV !== 'production',
  })
);

TranslationWatcher

Wires chokidar to re-load catalogs whenever matching .po or .mo files change. Normally you do not need to interact with it directly—createPolingo({ watch: true }) handles the setup.

Framework recipes

Express

import express from 'express';
import { polingoMiddleware } from '@polingo/node';

const app = express();

app.use(
  polingoMiddleware({
    locales: ['en', 'es'],
    directory: './locales',
    fallback: 'en',
  })
);

app.get('/', (req, res) => {
  res.send(req.polingo.t('Welcome to Polingo!'));
});

Fastify

import Fastify from 'fastify';
import { polingoMiddleware } from '@polingo/node';

const fastify = Fastify();
fastify.addHook('onRequest', polingoMiddleware({ locales: ['en', 'es'], directory: './locales' }));

fastify.get('/', async (req) => {
  return { message: req.polingo.t('Hello from Fastify') };
});

Next.js route handlers / API routes

Create once and reuse between requests to avoid repeated disk IO:

import { createPolingo } from '@polingo/node';

let nodePolingo: Awaited<ReturnType<typeof createPolingo>> | null = null;

async function getPolingo() {
  if (!nodePolingo) {
    nodePolingo = await createPolingo({
      locale: 'en',
      locales: ['en', 'es'],
      directory: './locales',
    });
  }
  return nodePolingo;
}

Hot reload & deployment tips

  • Enable watch: true only in development. File-system watchers keep extra descriptors open and may not be supported on serverless providers.
  • On change events the watcher clears the cache and re-loads the affected locale automatically. If you persist catalogs elsewhere, disable caching with cache: false and manage reloads manually.
  • Compile .po files to .mo for production to reduce parsing cost (use msgfmt or @polingo/cli once it lands).
  • Call await polingo.stopWatching?.() during graceful shutdown to release chokidar resources.

Troubleshooting

  • Translation file not found – verify your directory and ensure both <locale>/<domain>.po and <locale>/LC_MESSAGES/<domain>.po variants are present if you rely on gettext structure.
  • Invalid .po file – run msgfmt -c or a lint tool before deployment; parsing errors bubble up from gettext-parser.
  • High memory usage with many locales – disable caching (cache: false) or supply a MemoryCache with a maxSize.
  • Locale fallback not respected – make sure the fallback locale is included in the locales preload array so it is available immediately.

Related packages

  • @polingo/core – translation runtime (Translator, caches, helpers).
  • @polingo/web – fetch-based loader with localStorage cache for browsers.
  • @polingo/react – React hooks, context provider, and Trans component.
  • @polingo/cli – command line tooling for extraction, compilation, and validation.

License

MIT © Reinier Hernández Avila