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

@forgedevstack/lingo

v1.0.1

Published

Translation and localization library for ForgeStack. Manage languages, keys, and AI-powered translations.

Downloads

261

Readme

Lingo

Translation and localization library for ForgeStack. Manage languages, resolve keys, handle plurals, and switch locales — all with a clean API.

Use Lingo Portal to manage translations visually: create a project, add keys, and AI-translate to all languages in one click.


ForgeStack

Lingo is part of the ForgeStack ecosystem. The Lingo Portal (the web app where you manage projects and keys) is built with:

| Package | Purpose | |--------|--------| | @forgedevstack/bear | Full UI kit — buttons, inputs, cards, modals, typography, icons, alerts, tabs, etc. | | @forgedevstack/forge-compass | Client-side routing — CompassProvider, Routes, useNavigate, useRoute. | | @forgedevstack/grid-table | Data tables for listing and editing (e.g. keys, projects). |

You can use Lingo in any stack. If you build with React, Bear and Compass pair well for UI and navigation; grid-table is optional for table-heavy admin screens.


Features

  • Key resolution — Dot-separated nested keys (auth.login.title).
  • InterpolationHello, {{name}}!Hello, John!.
  • Plurals — CLDR plural categories (zero, one, two, few, many, other) for 30+ languages.
  • RTL support — Automatic dir and lang on the document and provider wrapper.
  • Local or remote — Bundle translations or fetch from Lingo Portal API.
  • Caching — Persist selected locale in localStorage.
  • Framework-agnostic core — React adapter included; core works anywhere.
  • Tiny — Zero dependencies (React optional).

Install

npm install @forgedevstack/lingo

React is optional (peer dependency when using the React build):

npm install @forgedevstack/lingo react

Quick start

Local translations

import { createLingo, LingoProvider, useLingo } from '@forgedevstack/lingo';

const lingo = createLingo({
  defaultLocale: 'en',
  fallbackLocale: 'en',
  locales: ['en', 'es', 'fr', 'ar'],
  source: {
    type: 'local',
    translations: {
      en: {
        greeting: 'Hello, {{name}}!',
        auth: { login: 'Sign In', register: 'Sign Up' },
        items: { one: '{{count}} item', other: '{{count}} items' },
      },
      es: {
        greeting: '¡Hola, {{name}}!',
        auth: { login: 'Iniciar sesión', register: 'Registrarse' },
        items: { one: '{{count}} elemento', other: '{{count}} elementos' },
      },
    },
  },
});

function App() {
  return (
    <LingoProvider instance={lingo}>
      <MyPage />
    </LingoProvider>
  );
}

function MyPage() {
  const { t, locale, setLocale, direction } = useLingo();

  return (
    <div>
      <h1>{t('greeting', { name: 'John' })}</h1>
      <p>{t('auth.login')}</p>
      <p>{t('items', { count: 5 })}</p>
      <p>Direction: {direction}</p>
      <button onClick={() => setLocale('es')}>Español</button>
      <button onClick={() => setLocale('ar')}>العربية</button>
    </div>
  );
}

Remote translations (Lingo Portal)

Configure Lingo to load translations from the Portal API (e.g. after creating a project and copying the API URL from the Export page):

import { createLingo } from '@forgedevstack/lingo';

const lingo = createLingo({
  defaultLocale: 'en',
  fallbackLocale: 'en',
  locales: ['en', 'es', 'fr'],
  source: {
    type: 'remote',
    projectId: 'proj_abc123',
    endpoint: 'https://your-lingo-portal.com/api',
    apiKey: 'your_optional_api_key', // if your API requires it
  },
  cache: true,
  storageKey: 'lingo_locale',
});

Translations are fetched when the user switches locale. The API returns a flat key → value map for the requested locale.


API reference

createLingo(config)

Creates a Lingo instance.

| Config | Type | Description | |--------|------|-------------| | defaultLocale | string | Locale to use on first load | | fallbackLocale | string | Locale to fall back to when a key is missing | | locales | string[] | Supported locale codes | | source | TranslationSource | { type: 'local', translations } or { type: 'remote', projectId, endpoint?, apiKey? } | | cache | boolean | Persist locale in localStorage (default: true) | | storageKey | string | localStorage key (default: 'lingo_locale') | | debug | boolean | Log missing keys (default: true) | | onLocaleChange | (locale: string) => void | Callback on locale change | | onMissingKey | (key: string, locale: string) => void | Callback when a translation is missing |

Instance methods

| Method | Description | |--------|-------------| | t(key, vars?) | Translate a key with optional interpolation vars | | locale | Current active locale | | setLocale(locale) | Change locale (async; may fetch remote) | | locales | Array of supported locales | | direction | 'ltr' or 'rtl' for the current locale | | getLocaleInfo(locale) | Get locale metadata (name, nativeName, flag, direction) | | isLoading | true while fetching remote translations | | subscribe(listener) | Listen for state changes; returns unsubscribe fn | | addTranslations(locale, map) | Add or merge translations at runtime |

React exports

| Export | Description | |--------|-------------| | <LingoProvider instance={lingo}> | Wraps app with Lingo context; sets dir and lang | | useLingo() | Returns { t, locale, setLocale, locales, direction, isLoading, getLocaleInfo } | | <T k="key" vars={{}} /> | Inline translation component | | <Lingo k="key" vars={{}} /> | Same as <T>, with optional className and style | | <LocaleSwitcher /> | Simple <select> dropdown for switching locales |


Interpolation

Use {{variableName}} in translation strings and pass vars as the second argument to t() or via the vars prop on <T> / <Lingo>:

// String: "Hello, {{name}}!"
t('greeting', { name: 'Jane' });  // → "Hello, Jane!"

// With <T>
<T k="greeting" vars={{ name: 'Jane' }} />

Plurals

Define plural forms using CLDR categories in your translation map:

{
  "items": {
    "zero": "No items",
    "one": "{{count}} item",
    "other": "{{count}} items"
  }
}

Pass count in vars: t('items', { count: 3 })"3 items".

Supported plural rules: English, Spanish, French, Portuguese, German, Russian, Ukrainian, Polish, Czech, Arabic, Hebrew, Japanese, Korean, Chinese, and more.


RTL

When you switch to an RTL locale (ar, he, fa, ur), Lingo automatically:

  • Sets document.documentElement.dir = 'rtl'
  • Sets document.documentElement.lang to the locale
  • Wraps the provider children in a <div dir="rtl">

Utilities

import {
  flattenTranslations,
  unflattenTranslations,
  mergeTranslations,
  getDirection,
} from '@forgedevstack/lingo';

| Utility | Description | |---------|-------------| | flattenTranslations(map) | Nested object → flat dot-separated keys | | unflattenTranslations(flat) | Flat key-value → nested map | | mergeTranslations(a, b) | Deep merge (b overrides a) | | getDirection(locale) | Returns 'ltr' or 'rtl' |


Locale catalog

LOCALE_CATALOG provides metadata for 30+ locales (name, nativeName, direction, flag):

import { LOCALE_CATALOG } from '@forgedevstack/lingo';

// e.g. { code: 'ar', name: 'Arabic', nativeName: 'العربية', direction: 'rtl', flag: '🇸🇦' }

Package entry points

  • @forgedevstack/lingo — Core + React (createLingo, LingoProvider, useLingo, <T>, <Lingo>, LocaleSwitcher, utilities, types).
  • @forgedevstack/lingo/react — Same React components and hooks; use this subpath if you want to tree-shake the core.

Version

1.0.0