SayKit
ReferenceAPI

saykit

API reference for the saykit core runtime

The saykit package exports the Say class and a handful of supporting types.

import { Say } from 'saykit';
import type { ReadonlySay } from 'saykit';

Say

A container for locales, messages, the active locale, and formatting.

new Say(options)

new Say<Locale, Loader>(options: Say.Options<Locale, Loader>);

Prop

Type

Properties

Prop

Type

load(...locales)

Loads message catalogues for the given locales through the configured loader. With no arguments, loads every configured locale.

say.load();
say.load('fr');
say.load('fr', 'ja');

Already-loaded locales are skipped. If a loader is required but missing, throws. Returns this synchronously if all loaders are sync, or a promise resolving to this otherwise.

assign(locale, messages) / assign(record)

Directly attach messages without going through a loader.

say.assign('fr', { abc123: 'Bonjour !' });
say.assign({ en: { ... }, fr: { ... } });

Returns this.

activate(locale)

Set the active locale. The locale must be loaded or assigned first.

say.activate('fr');

Returns this.

match(...guesses)

Pick the best supported locale from one or more guesses. Each argument can be a string or array of strings; all guesses are flattened in order.

say.match('fr-CA', 'en');
say.match(['fr-CA', 'en-US'], 'de');

Matching order:

  1. exact match against locales
  2. language-prefix match (fr-CAfr)
  3. the first configured locale, as a final fallback

Returns the matched locale.

clone()

Returns a new Say with the same locales, messages, and loader. The new instance is independent, activating a locale on it doesn't affect the original.

freeze()

Returns a ReadonlySay view. Frozen instances can still read state and format messages, but cannot load, assign, or activate.

const readonly = say.clone().activate('fr').freeze();

call(descriptor)

Format a compiled message descriptor against the active locale's catalogue.

say.call({ id: 'abc123', name: 'Ada' }); // → "Hello, Ada!"

The descriptor must have an id. Extra properties are ICU placeholder values.

In normal application code, you don't write this, the build transform emits it from your say`...` macros.

Iteration

Say instances are iterable. They yield [frozenLocaleSay, locale] pairs for every configured locale.

for (const [localised, locale] of say) {
  console.log(locale, localised`Hello!`);
}

Each localised is a frozen clone with that locale already activated.

Macros

These methods are recognised by the SayKit build-tool plugins and rewritten into say.call(...) invocations. Calling them at runtime without a plugin throws.

say`template`

The tagged-template macro.

say`Hello, ${name}!`;

say({ id, context })

Descriptor form, returns a callable that you tag the template against.

say({ id: 'greeting' })`Hello!`;
say({ context: 'direction' })`Right`;

say.plural(value, options)

say.plural(count, {
  one: 'You have 1 item',
  other: 'You have # items',
});

say.ordinal(value, options)

say.ordinal(position, {
  1: '#st',
  2: '#nd',
  3: '#rd',
  other: '#th',
});

say.select(value, options)

say.select(gender, {
  male: 'He liked it',
  female: 'She liked it',
  other: 'They liked it',
});

Types

Say.Messages

namespace Say {
  type Messages = { [key: string]: string };
}

Say.Loader<Locale>

namespace Say {
  type Loader<Locale extends string> = (locale: Locale) => Messages | Promise<Messages>;
}

Say.Options<Locale, Loader>

Either messages is required (and loader optional), or loader is required (and messages optional).

ReadonlySay<Locale, Loader>

Say with load, assign, and activate typed as never. Returned by say.freeze().

NumeralOptions / SelectOptions

Option-bag types for plural, ordinal, and select. Both require an other key.

Next

On this page