Skip to content

Commit 9aa7004

Browse files
feat: enhance TypeScript loader to support nested fields and arrays (#759)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Max Prilutskiy <maks.prilutskiy@gmail.com>
1 parent cc0fee2 commit 9aa7004

3 files changed

Lines changed: 340 additions & 23 deletions

File tree

.changeset/blue-pens-cheer.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@lingo.dev/_spec": minor
3+
"lingo.dev": minor
4+
---
5+
6+
Enhance TypeScript loader to support nested fields and arrays

packages/cli/src/cli/loaders/typescript.spec.ts

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,181 @@ describe("typescript loader", () => {
7474
expect(result).toContain("farewell: \"Adi");
7575
expect(result).toContain("number: 42");
7676
});
77+
78+
it("should extract string literals from nested objects", async () => {
79+
const input = `
80+
export default {
81+
messages: {
82+
welcome: "Welcome to our app",
83+
error: "Something went wrong",
84+
count: 5
85+
},
86+
settings: {
87+
theme: {
88+
name: "Dark Mode",
89+
colors: {
90+
primary: "blue",
91+
secondary: "gray"
92+
}
93+
}
94+
}
95+
};
96+
`;
97+
98+
const loader = createTypescriptLoader().setDefaultLocale("en");
99+
const result = await loader.pull("en", input);
100+
101+
expect(result).toEqual({
102+
"messages/welcome": "Welcome to our app",
103+
"messages/error": "Something went wrong",
104+
"settings/theme/name": "Dark Mode",
105+
"settings/theme/colors/primary": "blue",
106+
"settings/theme/colors/secondary": "gray"
107+
});
108+
});
109+
110+
it("should extract string literals from arrays", async () => {
111+
const input = `
112+
export default {
113+
greetings: ["Hello", "Hi", "Hey"],
114+
categories: [
115+
{ name: "Electronics", description: "Electronic devices" },
116+
{ name: "Books", description: "Reading materials" }
117+
]
118+
};
119+
`;
120+
121+
const loader = createTypescriptLoader().setDefaultLocale("en");
122+
const result = await loader.pull("en", input);
123+
124+
expect(result).toEqual({
125+
"greetings/0": "Hello",
126+
"greetings/1": "Hi",
127+
"greetings/2": "Hey",
128+
"categories/0/name": "Electronics",
129+
"categories/0/description": "Electronic devices",
130+
"categories/1/name": "Books",
131+
"categories/1/description": "Reading materials"
132+
});
133+
});
134+
135+
it("should update string literals in nested objects", async () => {
136+
const input = `
137+
export default {
138+
messages: {
139+
welcome: "Welcome to our app",
140+
error: "Something went wrong"
141+
},
142+
settings: {
143+
theme: {
144+
name: "Dark Mode",
145+
colors: {
146+
primary: "blue"
147+
}
148+
}
149+
}
150+
};
151+
`;
152+
153+
const loader = createTypescriptLoader().setDefaultLocale("en");
154+
155+
await loader.pull("en", input);
156+
157+
const data = {
158+
"messages/welcome": "Bienvenido a nuestra aplicación",
159+
"messages/error": "Algo salió mal",
160+
"settings/theme/name": "Modo Oscuro",
161+
"settings/theme/colors/primary": "azul"
162+
};
163+
164+
const result = await loader.push("es", data);
165+
166+
const resultStr = JSON.stringify(result);
167+
expect(resultStr).toContain("Bienvenido a nuestra aplicaci");
168+
expect(resultStr).toContain("Algo sali");
169+
expect(resultStr).toContain("Modo Oscuro");
170+
expect(resultStr).toContain("azul");
171+
});
172+
173+
it("should update string literals in arrays", async () => {
174+
const input = `
175+
export default {
176+
greetings: ["Hello", "Hi", "Hey"],
177+
categories: [
178+
{ name: "Electronics", description: "Electronic devices" },
179+
{ name: "Books", description: "Reading materials" }
180+
]
181+
};
182+
`;
183+
184+
const loader = createTypescriptLoader().setDefaultLocale("en");
185+
186+
await loader.pull("en", input);
187+
188+
const data = {
189+
"greetings/0": "Hola",
190+
"greetings/1": "Hola",
191+
"greetings/2": "Oye",
192+
"categories/0/name": "Electrónica",
193+
"categories/0/description": "Dispositivos electrónicos",
194+
"categories/1/name": "Libros",
195+
"categories/1/description": "Materiales de lectura"
196+
};
197+
198+
const result = await loader.push("es", data);
199+
200+
const resultStr = JSON.stringify(result);
201+
expect(resultStr).toContain("Hola");
202+
expect(resultStr).toContain("Oye");
203+
expect(resultStr).toContain("Electr");
204+
expect(resultStr).toContain("Dispositivos electr");
205+
expect(resultStr).toContain("Libros");
206+
expect(resultStr).toContain("Materiales de lectura");
207+
});
208+
209+
it("should handle mixed nested structures", async () => {
210+
const input = `
211+
export default {
212+
app: {
213+
name: "My App",
214+
version: "1.0.0",
215+
features: ["Login", "Dashboard", "Settings"],
216+
pages: [
217+
{
218+
title: "Home",
219+
sections: [
220+
{ heading: "Welcome", content: "Welcome to our app" },
221+
{ heading: "Features", content: "Check out our features" }
222+
]
223+
},
224+
{
225+
title: "About",
226+
sections: [
227+
{ heading: "Our Story", content: "We started in 2020" }
228+
]
229+
}
230+
]
231+
}
232+
};
233+
`;
234+
235+
const loader = createTypescriptLoader().setDefaultLocale("en");
236+
const result = await loader.pull("en", input);
237+
238+
expect(result).toEqual({
239+
"app/name": "My App",
240+
"app/version": "1.0.0",
241+
"app/features/0": "Login",
242+
"app/features/1": "Dashboard",
243+
"app/features/2": "Settings",
244+
"app/pages/0/title": "Home",
245+
"app/pages/0/sections/0/heading": "Welcome",
246+
"app/pages/0/sections/0/content": "Welcome to our app",
247+
"app/pages/0/sections/1/heading": "Features",
248+
"app/pages/0/sections/1/content": "Check out our features",
249+
"app/pages/1/title": "About",
250+
"app/pages/1/sections/0/heading": "Our Story",
251+
"app/pages/1/sections/0/content": "We started in 2020"
252+
});
253+
});
77254
});

0 commit comments

Comments
 (0)