Skip to content

Commit b49786e

Browse files
committed
docs: improve Korean translation and fix inconsistencies in examples
1 parent 06ce40b commit b49786e

File tree

2 files changed

+52
-79
lines changed

2 files changed

+52
-79
lines changed

docs/guide/examples.md

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -320,19 +320,4 @@ yield* step("item", ItemForm, {});
320320
}
321321
```
322322

323-
### Error Handling
324-
325-
```typescript
326-
*do(step) {
327-
try {
328-
const profile = yield* step("profile", ProfileForm, {});
329-
const verification = yield* step("verify", VerificationForm, { email: profile.email });
330-
return { profile, verification };
331-
} catch (error) {
332-
const retry = yield* step("retry", RetryForm, { error });
333-
return { error: retry };
334-
}
335-
}
336-
```
337-
338323
These examples demonstrate how Mozard enables concise, type-safe composition of complex form workflows using standard JavaScript control structures.

docs/kr/guide/examples.md

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ type Result = {
2626
preferences: Preferences;
2727
};
2828

29-
// 폼 컴포넌트들
3029
const ProfileForm = (props: MozardStepProps<Profile>) => {
3130
const { register, handleSubmit } = useForm<Profile>();
32-
31+
3332
return (
3433
<form onSubmit={handleSubmit(props.onSubmit)}>
3534
<h2>기본 정보</h2>
@@ -43,14 +42,14 @@ const ProfileForm = (props: MozardStepProps<Profile>) => {
4342

4443
const ParentConsentForm = (props: MozardStepProps<ParentConsent>) => {
4544
const { register, handleSubmit } = useForm<ParentConsent>();
46-
45+
4746
return (
4847
<form onSubmit={handleSubmit(props.onSubmit)}>
49-
<h2>보호자 동의 (미성년자)</h2>
48+
<h2>보호자 동의 (18세 미만)</h2>
5049
<input {...register("parentEmail", { required: true })} placeholder="보호자 이메일" />
5150
<label>
5251
<input {...register("agreed", { required: true })} type="checkbox" />
53-
보호자가 가입에 동의합니다
52+
보호자가 가입에 동의했습니다
5453
</label>
5554
<button type="submit">다음</button>
5655
</form>
@@ -59,14 +58,14 @@ const ParentConsentForm = (props: MozardStepProps<ParentConsent>) => {
5958

6059
const PreferencesForm = (props: MozardStepProps<Preferences> & { isMinor: boolean }) => {
6160
const { register, handleSubmit } = useForm<Preferences>();
62-
61+
6362
return (
6463
<form onSubmit={handleSubmit(props.onSubmit)}>
6564
<h2>환경설정</h2>
6665
{!props.isMinor && (
6766
<label>
6867
<input {...register("newsletter")} type="checkbox" />
69-
뉴스레터 수신 동의
68+
뉴스레터 구독
7069
</label>
7170
)}
7271
<select {...register("theme")}>
@@ -78,40 +77,36 @@ const PreferencesForm = (props: MozardStepProps<Preferences> & { isMinor: boolea
7877
);
7978
};
8079

81-
// 메인 앱
82-
export function SignUpApp() {
80+
export function RegistrationApp() {
8381
const [values, setValue] = useState<Entry<Schema>[]>([]);
84-
82+
8583
const { elements, done, value, get } = useMozard<Schema, Result>({
8684
values,
8785
onNext: setValue,
8886
*do(step) {
89-
// 1. 기본 정보 수집
9087
const profile = yield* step("profile", ProfileForm, {});
91-
92-
// 2. 미성년자인 경우 보호자 동의 필요
88+
9389
let parentConsent: ParentConsent | undefined;
9490
if (profile.age < 18) {
9591
parentConsent = yield* step("parentConsent", ParentConsentForm, {});
9692
}
97-
98-
// 3. 환경설정 (미성년자는 뉴스레터 옵션 제외)
99-
const preferences = yield* step("preferences", PreferencesForm, {
100-
isMinor: profile.age < 18
93+
94+
const preferences = yield* step("preferences", PreferencesForm, {
95+
isMinor: profile.age < 18
10196
});
102-
97+
10398
return { profile, parentConsent, preferences };
10499
}
105100
}, []);
106-
101+
107102
const profile = get("profile");
108103
const currentStep = values.length + 1;
109104
const totalSteps = profile?.age < 18 ? 3 : 2;
110-
105+
111106
return (
112107
<div>
113108
<div>진행률: {currentStep}/{totalSteps}</div>
114-
109+
115110
{done ? (
116111
<div>
117112
<h1>가입 완료!</h1>
@@ -122,7 +117,7 @@ export function SignUpApp() {
122117
<div>
123118
{values.length > 0 && (
124119
<button onClick={() => setValue(values.slice(0, -1))}>
125-
이전 단계
120+
이전
126121
</button>
127122
)}
128123
{elements.at(-1)}
@@ -133,24 +128,18 @@ export function SignUpApp() {
133128
}
134129
```
135130

136-
## 2. 동적 아이템 추가 플로우
131+
## 2. 동적 아이템 수집
137132

138-
사용자가 원하는 만큼 아이템을 추가할 수 있는 동적 폼입니다.
133+
동적 폼 루프를 구현하는 방법을 보여주는 예제입니다:
139134

140135
```tsx
141136
type User = { name: string; role: 'user' | 'admin' };
142137
type Item = { title: string; description: string };
143138
type ContinueChoice = { continue: boolean };
144139

145-
type DynamicSchema = {
146-
user: User;
147-
[key: `item-${number}`]: Item;
148-
[key: `continue-${number}`]: ContinueChoice;
149-
};
150-
151140
const ItemForm = (props: MozardStepProps<Item> & { index: number }) => {
152141
const { register, handleSubmit } = useForm<Item>();
153-
142+
154143
return (
155144
<form onSubmit={handleSubmit(props.onSubmit)}>
156145
<h2>아이템 #{props.index + 1}</h2>
@@ -163,65 +152,63 @@ const ItemForm = (props: MozardStepProps<Item> & { index: number }) => {
163152

164153
const ContinueForm = (props: MozardStepProps<ContinueChoice> & { itemCount: number }) => {
165154
const { register, handleSubmit } = useForm<ContinueChoice>();
166-
155+
167156
return (
168157
<form onSubmit={handleSubmit(props.onSubmit)}>
169158
<h2>현재 {props.itemCount}개 아이템이 추가되었습니다</h2>
170159
<label>
171160
<input {...register("continue")} type="checkbox" />
172-
아이템을 더 추가하시겠습니까?
161+
더 추가하시겠습니까?
173162
</label>
174-
<button type="submit">결정</button>
163+
<button type="submit">계속</button>
175164
</form>
176165
);
177166
};
178167

179168
export function DynamicItemApp() {
180-
const [values, setValue] = useState<Entry<DynamicSchema>[]>([]);
181-
182-
const { elements, done, value } = useMozard<DynamicSchema, { user: User; items: Item[] }>({
169+
const [values, setValue] = useState<Entry<any>[]>([]);
170+
171+
const { elements, done, value } = useMozard({
183172
values,
184173
onNext: setValue,
185174
*do(step) {
186175
const user = yield* step("user", UserForm, {});
187-
176+
188177
const items: Item[] = [];
189178
let shouldContinue = true;
190-
191-
// 첫 번째 아이템은 필수
179+
192180
const firstItem = yield* step("item-0", ItemForm, { index: 0 });
193181
items.push(firstItem);
194-
195-
// 추가 아이템들은 사용자 선택에 따라
182+
196183
while (shouldContinue) {
197184
const { continue: wantMore } = yield* step(
198-
`continue-${items.length}`,
199-
ContinueForm,
185+
`continue-${items.length}`,
186+
ContinueForm,
200187
{ itemCount: items.length }
201188
);
202-
189+
203190
if (wantMore) {
204191
const nextItem = yield* step(
205-
`item-${items.length}`,
206-
ItemForm,
192+
`item-${items.length}`,
193+
ItemForm,
207194
{ index: items.length }
208195
);
209196
items.push(nextItem);
210197
} else {
211198
shouldContinue = false;
212199
}
213200
}
214-
201+
215202
return { user, items };
216203
}
217204
}, []);
218-
205+
219206
return (
220207
<div>
221208
{done ? (
222209
<div>
223210
<h1>완료!</h1>
224-
<h2>{value.user.name}님의 아이템 목록:</h2>
211+
<h2>{value.user.name}님의 아이템들:</h2>
225212
<ul>
226213
{value.items.map((item, i) => (
227214
<li key={i}>{item.title}: {item.description}</li>
@@ -236,9 +223,9 @@ export function DynamicItemApp() {
236223
}
237224
```
238225

239-
## 3. 복잡한 조건부 분기
226+
## 3. 복잡한 조건부 플로우
240227

241-
관리자와 일반 사용자에 따라 완전히 다른 플로우를 가지는 예제입니다.
228+
사용자 타입에 따른 다중 분기 경로를 보여주는 예제입니다:
242229

243230
```tsx
244231
type UserType = { type: 'admin' | 'user'; email: string };
@@ -248,29 +235,26 @@ type Verification = { code: string };
248235

249236
export function ConditionalFlowApp() {
250237
const [values, setValue] = useState<Entry<any>[]>([]);
251-
238+
252239
const { elements, done, value } = useMozard({
253240
values,
254241
onNext: setValue,
255242
*do(step) {
256243
const userType = yield* step("userType", UserTypeForm, {});
257-
244+
258245
if (userType.type === "admin") {
259-
// 관리자 플로우
260246
const verification = yield* step("verification", VerificationForm, {});
261247
const adminSettings = yield* step("adminSettings", AdminSettingsForm, {});
262-
248+
263249
return {
264250
type: "admin" as const,
265251
email: userType.email,
266252
verification,
267253
settings: adminSettings
268254
};
269255
} else {
270-
// 일반 사용자 플로우
271256
const profile = yield* step("userProfile", UserProfileForm, {});
272-
273-
// 관심사가 3개 이상이면 추가 설문
257+
274258
if (profile.interests.length >= 3) {
275259
const survey = yield* step("survey", SurveyForm, { interests: profile.interests });
276260
return {
@@ -280,7 +264,7 @@ export function ConditionalFlowApp() {
280264
survey
281265
};
282266
}
283-
267+
284268
return {
285269
type: "user" as const,
286270
email: userType.email,
@@ -289,7 +273,7 @@ export function ConditionalFlowApp() {
289273
}
290274
}
291275
}, []);
292-
276+
293277
return (
294278
<div>
295279
{done ? (
@@ -324,11 +308,15 @@ yield* step("item", ItemForm, {}); // 반복문에서 중복 가능
324308
```typescript
325309
*do(step) {
326310
const user = yield* step("user", UserForm, {});
327-
311+
328312
if (user.type === "admin") {
329313
const settings = yield* step("adminSettings", AdminSettingsForm, {});
330314
return { user, adminSettings: settings }; // 명시적 키 이름
331315
}
332-
316+
333317
const profile = yield* step("userProfile", UserProfileForm, {});
334-
return { user, profile };
318+
return { user, userProfile: profile };
319+
}
320+
```
321+
322+
이러한 예제들은 Mozard의 모나딕 합성이 어떻게 복잡한 폼 플로우를 간결하고 타입 안전하게 표현할 수 있는지 보여줍니다. Generator의 `yield*` 구문을 통해 각 단계를 자연스럽게 연결하고, JavaScript의 제어 구조(`if`, `while`, `for`)를 그대로 사용할 수 있습니다.

0 commit comments

Comments
 (0)