# Frontend Translations

> MANDATORY frontend translations with @aexol/dynamite - ALL user-facing text MUST use t(). useDynamite hook, factory patterns for data/schemas, cookie-based locale Use when this capability is needed.

- Skill: `tomevault-io/frontend-translations` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/frontend-translations`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/frontend-translations/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/frontend-translations

---


**ALL user-visible text MUST use `t()`. Hardcoded user-facing strings are bugs.**

## Usage

```typescript
import { useDynamite } from '@aexol/dynamite';

const { t, locale } = useDynamite();
t('Hello World');
t('Welcome, {{name}}', { name: 'John' });
```

## Factory Pattern (data files & Zod schemas)

Files outside React tree can't call hooks — accept `t` as parameter:

```typescript
export const getFeatures = (t: (key: string) => string) => [{ title: t('Feature One') }];

export const createSchema = (t: (key: string) => string) =>
  z.object({ name: z.string().min(2, t('Name must be at least 2 characters')) });

export type SchemaValues = z.infer<ReturnType<typeof createSchema>>;

// Inside component:
const schema = createSchema(t);
const form = useForm({ resolver: zodResolver(schema) });
```

## Locale (Cookie-Based)

- Locale stored in a `locale` **cookie** — NOT localStorage, NOT Zustand
- `LanguageSwitcher` sets cookie + `window.location.reload()`
- Server reads cookie → SSR renders correct language
- New locale: add to `SUPPORTED_LOCALES` in `backend/src/config/cookies.ts`, create `frontend/public/locales/{code}/common.json`, restart dev

## What to Translate

**Always:** buttons, page titles, form labels/placeholders, error messages, toasts, table headers, tab labels, nav items, empty states, confirmation dialogs

**Never:** brand names, code snippets, URLs, strings in `api/`/`lib/`/`stores/` that don't reach UI

## Rules

1. Key = English text — flat, no nesting
2. Factory pattern for all data files and Zod schemas
3. Locale via cookie only
4. **NEVER manually edit non-English locale files** — auto-generated by `@aexol/vite-plugin-dev-translate`
5. Commit generated translation files to git
6. Files outside React tree (`api/`, `lib/`) can't call `useDynamite()` — leave in English
7. Date formatting: use `locale` from `useDynamite()` with BCP 47 map: `{ en: 'en-US', pl: 'pl-PL' }`

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/aexol-studio) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-11 -->

