원클릭으로
locale-ui-patterns
// Use when creating or modifying OpenChamber UI text, labels, buttons, placeholders, aria labels, empty states, toasts, dialogs, settings copy, navigation labels, or any user-facing strings.
// Use when creating or modifying OpenChamber UI text, labels, buttons, placeholders, aria labels, empty states, toasts, dialogs, settings copy, navigation labels, or any user-facing strings.
| name | locale-ui-patterns |
| description | Use when creating or modifying OpenChamber UI text, labels, buttons, placeholders, aria labels, empty states, toasts, dialogs, settings copy, navigation labels, or any user-facing strings. |
User-facing UI text must go through @/lib/i18n; do not hardcode English strings in components.
Use this skill for any React UI change that adds or edits visible text, accessible labels, placeholders, tooltips, toasts, dialogs, settings labels, navigation labels, or empty/error states.
packages/ui/src/lib/i18n/messages/en.ts.packages/ui/src/lib/i18n/messages/.const { t } = useI18n() from @/lib/i18n and render t('key').label(locale) from useI18n().packages/ui/src/lib/i18n/*; do not add locale fields to broad stores like useUIStore.useI18n().@/lib/i18n, not deep files.t(...) calls inside React render/hook scope so locale changes re-render text.labelKey / descriptionKey; resolve with t(...) inside the component.t explicitly.Use stable semantic keys, not English text as keys.
Keys should describe location + UI role + meaning. They should not encode current copy wording.
Use existing nearby naming when extending a surface. If no nearby pattern exists, choose a short path that mirrors the UI ownership.
Namespaces like layout.*, settings.*, chat.*, git.*, session.*, toast.*, and dialog.* are examples, not a fixed exhaustive list.
Good:
'settings.appearance.language.label': 'Language'
'layout.mainTab.chat': 'Chat'
'chat.input.placeholder': 'Ask OpenChamber...'
Bad:
'Language': 'Language'
'chatLabel': 'Chat'
'askOpenChamberDotDotDot': 'Ask OpenChamber...'
Avoid overly generic keys unless the text is truly global and context-independent. Prefer specific keys when button meaning can vary by surface.
Use {name} placeholders for dynamic values.
'toast.language.changed': 'Language changed to {language}'
t('toast.language.changed', { language: label(locale) })
Do not pass grammar fragments as params. Never use params like {suffix}, {plural}, {article}, {prefix}, {dateSuffix}, or pieces of words/sentences.
Bad:
t('dialog.delete.description', { count, suffix: count === 1 ? '' : 's' })
Good:
count === 1
? t('dialog.delete.descriptionSingle', { count })
: t('dialog.delete.descriptionPlural', { count })
Plural/count-dependent text must use separate complete-message keys unless all supported locales can use one identical complete sentence. Placeholders are only for real values ({count}, {name}, {path}), not grammar.
Optional clauses must also be complete-message keys. Do not build a sentence by injecting a translated phrase into another translated sentence.
Bad:
t('dialog.delete.description', {
dateLabel: date ? t('dialog.delete.dateSuffix', { date }) : '',
})
Good:
date
? t('dialog.delete.descriptionWithDate', { count, date })
: t('dialog.delete.description', { count })
aria-label, title, image alt text when user-facingDo not translate:
OpenChamber, OpenCode, GitHubMCP, SSE, WebSocket, APIUse when implementing drag-to-reorder / sortable lists or chips in OpenChamber with @dnd-kit — covers the correct setup for BOTH desktop and mobile (touch), the variable-width "stretch" fix, the wrapping multi-row strategy choice, and the pitfalls (infinite update loop, offset overlay) we already hit and fixed.
Use when creating or modifying UI components, styling, visual elements, or icons in OpenChamber. All UI colors must use theme tokens - never hardcoded values or Tailwind color classes. All icons must use the shared Icon component from the SVG sprite system - never import from @remixicon/react directly.
Use when creating or modifying terminal CLI commands, prompts, or output formatting in OpenChamber. Enforces Clack UX standards with strict parity and safety across TTY/non-TTY, --quiet, and --json modes.
Use when creating or modifying UI components, styling, or visual elements related to Settings in OpenChamber.