---
id: vanilla/quickstart
title: Quickstart
---

Eight steps from empty Vite app to first translated string — no framework required. Each step links the page that owns the detail.

## 1. Install

```bash
pnpm add @secundus-studio/stift-core@0.4.0 @secundus-studio/stift-vite-plugin@0.4.0
```

Package variants: [Installation](../getting-started/installation.md).

## 2. Wire the Vite plugin

```ts
// vite.config.ts
import { stiftPlugin } from '@secundus-studio/stift-vite-plugin'

export default defineConfig({
  plugins: [stiftPlugin()],
})
```

Full options: [Build: Vite Plugin & CLI](../tooling/build.md).

## 3. Write the config

```ts
// stift.config.ts
import { defineConfig } from '@secundus-studio/stift-generator'

export default defineConfig({
  locales: { default: 'en', supported: ['en', 'ar'] },
  namespaces: { dir: 'locales', discovery: 'convention', default: ['common'] },
  messageFormat: 'icu-mf1',
  detection: { order: ['explicit', 'custom', 'navigator'], fallback: 'en' },
  loadingStrategy: 'lazy-per-namespace',
})
```

Start minimal; add `params.context`, `units`, and `security.tier` once the feature calls for them. Full schema: [stift.config.ts](../configuration/config-file.md).

## 4. Add the first namespace

Create `locales/en/common.json`:

```json
{ "greeting": "Hello, {name}!" }
```

The default locale is the schema — new keys propagate to every other locale automatically. Never hand-sync locale files. Rules: [Messages & Keys](../authoring/messages.md).

## 5. Create the instance

```ts
// src/stift.ts
import { createStift } from '@secundus-studio/stift-core'
import { createStiftRuntime } from 'virtual:stift/runtime'

export const stift = createStift({
  ...createStiftRuntime(), // generated config + catalog + source
})
```

The persisted locale + `setParam`/`setUnit` overrides are configured in `stift.config.ts` (`state: { prefix: '__stift_', storage: 'webStorage' }`) and read synchronously at construction. Generated artifacts: [Build: Vite Plugin & CLI](../tooling/build.md).

## 6. Boot

```ts
import { stift } from './stift'

const locale = await stift.detectLocale() // persisted > navigator > fallback
stift.setLocale(locale)
await stift.initialize({ locale }) // loads per loadingStrategy
```

## 7. Translate

```ts
Stift.scope('common')('greeting', { name: user.name })
```

Typos and wrong params are compile errors once the typegen runs. Values, plurals, formatting: [Translating & Formatting](./translating.md).

## 8. Verify

- `pnpm dev`: the greeting renders from `locales/en/common.json`.
- Mistype a key: `tsc` fails. That is the whole point.

## Where next?

- Writing real messages (ICU, dialects) → [Messages & Keys](../authoring/messages.md)
- Making it work offline → [Offline & Persistence](../runtime/offline-persistence.md)
- The React equivalents (provider, hooks) → [Setup & Boot Modes](../react/setup.md)
