Compile-time i18n for modern TypeScript apps

Write messages in code. Ship translations with almost no runtime baggage.

SayKit is a framework-agnostic i18n toolkit built around compile-time extraction, typed configuration, and small runtime primitives. It keeps authoring ergonomic for developers and translation flows clean for everyone else.

ReactNext.jsTanStack StartReact NativeExpoCarbon
Code example
import { Say } from '@saykit/react';

export function Inbox({ count }: { count: number }) {
  return (
    <section>
      <h1><Say>Inbox</Say></h1>
      <p>
        <Say.Plural
          _={count}
          zero="You have no unread messages"
          one="You have 1 unread message"
          other="You have # unread messages"
        />
      </p>
    </section>
  );
}

Why SayKit

  • Compile-time extraction from JS, TS, JSX, and TSX
  • ICU MessageFormat for plurals, ordinals, and select
  • Framework-agnostic core, with adapters for React and Carbon
  • Translation files are plain modules, importable directly
  • Typed config, fast CLI, watch mode for instant feedback

Terminal

$ saykit extract

✓ 12 messages extracted

→ src/locales/en.po, fr.po

End-to-end workflow

A translation pipeline that stays close to your codebase

From authoring to deployment, without pushing app teams onto a heavyweight platform or a third-party service.

01

Define

Author messages inline with tagged templates or React components.

02

Extract

Scan source files and collect ICU-ready messages into translation files.

03

Translate

Hand translators structured files with comments, context, and stable identifiers.

04

Deploy

Import translation files directly. No compile step, no extra build-time transform, no shipped extractor.

Ready to try it?

Start with the docs, then adapt the example closest to your stack.

The repo includes working examples for Next.js, TanStack Start, and Carbon. The core runtime stays useful even outside framework-specific adapters.