Skip to content

Commit c85f2ec

Browse files
jammy0903claude
andcommitted
feat: add full English language support for UI and lesson content
Replace all hardcoded Korean strings across 10 frontend components with i18n t() calls, add ~100 new EN/KO translation keys, implement locale-aware lesson content loading (backend ?locale= param + JSON file fallback), and create English versions of two C lessons (c-1-1, c-1-5). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6842904 commit c85f2ec

15 files changed

Lines changed: 759 additions & 121 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"lessonId": "c-1-1",
3+
"title": "Declaration and Memory Allocation",
4+
"concept": "The moment you declare a variable, memory space is reserved (but not initialized)",
5+
"content": {
6+
"code": "#include <stdio.h>\n\nint main() {\n int a;\n\n printf(\"Value of a: %d\\n\", a);\n\n return 0;\n}",
7+
"steps": [
8+
{
9+
"title": "Including the Header File",
10+
"explanation": "`#include <stdio.h>` imports declarations for standard I/O functions like `printf`.\n\nJust remember this: without this line, using `printf` will cause a compilation error.",
11+
"visualizationType": "cMemory",
12+
"code": "#include <stdio.h>",
13+
"stack": [],
14+
"heap": [],
15+
"stdout": ""
16+
},
17+
{
18+
"title": "Defining the main Function",
19+
"explanation": "`int main()` is the program's entry point. When execution begins, a main stack frame is created, and local variables are stored in this frame.\n\nAt this stage, no local variables have been declared yet, so only the frame exists.",
20+
"visualizationType": "cMemory",
21+
"code": "int main() {",
22+
"stack": [
23+
{
24+
"name": "main",
25+
"type": "frame",
26+
"func": "main",
27+
"value": "frame"
28+
}
29+
]
30+
},
31+
{
32+
"title": "Variable Declaration",
33+
"explanation": "`int a;` only reserves memory space without assigning a value.\n\nSo `a` contains a garbage value, and reading it can produce unpredictable results. It's generally safer to initialize at declaration, like `int a = 0;`.",
34+
"visualizationType": "cMemory",
35+
"code": "int a;",
36+
"stack": [
37+
{
38+
"name": "a",
39+
"value": "??? (Garbage)",
40+
"type": "int",
41+
"address": "0x1004"
42+
}
43+
]
44+
},
45+
{
46+
"title": "Garbage Value",
47+
"explanation": "Printing uninitialized `a` produces different results depending on the execution environment.\n\nThis is Undefined Behavior, and it causes bugs that are extremely hard to debug. The takeaway is simple: always initialize local variables at declaration.",
48+
"visualizationType": "terminal",
49+
"code": "printf(\"Value of a: %d\\n\", a);",
50+
"stdout": "Value of a: 21845 (example, varies per execution)"
51+
}
52+
],
53+
"deltaFormat": true
54+
},
55+
"quiz": {
56+
"question": "When you only declare a variable in C (without initialization), what value does it contain?",
57+
"options": [
58+
"Always 0",
59+
"Always NULL",
60+
"Unknown (Garbage Value)",
61+
"1"
62+
],
63+
"correctIndex": 2,
64+
"explanation": "Automatic initialization to zero only happens for global variables and static variables.\nLocal variables inside functions contain garbage values if not explicitly initialized."
65+
},
66+
"misconceptions": [
67+
{
68+
"wrong": "All variables start at 0",
69+
"correct": "Local variables are never automatically initialized to 0.",
70+
"why": "C considers initializing every variable to 0 a waste of performance (C prioritizes performance above all)."
71+
}
72+
],
73+
"keyTakeaway": "Declaring a variable creates memory space. But the value must be set by you."
74+
}
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
{
2+
"lessonId": "c-1-5",
3+
"title": "Loops (for)",
4+
"concept": "The for loop expresses initialization, condition, and increment in a single line. It's ideal for repetitions with a known count.",
5+
"content": {
6+
"code": "#include <stdio.h>\n\nint main() {\n int sum = 0;\n\n for (int i = 1; i <= 5; i++) {\n sum = sum + i;\n printf(\"i=%d, sum=%d\\n\", i, sum);\n }\n\n printf(\"Final sum: %d\\n\", sum);\n\n return 0;\n}\n",
7+
"steps": [
8+
{
9+
"title": "Starting main Function",
10+
"explanation": "Program starts. A main stack frame is created. In this lesson, we learn the **for loop** which executes the same code multiple times.\n\nWhat if you need the sum from 1 to 1000? Hardcoding is impossible — you need a loop. Think of it as placing a calculator on your desk — now you're ready to add numbers one by one.",
11+
"visualizationType": "cMemory",
12+
"code": "int main() {",
13+
"stack": [
14+
{
15+
"frame": "main",
16+
"name": "main",
17+
"value": "main"
18+
}
19+
],
20+
"heap": [],
21+
"stdout": ""
22+
},
23+
{
24+
"title": "Initializing the Sum Variable",
25+
"explanation": "`sum` must start at 0 for the accumulated result to be correct.\n\nWithout initialization, the calculation would start from a previous garbage value, corrupting the result.",
26+
"code": "int sum = 0;",
27+
"stack": [
28+
{
29+
"frame": "main",
30+
"name": "main",
31+
"value": "main"
32+
},
33+
{
34+
"name": "sum",
35+
"type": "int",
36+
"value": "0",
37+
"highlight": true,
38+
"address": "0x1000"
39+
}
40+
]
41+
},
42+
{
43+
"title": "Entering the for Loop (i = 1)",
44+
"explanation": "`for (int i = 1; i <= 5; i++)` packs initialization (i=1), condition (i<=5), and increment (i++) into one line.\n\nIf the condition is true, the body executes. When it becomes false, the loop terminates immediately.",
45+
"code": "for (int i = 1; i <= 5; i++) {",
46+
"stack": [
47+
{
48+
"frame": "main",
49+
"name": "main",
50+
"value": "main"
51+
},
52+
{
53+
"name": "sum",
54+
"type": "int",
55+
"value": "0",
56+
"address": "0x1000"
57+
},
58+
{
59+
"name": "i",
60+
"type": "int",
61+
"value": "1",
62+
"highlight": true,
63+
"address": "0x0ffc"
64+
}
65+
]
66+
},
67+
{
68+
"title": "Iteration 1: Adding i to sum",
69+
"explanation": "`sum = sum + i;` is the basic accumulation pattern.\n\nIn iteration 1, `sum = 0 + 1`, so `sum` becomes 1.",
70+
"code": "sum = sum + i;",
71+
"stack": [
72+
{
73+
"frame": "main",
74+
"name": "main",
75+
"value": "main"
76+
},
77+
{
78+
"name": "sum",
79+
"type": "int",
80+
"value": "1",
81+
"highlight": true,
82+
"address": "0x1000"
83+
},
84+
{
85+
"name": "i",
86+
"type": "int",
87+
"value": "1",
88+
"address": "0x0ffc"
89+
}
90+
]
91+
},
92+
{
93+
"title": "Iteration 1: Printing Current Values",
94+
"explanation": "Output: ```i=1, sum=1```. Printing values each iteration enables **step-by-step debugging** to verify the program works as intended.\n\nIteration 1 complete: added ```i=1``` to ```sum```, changing it from 0→1. Now the increment (```i++```) executes making ```i``` become 2, and the condition (```i <= 5```) is checked again.",
95+
"code": "printf(\"i=%d, sum=%d\\n\", i, sum);",
96+
"stdout": "i=1, sum=1"
97+
},
98+
{
99+
"title": "Iteration 2: i Increments (i = 2)",
100+
"explanation": "The increment expression makes `i` become 2. In a for loop, the increment runs automatically after the body.\n\nThe flow is always the same: check condition → execute body → increment → check condition again.",
101+
"code": "for (int i = 1; i <= 5; i++) {",
102+
"stack": [
103+
{
104+
"frame": "main",
105+
"name": "main",
106+
"value": "main"
107+
},
108+
{
109+
"name": "sum",
110+
"type": "int",
111+
"value": "1",
112+
"address": "0x1000"
113+
},
114+
{
115+
"name": "i",
116+
"type": "int",
117+
"value": "2",
118+
"highlight": true,
119+
"address": "0x0ffc"
120+
}
121+
]
122+
},
123+
{
124+
"title": "Iteration 2: sum += i",
125+
"explanation": "In iteration 2, `i=2` so `sum` increases from `1 → 3`.\n\nThis is the accumulation pattern at work: each iteration adds the current i to build the final sum.",
126+
"code": "sum = sum + i;",
127+
"stack": [
128+
{
129+
"frame": "main",
130+
"name": "main",
131+
"value": "main"
132+
},
133+
{
134+
"name": "sum",
135+
"type": "int",
136+
"value": "3",
137+
"highlight": true,
138+
"address": "0x1000"
139+
},
140+
{
141+
"name": "i",
142+
"type": "int",
143+
"value": "2",
144+
"address": "0x0ffc"
145+
}
146+
]
147+
},
148+
{
149+
"title": "Iteration 2: Output",
150+
"explanation": "The current state shows `i=2, sum=3`.\n\nHaving intermediate output makes it very useful for debugging the loop flow and accumulation process.",
151+
"code": "printf(\"i=%d, sum=%d\\n\", i, sum);",
152+
"stdout": "i=1, sum=1\ni=2, sum=3"
153+
},
154+
{
155+
"title": "Iteration 3: i = 3, sum = 6",
156+
"explanation": "In iteration 3, `sum = 3 + 3` makes `sum=6`.\n\nThe loop repeatedly applies the same rule to progressively build the result.",
157+
"code": "sum = sum + i;",
158+
"stack": [
159+
{
160+
"frame": "main",
161+
"name": "main",
162+
"value": "main"
163+
},
164+
{
165+
"name": "sum",
166+
"type": "int",
167+
"value": "6",
168+
"highlight": true,
169+
"address": "0x1000"
170+
},
171+
{
172+
"name": "i",
173+
"type": "int",
174+
"value": "3",
175+
"highlight": true,
176+
"address": "0x0ffc"
177+
}
178+
],
179+
"stdout": "i=1, sum=1\ni=2, sum=3\ni=3, sum=6"
180+
},
181+
{
182+
"title": "Iteration 4: i = 4, sum = 10",
183+
"explanation": "In iteration 4, `sum = 6 + 4` makes `sum=10`.\n\nLoops build the final value through these step-by-step state changes.",
184+
"code": "sum = sum + i;",
185+
"stack": [
186+
{
187+
"frame": "main",
188+
"name": "main",
189+
"value": "main"
190+
},
191+
{
192+
"name": "sum",
193+
"type": "int",
194+
"value": "10",
195+
"highlight": true,
196+
"address": "0x1000"
197+
},
198+
{
199+
"name": "i",
200+
"type": "int",
201+
"value": "4",
202+
"highlight": true,
203+
"address": "0x0ffc"
204+
}
205+
],
206+
"stdout": "i=1, sum=1\ni=2, sum=3\ni=3, sum=6\ni=4, sum=10"
207+
},
208+
{
209+
"title": "Iteration 5 (Final): i = 5, sum = 15",
210+
"explanation": "In the final iteration, `i=5` is added to make `sum=15`.\n\nAfter the next increment, `i=6` fails the condition `i <= 5`, so the loop ends.",
211+
"code": "sum = sum + i;",
212+
"stack": [
213+
{
214+
"frame": "main",
215+
"name": "main",
216+
"value": "main"
217+
},
218+
{
219+
"name": "sum",
220+
"type": "int",
221+
"value": "15",
222+
"highlight": true,
223+
"address": "0x1000"
224+
},
225+
{
226+
"name": "i",
227+
"type": "int",
228+
"value": "5",
229+
"highlight": true,
230+
"address": "0x0ffc"
231+
}
232+
],
233+
"stdout": "i=1, sum=1\ni=2, sum=3\ni=3, sum=6\ni=4, sum=10\ni=5, sum=15"
234+
},
235+
{
236+
"title": "Loop Termination (Condition False)",
237+
"explanation": "When `i=6`, the condition `i <= 5` is false, so the loop terminates.\n\nA for loop exits the moment the condition becomes false, skipping the body entirely.",
238+
"code": "for (int i = 1; i <= 5; i++) {",
239+
"stack": [
240+
{
241+
"frame": "main",
242+
"name": "main",
243+
"value": "main"
244+
},
245+
{
246+
"name": "sum",
247+
"type": "int",
248+
"value": "15",
249+
"address": "0x1000"
250+
}
251+
]
252+
},
253+
{
254+
"title": "Printing the Final Sum",
255+
"explanation": "`printf` outputs the final sum `15`.\n\nThis is a classic pattern of accumulating intermediate states through repetition to produce the final result.",
256+
"code": "printf(\"Final sum: %d\\n\", sum);",
257+
"stdout": "i=1, sum=1\ni=2, sum=3\ni=3, sum=6\ni=4, sum=10\ni=5, sum=15\nFinal sum: 15"
258+
},
259+
{
260+
"title": "Program Termination",
261+
"explanation": "`return 0;` terminates the program normally.\n\nThe key takeaway is simple: the for loop is the most readable and safe choice for repetitions with a relatively clear count.",
262+
"code": "return 0;",
263+
"stack": []
264+
}
265+
],
266+
"deltaFormat": true
267+
},
268+
"quiz": {
269+
"question": "How many times does for (int i = 0; i < 3; i++) iterate?",
270+
"options": [
271+
"2 times",
272+
"3 times",
273+
"4 times",
274+
"Infinite loop"
275+
],
276+
"correctIndex": 1,
277+
"explanation": "Values of i: 0 → 1 → 2 → (3 fails i < 3, terminates)\n\ni values executed: 0, 1, 2 → 3 iterations total"
278+
},
279+
"misconceptions": [
280+
{
281+
"wrong": "The loop variable i can be used after the loop ends",
282+
"correct": "When declared as for (int i = ...), the scope of i is limited to the for block.",
283+
"why": "Once the loop ends, i is removed from the stack.\nTo use i outside the loop, you must declare it before the for statement."
284+
}
285+
],
286+
"keyTakeaway": "The for loop packs 'init; condition; increment' into one line — the best choice when the iteration count is clear!"
287+
}

packages/backend/src/modules/courses/routes.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const courseRoutes: FastifyPluginAsync = async (fastify) => {
4949
fastify.get('/lessons/:id', async (request, reply) => {
5050
try {
5151
const { id } = request.params as { id: string };
52+
const { locale } = request.query as { locale?: string };
5253
const lesson = await courseService.getLessonFull(id);
5354

5455
if (!lesson) {
@@ -57,7 +58,8 @@ const courseRoutes: FastifyPluginAsync = async (fastify) => {
5758

5859
// JSON 파일에서 콘텐츠 로드 (없으면 null)
5960
// Lazy Loading: await 필수
60-
const jsonContent = await lessonContentLoader.getContent(id);
61+
// locale이 있으면 해당 언어 파일을 먼저 시도 (e.g., c-1-1.en.json)
62+
const jsonContent = await lessonContentLoader.getContent(id, locale);
6163

6264
// 하이브리드 응답: DB 메타데이터 + JSON 콘텐츠
6365
// JSON 구조가 Flat한 경우(code, steps가 최상위)와 Nested된 경우(content 내부) 모두 지원

0 commit comments

Comments
 (0)