---
title: Translating
description: How Teak's web app and browser extension are translated, how to add or change text, and the glossary every language uses
---

The web app (`apps/web`) and the browser extension (`apps/extension`) are translated into Spanish, Portuguese (Brazil), German, French, Japanese, Korean and Simplified Chinese. Every word people read comes from one catalog in `packages/i18n` (`@teak/i18n`). The native apps, Raycast, the Safari extension, these docs and emails are in English. To choose a language in the app, see [Language](/docs/features#language).

## Where things live

| What | Where |
|---|---|
| Locales, cookie name, `intlLocale` | `packages/i18n/src/locales.ts` |
| The English catalog (the source) | `packages/i18n/messages/en.json` |
| One catalog per language | `packages/i18n/messages/<locale>.json` |
| Hooks: `useTranslations`, `useUiLocale`, `useIntlLocale` | `@teak/i18n/react` |
| A translator outside React | `createTeakTranslator` from `@teak/i18n` |
| Term glossary | [Glossary](#glossary) on this page |
| Server error messages | `errors.*` keys, `apps/web/src/lib/serverErrors.ts`, `hooks/useServerErrors.ts` |

The signed-in web app gets its locale from the `teak-locale` cookie (read in `AuthenticatedAppProvider`), which mirrors the account's Language setting. Without a provider, for example in tests or a screen outside the app shell, components render English.

## Adding or changing text

1. Add the English text to `en.json` under the component's namespace, for example `cardModal.menu.replaceImage`. Namespaces follow the component or area (`settings.footer`, `sidebar`, `cardModal.menu`). Reuse a `common.*` key only when the word means the same everywhere (Cancel, Close, Undo).
2. Read it with `const t = useTranslations("cardModal.menu")` and `t("replaceImage")`.
3. Add the same key to all seven other catalogs in the same pull request, translated with the [glossary](#glossary). `scripts/i18n-catalog.test.ts` fails when a catalog lacks a key or its placeholders differ from English.
4. Run `bun test scripts/i18n-catalog.test.ts`, then look at the screen in the language (Settings → Language), and in the pseudo-locale (`?__locale=en-XA`, development only).

## Writing messages

- **Whole sentences, never concatenated.** Put values in placeholders: `"Moved {count, plural, one {# card} other {# cards}} to {folder}"`.
- **Plurals** use ICU: `{count, plural, one {# card} other {# cards}}`. Japanese, Korean and Chinese only use `other`.
- **Markup inside a sentence** uses tags and `t.rich`: `"Read the <link>docs</link>"` with `t.rich("key", { link: (chunks) => <a href="…">{chunks}</a> })`.
- **Attributes and toasts** count too: `aria-label`, `title`, `placeholder`, `alt`, and the text of `toast(...)`, `toast.success(...)` and `toast.error(...)`.
- **Data arrays** (menu items, options, shortcut lists) keep a stable `id` and a message key, not an English `label`. Build the visible label with `t` where it renders.
- **Helpers outside React** (in `lib/`) that return text take a translator argument, typed `TeakTranslator<"namespace">`, instead of returning English.
- **Server errors:** show `useServerErrors().message(error, fallback)`. It translates every known server message and card code and falls back to the server's English text.

## What stays English

- "Teak", plan names where the glossary says so, and search syntax: qualifiers (`is:fav`, `type:image`, `tag:`) and date words, which people type.
- Text the server stores on cards: link facts, bylines, price labels, import errors.
- Developer surfaces: the public API, MCP tool descriptions and CLI output.

## Dates and numbers

Format with `Intl`, passing `useIntlLocale()` as the locale (or `intlLocale(locale, …)` outside React). In English it returns the locale the code used before translation: `useIntlLocale()` gives `undefined` (the browser's locale) and `useIntlLocale("en-US")` gives `"en-US"`, so English output doesn't change. Never write a fixed `"en-US"`; lint flags it.

## Lint

- Biome `noJsxLiterals` flags text between JSX tags in `apps/web/src` and the extension's `entrypoints` and `components`.
- `scripts/lint/no-ui-string.grit` flags words in `aria-label`, `title`, `placeholder`, `alt` and toast calls, plus fixed `"en-US"` locales.
- Tests and `apps/web/src/components/ui/**` (shadcn primitives) are exempt. Punctuation and "Teak" are allowed.

## Glossary

Use these terms in every catalog, so a word means the same thing on every screen.

Never translate:

- **Teak**, the product name.
- **Pro**, the paid plan's name.
- Search syntax people type: qualifiers (`is:fav`, `type:image`, `tag:`, `folder:`), `OR`, and date words (`today`, `last week`).
- Key names in shortcuts (⌘, Shift, Esc, Enter).

Translate meaning, not words: short UI labels stay short. Keep ICU placeholders, tag names and plural categories exactly. Use sentence case where the language has case, and the language's own punctuation.

| Language | Register |
|---|---|
| Spanish (es) | formal, `usted` |
| Portuguese, Brazil (pt-BR) | `você` |
| German (de) | formal, `Sie` |
| French (fr) | formal, `vous`; a narrow no-break space (U+202F) before `:` `?` `!` `;` |
| Japanese (ja) | polite, です/ます; plain nouns for buttons and menu items |
| Korean (ko) | 합니다 style for sentences; plain nouns for buttons and menu items |
| Chinese, Simplified (zh-Hans) | neutral; full-width punctuation |

### Terms

| English | es | pt-BR | de | fr | ja | ko | zh-Hans |
|---|---|---|---|---|---|---|---|
| card | tarjeta | card | Karte | fiche | カード | 카드 | 卡片 |
| note (text card) | nota | nota | Notiz | note | メモ | 메모 | 笔记 |
| link | enlace | link | Link | lien | リンク | 링크 | 链接 |
| image | imagen | imagem | Bild | image | 画像 | 이미지 | 图片 |
| video | vídeo | vídeo | Video | vidéo | 動画 | 동영상 | 视频 |
| audio | audio | áudio | Audio | audio | 音声 | 오디오 | 音频 |
| document | documento | documento | Dokument | document | ドキュメント | 문서 | 文档 |
| palette | paleta | paleta | Palette | palette | パレット | 팔레트 | 调色板 |
| quote | cita | citação | Zitat | citation | 引用 | 인용 | 引用 |
| folder | carpeta | pasta | Ordner | dossier | フォルダ | 폴더 | 文件夹 |
| smart folder | carpeta inteligente | pasta inteligente | intelligenter Ordner | dossier intelligent | スマートフォルダ | 스마트 폴더 | 智能文件夹 |
| tag | etiqueta | tag | Tag | tag | タグ | 태그 | 标签 |
| archive (verb) | archivar | arquivar | archivieren | archiver | アーカイブ | 보관 | 归档 |
| Archive (view) | Archivo | Arquivo | Archiv | Archives | アーカイブ | 보관함 | 归档 |
| trash | papelera | lixeira | Papierkorb | corbeille | ゴミ箱 | 휴지통 | 废纸篓 |
| move to trash | mover a la papelera | mover para a lixeira | in den Papierkorb legen | placer dans la corbeille | ゴミ箱に移動 | 휴지통으로 이동 | 移到废纸篓 |
| restore | restaurar | restaurar | wiederherstellen | restaurer | 復元 | 복원 | 恢复 |
| delete forever | eliminar definitivamente | excluir permanentemente | endgültig löschen | supprimer définitivement | 完全に削除 | 영구 삭제 | 永久删除 |
| favorite (verb) | marcar como favorita | favoritar | als Favorit markieren | ajouter aux favoris | お気に入りに追加 | 즐겨찾기에 추가 | 收藏 |
| Favorites | Favoritas | Favoritos | Favoriten | Favoris | お気に入り | 즐겨찾기 | 收藏 |
| hidden card | tarjeta oculta | card oculto | ausgeblendete Karte | fiche masquée | 非表示のカード | 숨긴 카드 | 隐藏的卡片 |
| library | biblioteca | biblioteca | Bibliothek | bibliothèque | ライブラリ | 라이브러리 | 资料库 |
| vault | bóveda | cofre | Tresor | coffre | 保管庫 | 보관소 | 资料库 |
| Revisit | Repasar | Revisitar | Wiedersehen | Revoir | 振り返り | 다시 보기 | 回顾 |
| Shuffle | Aleatorio | Aleatório | Zufällig | Aléatoire | シャッフル | 셔플 | 随机 |
| Focus mode | Modo concentración | Modo foco | Fokusmodus | Mode concentration | 集中モード | 집중 모드 | 专注模式 |
| Refresh details | Actualizar detalles | Atualizar detalhes | Details aktualisieren | Actualiser les détails | 詳細を更新 | 세부 정보 새로 고침 | 刷新详情 |
| More like this | Más como esta | Mais como este | Ähnliche Karten | Plus de ce genre | 似たカード | 비슷한 카드 | 更多类似内容 |
| highlight | resaltado | destaque | Markierung | surlignage | ハイライト | 하이라이트 | 高亮 |
| reader | lector | leitor | Leseansicht | lecteur | リーダー | 리더 | 阅读器 |
| search | buscar | pesquisar | suchen | rechercher | 検索 | 검색 | 搜索 |
| filter | filtro | filtro | Filter | filtre | フィルタ | 필터 | 筛选 |
| command palette | paleta de comandos | paleta de comandos | Befehlspalette | palette de commandes | コマンドパレット | 명령 팔레트 | 命令面板 |
| keyboard shortcuts | atajos de teclado | atalhos de teclado | Tastenkürzel | raccourcis clavier | キーボードショートカット | 키보드 단축키 | 键盘快捷键 |
| upload | subir | enviar | hochladen | importer | アップロード | 업로드 | 上传 |
| import | importar | importar | importieren | importer | インポート | 가져오기 | 导入 |
| export | exportar | exportar | exportieren | exporter | エクスポート | 내보내기 | 导出 |
| Settings | Ajustes | Configurações | Einstellungen | Réglages | 設定 | 설정 | 设置 |
| Language | Idioma | Idioma | Sprache | Langue | 言語 | 언어 | 语言 |
| Theme | Tema | Tema | Design | Thème | テーマ | 테마 | 主题 |
| Free (plan) | Gratis | Grátis | Kostenlos | Gratuit | 無料 | 무료 | 免费 |
| Pro (plan) | Pro | Pro | Pro | Pro | Pro | Pro | Pro |
| subscription | suscripción | assinatura | Abo | abonnement | サブスクリプション | 구독 | 订阅 |
| card limit | límite de tarjetas | limite de cards | Kartenlimit | limite de fiches | カードの上限 | 카드 한도 | 卡片上限 |
| sign in | iniciar sesión | entrar | anmelden | se connecter | サインイン | 로그인 | 登录 |
| sign out | cerrar sesión | sair | abmelden | se déconnecter | サインアウト | 로그아웃 | 退出登录 |
| account | cuenta | conta | Konto | compte | アカウント | 계정 | 账户 |
| API key | clave de API | chave de API | API-Schlüssel | clé d’API | API キー | API 키 | API 密钥 |
| extension | extensión | extensão | Erweiterung | extension | 拡張機能 | 확장 프로그램 | 扩展 |
| Undo | Deshacer | Desfazer | Rückgängig | Annuler | 元に戻す | 실행 취소 | 撤销 |
