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

@palamedes/core

v1.25.0

Published

Palamedes-owned i18n instance and macro entry points

Readme

@palamedes/core

npm version CI Sponsored by Sebastian Software License: MIT OR Apache-2.0

Palamedes-owned i18n instance creation and macro entry points.

Use this package when you want the app-facing runtime piece of Palamedes: create an i18n instance, author messages with macros, and let the surrounding tooling handle extraction and catalogs.

Installation

pnpm add @palamedes/core

Minimal Example

import { createI18n } from "@palamedes/core";
import { setClientI18n } from "@palamedes/runtime";

const i18n = createI18n();

setClientI18n(i18n);

Runtime Fallback Hooks

createI18n starts with DEFAULT_LOCALE ("en") and accepts an optional locale override plus hooks for production telemetry. The initial locale is active immediately, including before its catalog is loaded. Missing active-locale catalog entries still render the source message, but onMissing lets apps count them. Malformed runtime patterns fall back to the source message instead of throwing through the component tree, and onError receives the parse/format failure.

const i18n = createI18n({
  onMissing({ id, locale }) {
    reportMetric("palamedes.missing", { id, locale });
  },
  onError({ id, locale, error }) {
    captureException(error, { tags: { id, locale } });
  },
});

Pass locale when the instance should start in another locale:

const i18n = createI18n({ locale: "de" });

For server-rendered applications, set timeZone to the same IANA identifier on the server and client. ICU {when, date} and {when, time} arguments then use that zone instead of the host process or browser zone, preventing hydration output from drifting across environments.

const i18n = createI18n({ locale: "en-US", timeZone: "Europe/Berlin" });

Date objects, timestamps, and ISO strings with a time represent instants and are rendered in timeZone. Date-only ISO strings such as "2026-06-12" represent civil calendar dates, so their year, month, and day stay the same in every configured zone. Invalid or empty zone identifiers throw a RangeError while creating the instance.

Use pmds audit --fail-on error in CI for checked-in catalogs, then wire these hooks to observe runtime-loaded catalogs or fast-moving translation changes. getMessage(id, metadata) uses the same missing-catalog lookup path as _(), so onMissing also fires when callers ask for a raw pattern by id and the active catalog does not contain that id. Since the initial locale is active immediately, this includes lookups before the first load() or activate() call. Apps that use source messages for the default locale without loading its catalog should account for those events in their telemetry policy.

For authoring imports, use:

import { t } from "@palamedes/core/macro";

The macro entry exports t, plural, select, and selectOrdinal. These eager macros must be used inside a function, method, or callback so they run after the relevant i18n instance has been activated. The transformer and extractor reject module-scope usage. Class field initializers do not count as function scope; use a method or getter instead.

Locale Controls

Use @palamedes/core/locale for framework-agnostic locale resolution and switch UI data:

import { defineLocaleControls } from "@palamedes/core/locale";

const localeControls = defineLocaleControls({
  locales: ["en", "de"],
  defaultLocale: "en",
});

const locale = localeControls.preferredLocale(request.headers.get("accept-language"));

The subpath also exports parseAcceptLanguage(), buildLocaleSwitchItems(), and their related types. React and Solid re-export the switch-item helper for component packages.

defineLocaleControls also binds deliberate-choice cookies, canonical URLs, and suggestion decisions for the cookie, route, subdomain, and tld strategies. Under the host strategies a locale switch changes the host, so canonicalUrl() and suggest() return host-carrying URLs. Those are protocol-relative (//host/path) by default — correct on http locally and https in production — until the config pins a scheme:

const localeControls = defineLocaleControls({
  locales: ["en", "de"],
  defaultLocale: "en",
  hosts: { mode: "subdomain" },
  protocol: "https",
});

Set protocol when the emitted URLs must be absolute, for example in canonical link tags, hreflang alternates, or sitemaps. See Locale strategies and the core API reference.

defineLocaleControls() validates its configuration immediately, including a non-empty unique locale set, the default locale, cookie names, http/https protocols, and configured DNS hosts/TLD labels. Locale identifiers only need to be DNS labels when the subdomain or tld strategy places them in a host.

Runtime Formatting

Catalog modules generated by the Palamedes plugins are compiled during the build. They export one message map: constant translations remain strings, while dynamic translations are renderer-independent functions. Core, React, and Solid execute those functions directly without browser ICU parsing or AST interpretation. Plural/select branches are allocated once when the module loads, not once per render.

Use the parser-free production entrypoint when the application loads only these generated catalogs:

import { createI18n, type CompiledCatalogMessages } from "@palamedes/core/compiled";

declare module "*.po" {
  export const messages: CompiledCatalogMessages;
}

const i18n = createI18n();

Generated catalog modules, transformed Trans components, and compiled MDX select their matching compiled entrypoints automatically. The explicit Core import above keeps the parser out of the application's own i18n factory too.

Hand-written string catalogs keep the bounded lazy parser and the same onError fallback behavior through createI18n from @palamedes/core. The parser-free factory rejects those unbranded catalogs at load() so an accidental compatibility dependency cannot silently enlarge the browser bundle. Generated catalogs are executable modules rather than JSON data: JSON serialization intentionally omits their function entries.

The package-root instance also exposes an optional parsePattern(pattern) adapter capability. It parses the argument as a raw ICU pattern without a catalog lookup; the parser-free factory intentionally omits it.

Palamedes supports the common ICU argument types that product UIs usually need inside translated sentences:

i18n._("Paid {amount, number, ::currency/EUR} on {when, date, medium} at {when, time, short}", {
  amount: 12.3,
  when: new Date(),
});

Supported runtime styles:

  • {value, number} plus percent, integer, and ::currency/ISO_CODE
  • {value, date, short|medium|long|full}
  • {value, time, short|medium|long|full}

Currency formatting must use the ::currency/ISO_CODE skeleton form; bare currency/ISO_CODE is outside the supported runtime subset.

Catalog artifact compilation reports unsupported formatter kinds such as list, duration, ago, and name as errors because the runtime does not render those kinds. Unsupported styles on number, date, and time are warnings: the runtime falls back to the default Intl formatter for that argument type.

Quoting And Literal Text

Apostrophes in source messages need no escaping. The macros and the extractor escape them on the way into the catalog, so t messages such as Ada's file and don't panic simply work. The one exception is a descriptor with a string-literal message — t({ message: "Hello {name}" }) — which is the raw-ICU authoring surface: placeholders and ICU quoting are written literally and nothing is auto-escaped there. The JSX message attribute (<Trans message="Hello {name}" />) is that same raw-ICU surface, while <Trans> children are authored text and are escaped.

The rules matter when a translator edits a .po file by hand, when a catalog comes back from a TMS, or when a pattern is passed straight to formatMessagePattern(). Palamedes implements ICU apostrophe quoting in its lenient form:

  • '' is always a literal apostrophe — Ada''s renders Ada's.
  • A single ' opens a quoted literal only before {, }, or (inside a plural or selectordinal branch, where # is syntax) #. Text up to the closing ' is literal.
  • Everywhere else ' is just an apostrophe, so don't and l'été render unchanged instead of swallowing the rest of the sentence.
  • An unterminated quote auto-closes at the end of the pattern instead of throwing.

'{' is therefore how a message emits a literal brace:

i18n._("Write '{'name'}' to insert the user name", {});
// -> "Write {name} to insert the user name"

Quoted text is exposed as MessageLiteralNode in getMessageNodes(), so custom renderers must handle that node type alongside text.

Plural Offset

plural and selectordinal support ICU offset:N for "and N others" sentences:

i18n._("{count, plural, offset:1 =0 {nobody else} one {# other} other {# others}}", { count: 3 });
// -> "2 others"

Exact =N keys match the raw value; plural categories select on value - offset, and # renders value - offset. The macro spelling is plural(count, { offset: 1, … }), and the React/Solid components take offset={1}; all three compile to the ICU form above.

palamedes is part of the Ferramenta family — Rust-native developer tools that keep the APIs the ecosystem already knows.

Siblings: ferroni · ferriki · ferromark · ferrolex · ferrocat · ferrovia · ferralk · ferrugo.

License

Sebastian Software

MIT OR Apache-2.0 © 2026 Sebastian Software