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

@vocoder/core

v0.3.2

Published

Shared primitives for the Vocoder i18n SDK — hash, ICU formatting, locale utilities, and types

Readme

@vocoder/core

Shared primitives for the Vocoder i18n SDK.

Installation

npm install @vocoder/core

When to use this package directly

Most users should install @vocoder/react instead — it re-exports everything from this package along with the React components and hooks.

Use @vocoder/core directly only when you are:

  • Building a custom framework integration that does not use React
  • Writing tooling (extractors, validators, migration scripts) that needs hash generation or ICU formatting without a React dependency
  • Implementing a custom runtime that needs cookie utilities or locale matching

API Reference

generateMessageHash(text, context?, formality?)

Generates a stable 7-character base-36 message ID from source text. Produces the same output in Node.js and browsers. Used by the extractor at build time and the runtime in the browser — both always produce the same key for the same input.

import { generateMessageHash } from "@vocoder/core";

// Deterministic — same input always produces the same hash
generateMessageHash("Hello, world!");         // "3k2m9q1"

// Context disambiguates identical strings with different meanings
generateMessageHash("Save", "button label");  // different hash
generateMessageHash("Save", "dialog title");  // different hash

// Formality produces separate keys for register variants
generateMessageHash("Welcome back", undefined, "formal");   // hash A
generateMessageHash("Welcome back", undefined, "informal"); // hash B
generateMessageHash("Welcome back", undefined, "auto");     // same as no formality

| Parameter | Type | Required | Description | |---|---|---|---| | text | string | yes | Source message text | | context | string | no | Disambiguation string for identical text with different meanings | | formality | string | no | "formal" or "informal" produce distinct hashes; "auto" and undefined hash identically |

Returns a 7-character string (base-36, zero-padded). Collision probability is approximately 0.002% across 10,000 strings.


formatICU(text, values, locale?)

Formats an ICU MessageFormat string with interpolated values. Returns the raw text unchanged if parsing or formatting throws — the caller always receives a string, never an exception.

import { formatICU } from "@vocoder/core";

// Plural
formatICU(
  "{count, plural, one {# item} other {# items}}",
  { count: 1 },
  "en"
); // "1 item"

formatICU(
  "{count, plural, one {# item} other {# items}}",
  { count: 5 },
  "en"
); // "5 items"

// Select
formatICU(
  "{gender, select, male {He agreed} female {She agreed} other {They agreed}}",
  { gender: "female" },
  "en"
); // "She agreed"

// Simple interpolation
formatICU("Hello, {name}!", { name: "Maria" }, "es"); // "Hello, Maria!"

| Parameter | Type | Required | Description | |---|---|---|---| | text | string | yes | ICU MessageFormat string | | values | Record<string, any> | yes | Interpolation values keyed by placeholder name | | locale | string | no | BCP 47 locale tag; defaults to "en" |

Returns a string. Parsed results are cached by "locale:text" key.


rewriteSelectordinalInICU(icu, ordinalForms, values)

Rewrites any embedded selectordinal nodes in an ICU string using a locale's ordinalForms data before passing the string to formatICU. This is required when a selectordinal appears inside a larger sentence rather than as the sole top-level element, because translation providers store incorrect ordinal branches in those cases.

import { rewriteSelectordinalInICU, formatICU } from "@vocoder/core";

const rewritten = rewriteSelectordinalInICU(
  "Congrats on your {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} anniversary!",
  ordinalForms, // from locale bundle
  { year: 3 }
);
const result = formatICU(rewritten, { year: 3 }, "en");
// "Congrats on your 3rd anniversary!"

Returns icu unchanged when the string contains no "selectordinal" substring (fast path) or when parsing throws.

This function is called automatically by @vocoder/react when rendering ordinals. See the @vocoder/react docs for usage via ordinal() and the <T> component.


formatValue(value, format, locale, options?)

Formats a number or date value using Intl.NumberFormat or Intl.DateTimeFormat. Formatters are cached internally.

import { formatValue } from "@vocoder/core";

formatValue(1234567.89, "number",   "de");                         // "1.234.567,89"
formatValue(0.175,      "percent",  "en");                         // "17.5%"
formatValue(9876543,    "compact",  "en");                         // "9.9M"
formatValue(42.6,       "integer",  "fr");                         // "43"
formatValue(49.99,      "currency", "en", { currency: "USD" });    // "$49.99"
formatValue(new Date(), "date",     "ja", { dateStyle: "long" });  // "2026年5月9日"
formatValue(new Date(), "time",     "en");                         // "3:04 PM"
formatValue(new Date(), "datetime", "en", { dateStyle: "short", timeStyle: "short" }); // "5/9/26, 3:04 PM"

| Parameter | Type | Required | Description | |---|---|---|---| | value | string \| number \| Date | yes | The value to format | | format | FormatMode | yes | One of the format modes listed below | | locale | string | yes | BCP 47 locale tag | | options | FormatValueOptions | no | Additional formatting options |

Format modes:

| Mode | Input type | Description | |---|---|---| | "number" | number | Locale-aware decimal formatting | | "integer" | number | Rounded to zero decimal places | | "percent" | number | Multiplies by 100 and appends percent sign | | "compact" | number | Abbreviated notation (1.2M, 3.4K) | | "currency" | number | Currency symbol and formatting; requires options.currency | | "date" | Date / string / number | Date portion only | | "time" | Date / string / number | Time portion only | | "datetime" | Date / string / number | Date and time |

FormatValueOptions:

| Option | Type | Default | Description | |---|---|---|---| | currency | string | — | ISO 4217 currency code (e.g. "USD"); required when format is "currency" | | dateStyle | "full" \| "long" \| "medium" \| "short" | "medium" | Date display style | | timeStyle | "full" \| "long" \| "medium" \| "short" | "short" | Time display style |


getCookie(name, cookieString?) / getBestMatchingLocale(...) / setCookie(...)

Cookie utilities and locale negotiation used by the Vocoder provider for locale detection and persistence.

import { getCookie, setBestMatchingLocale, setCookie, getBestMatchingLocale } from "@vocoder/core";

// Read a cookie (browser or server)
const locale = getCookie("vocoder_locale");                        // browser
const locale = getCookie("vocoder_locale", req.headers.cookie);   // server

// Write a cookie (browser only)
setCookie("vocoder_locale", "fr", { maxAge: 31536000, path: "/" });

// Negotiate the best supported locale from a preferred value
getBestMatchingLocale("en-US", ["en", "fr", "de"], "en"); // "en"
getBestMatchingLocale("pt-BR", ["pt", "en"],       "en"); // "pt"
getBestMatchingLocale("zh",    ["en", "fr"],        "en"); // "en" (fallback)

getCookie(name, cookieString?) — Reads a cookie by name. When cookieString is omitted it reads from document.cookie in the browser. Returns null when the cookie is absent or the environment is not a browser and no string was provided.

setCookie(name, value, options?) — Writes a cookie to document.cookie. No-ops in non-browser environments. Defaults: maxAge 1 year, path /, sameSite "Lax", secure based on current protocol.

getBestMatchingLocale(preferredLocale, supportedLocales, fallback) — Returns the closest supported locale for a given preference. Tries exact match first, then language-only match ("en-US""en"), then any regional variant of the same language, then the fallback.


Types

| Type | Description | |---|---| | TranslationsMap | Nested map of locale → key → translated string | | OrdinalSuffixes | CLDR plural-category suffixes (zero, one, two, few, many, other) for suffix-based ordinals | | OrdinalForms | Discriminated union: { type: "suffix"; suffixes: OrdinalSuffixes } or { type: "word"; words: Record<string, Record<number, string>> } | | LocaleInfo | Metadata for a single locale: nativeName, optional dir ("rtl"), currencyCode, and ordinalForms | | LocalesMap | Map of locale code → LocaleInfo | | FormatMode | Union of valid format mode strings for formatValue | | TOptions | Options for <T> and t(): context, formality, and id | | VocoderTranslationData | Canonical translation bundle shape: config (source locale, target locales, locale metadata) + translations map + updatedAt | | FormatValueOptions | Options for formatValue: currency, dateStyle, timeStyle |


Most users should install @vocoder/react which re-exports everything from this package.