Compile-Time vs Runtime Flow
Compile-Time Processing
During build, the Babel plugin:- Parses your source code looking for
saymacro calls - Extracts messages and converts them to ICU MessageFormat
- Transforms macro calls into runtime function calls
- Generates unique IDs for each message (via hashing)
Runtime Processing
At runtime, the Say class:- Loads translations for the active locale
- Formats messages using ICU MessageFormat
- Manages locale state and fallbacks
The Babel Plugin
The Babel plugin is the heart of Saykit’s compile-time transformation. It processes two types of syntax:Tagged Template Literals
- Extracts the message
"Hello, {0}!" - Generates a hash ID (
a1b2c3) - Transforms the tagged template into a
call()method - Maps placeholders to numbered parameters
packages/plugin-babel/src/core/visitor.ts:14-26
Method Calls (plural, select, ordinal)
packages/plugin-babel/src/features/js/parser.ts:44-100
Message Processing Pipeline
1. Parsing Phase
The visitor walks the AST looking for expressions and JSX elements:packages/plugin-babel/src/core/visitor.ts:14-26
2. Message Conversion
Messages are converted to ICU MessageFormat:packages/plugin-babel/src/core/messages/convert.ts:10-50
3. Hash Generation
Each message gets a unique ID based on its content and optional context:- Stable IDs across builds
- Context-based disambiguation
- Optional custom IDs via
say({ id: 'custom' })
packages/plugin-babel/src/core/messages/hash.ts
4. Extraction
Messages are collected and written to translation files:packages/config/src/shapes.ts:8-16
Package Structure
Saykit is organized as a monorepo with specialized packages:saykit
Core runtime - the
Say class and type definitionsPackage: packages/integration@saykit/babel-plugin
Babel plugin for macro transformationPackage:
packages/plugin-babel@saykit/config
Configuration management and CLI toolsPackage:
packages/config@saykit/format-po
PO/POT file formatter (default)Package:
packages/format-po@saykit/react
React integration with
<Say> componentPackage: packages/integration-react@saykit/unplugin
Universal plugin for Vite, Webpack, etc.Package:
packages/unpluginKey Design Principles
Type Safety
TheSay class is fully typed with TypeScript generics:
Zero Runtime Overhead
Macros are compiled away - no runtime macro processing:- ✅ Message extraction happens at build time
- ✅ IDs are pre-generated
- ✅ Only the formatted message runs at runtime
Framework Agnostic
The core is framework-independent:- Works with React, Vue, Svelte, etc.
- Integrations provide framework-specific helpers
- CLI tools work standalone
Developer Experience
Natural syntax with full IDE support:- Tagged templates for simple messages
- Method calls for plurals/selects
- TypeScript autocompletion
- JSX component syntax for React
The Babel plugin must be configured in your build tool for macros to work. See Installation for setup instructions.