# i18n (Thai / English)

LCBP3 frontend **must not** hardcode Thai or English UI strings in components.

## Rules

1. **All user-facing strings go through the i18n layer** (`next-intl` / `i18next` — check `frontend/package.json`).
2. **Keys use kebab-case**, namespaced by feature:
   - `correspondence.list.title`
   - `correspondence.form.submit`
   - `common.actions.cancel`
3. **Comments in code remain Thai** (business logic explanation); **only UI copy** goes through i18n.
4. **Error messages** from backend (via ADR-007 `userMessage`) are already localized server-side — render them directly, don't translate client-side.

---

## ❌ Wrong

```tsx
export function CorrespondenceHeader() {
  return <h1>รายการหนังสือติดต่อ</h1>; // ❌ hardcoded Thai
}

toast.success('บันทึกสำเร็จ'); // ❌ hardcoded
```

---

## ✅ Right

```tsx
import { useTranslations } from 'next-intl';

export function CorrespondenceHeader() {
  const t = useTranslations('correspondence.list');
  return <h1>{t('title')}</h1>;
}

toast.success(t('save.success'));
```

Translation files:

```json
// messages/th.json
{
  "correspondence": {
    "list": { "title": "รายการหนังสือติดต่อ" },
    "save":  { "success": "บันทึกสำเร็จ" }
  }
}

// messages/en.json
{
  "correspondence": {
    "list": { "title": "Correspondence List" },
    "save":  { "success": "Saved successfully" }
  }
}
```

---

## Zod Error Messages

Zod error messages shown in forms **do** stay in Thai inline (per `specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md`), because they're schema-bound and rarely need translation. If dual-language support becomes required, wrap with an i18n-aware resolver:

```ts
const schema = z.object({
  projectUuid: z.string().uuid(t('validation.project.required')),
});
```

---

## Reference

- [i18n Guidelines](../../../specs/05-Engineering-Guidelines/05-08-i18n-guidelines.md)
- [Frontend Guidelines](../../../specs/05-Engineering-Guidelines/05-03-frontend-guidelines.md)
