Worked example: how-to¶
Generated by
skills/document-authorwith type=how-to. Demonstrates the canonical Diátaxis how-to format — direct, problem-driven, no fluff.
---
title: How to add Korean copy to existing English-only components
description: Translate component copy to Korean while preserving design-ai conventions for honorific level, IME handling, and Daum Postcode integration.
type: how-to
audience: Developers shipping a Korean version of an English product
last_updated: 2026.05.08
---
# How to add Korean copy to existing English-only components
When you need to: ship a Korean locale for a product currently in English only.
## TL;DR
```ts
// 1. Wrap copy in a t() function
<button>{t("Save")}</button>
// 2. Use Korean-aware t() with honorific level
import { t } from "@/lib/i18n";
t("Save"); // → "저장" (consumer) or "저장하기" (formal)
Set LOCALE=ko and HONORIFIC=informal (해요체) or formal (합쇼체) per app configuration. Default formal for fintech / B2B; informal for consumer.
Steps¶
1. Inventory the copy¶
Find every literal string in your components. Tools:
# Quick grep
grep -r "Save\|Cancel\|Submit" src/
# Better: use react-i18next's extractor
i18next-scanner --config i18next-scanner.config.js
Output: a JSON file mapping every English string to a key.
2. Pick honorific level for your product¶
Use knowledge/i18n/korean-product-conventions.md to decide:
- Consumer mobile / friendly: 해요체 (~해요)
- B2B / formal / fintech / banking: 합쇼체 (~합니다)
- Government / legal / healthcare: 합쇼체 always
Decision sticks for the entire app — don't mix.
3. Translate using design-ai conventions¶
For UI strings, use the canonical Korean per knowledge/i18n/korean-typography.md:
| English | 해요체 | 합쇼체 |
|---|---|---|
| Save | 저장 | 저장하기 |
| Cancel | 취소 | 취소 |
| Submit | 제출 / 등록 | 제출하기 |
| Delete | 삭제 | 삭제하기 |
| Sign in | 로그인 | 로그인 |
| Sign up | 가입 | 회원가입 |
| Loading | 로딩 중 | 불러오는 중 |
| Try again | 다시 시도 | 다시 시도해 주세요 |
Don't direct-translate — Korean has different defaults. Example: "Submit" rarely means 제출 in Korean apps; it usually means 등록 or 저장.
4. Replace English in components¶
For each component:
Where t() reads from your locale JSON.
5. Handle Korean IME for input components¶
If your component has typeahead / autocomplete / mention features, IME composition must be respected. Update existing components:
+ const [isComposing, setIsComposing] = useState(false);
- <input onChange={(e) => onChange(e.target.value)} />
+ <input
+ onChange={(e) => !isComposing && onChange(e.target.value)}
+ onCompositionStart={() => setIsComposing(true)}
+ onCompositionEnd={(e) => {
+ setIsComposing(false);
+ onChange(e.target.value);
+ }}
+ />
Cite examples/component-input.md for the full pattern.
6. Replace address inputs with Daum Postcode¶
Korean users won't tolerate free-form address. Replace any <AddressInput> with the Daum Postcode-integrated version:
import { DaumPostcode } from "react-daum-postcode";
// ...use the Daum widget; see knowledge/i18n/korean-product-conventions.md
Cite examples/component-address-input.md.
7. Apply Korean typography¶
Add Pretendard to your font stack:
:root {
--font-family-base: 'Pretendard', -apple-system, BlinkMacSystemFont,
'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
}
Bump body line-height to 1.6 (Korean +10% adjustment) per knowledge/i18n/korean-typography.md:
Contrast check: translated Korean body text must keep at least 4.5:1 against the page background, and focus indicators on locale switchers or copy controls must keep 3:1 per knowledge/a11y/contrast.md. Screen reader output must announce the active locale and any language switcher state via aria-current or equivalent text.
8. Add Korean-specific patterns¶
If your app has:
- Payment: replace generic with Toss/KakaoPay/NaverPay buttons. See knowledge/i18n/korean-payments.md.
- Phone auth: add SMS verification flow with InputOTP — see examples/component-input-otp.md.
- Identity verification: integrate PASS — see examples/component-pass-auth.md.
- Money display: use KRWAmount or AmountInput — see examples/component-krw-amount.md.
Variations¶
Just translation, no Korean-specific UX¶
If you're only translating words (e.g., a documentation site), skip steps 5–8. The result will work but won't feel native.
Multi-locale (en + ko in one app)¶
Use a locale switcher in settings. Persist to localStorage + send via Accept-Language header.
Korean-only product¶
Skip the en stage entirely. Don't ship english-strings-with-Korean-fallback — just write Korean directly.
Common pitfalls¶
| Pitfall | Fix |
|---|---|
| Mixed 합쇼체 + 해요체 in same screen | Pick one. Document in style guide. |
| Translation breaks layout (Korean longer or shorter) | Use flex-grow not fixed widths; allow wrap. |
| Phone validation regex assumes US format | Update to Korean: /^01[0-9]-?\d{3,4}-?\d{4}$/ |
| English error messages slip through | Add a CI check via tools/audit/korean-copy-check.py. |
| Date format mm/dd/yyyy | Switch to yyyy.MM.dd (KR convention). |
See also¶
knowledge/i18n/korean-product-conventions.md— broader UX conventionsknowledge/i18n/korean-typography.md— type rulesknowledge/i18n/korean-payments.md— payment patternsknowledge/i18n/korean-publishing.md— store submissiontools/audit/korean-copy-check.py— automated check ```
Why this is a good how-to example¶
- Problem stated up front ("when you need to…").
- TL;DR with code snippet — for the reader who'll only read 5 seconds.
- Numbered steps with concrete actions.
- Variations section for adjacent cases.
- Common pitfalls save debug time.
- No motivation/background — that's an explanation doc.
- Imperative voice throughout ("install", "replace", "switch").
Cite knowledge/patterns/technical-writing.md for voice rules.
Cross-reference¶
examples/doc-tutorial-example.md— tutorial format (different)skills/document-author/PLAYBOOK.mdknowledge/patterns/information-architecture.md