Skip to content

Commit b1c397b

Browse files
feat: split mdx images into separate sections (#680)
* fix: dates in mdx feat: support locked keys in mdx * feat: split images into sections too
1 parent f200a62 commit b1c397b

11 files changed

Lines changed: 203 additions & 82 deletions

File tree

.changeset/eleven-otters-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"lingo.dev": patch
3+
---
4+
5+
split images into sections
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"lingo.dev": patch
3+
---
4+
5+
dates in mdx

.prettierrc

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/cli/.prettierrc

Lines changed: 0 additions & 17 deletions
This file was deleted.

packages/cli/demo/mdx/de.mdx

Whitespace-only changes.

packages/cli/i18n.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@
22
"version": 1.6,
33
"locale": {
44
"source": "en",
5-
"targets": ["es"]
6-
},
7-
"buckets": {
8-
"mdx": {
9-
"lockedKeys": ["meta/slug", "meta/category"],
10-
"include": ["demo/mdx/[locale].mdx"]
11-
}
5+
"targets": ["de"]
126
},
7+
"main": {},
138
"$schema": "https://lingo.dev/schema/i18n.json"
149
}

packages/cli/i18n.lock

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +0,0 @@
1-
version: 1
2-
checksums:
3-
77624f597c2092ea61483d71313398c3:
4-
meta/title: 0a2cc2035f59644733615dd8675b3618
5-
meta/summary: dd9c3e74401afb579e4668b11f11f2ab
6-
meta/author: 5cc899158b9a4b8e2a6abaf26c498786
7-
content/0: 4dfc7a0ee6a9dc089d8a76ad27d38754
8-
content/1: 133929451ee05c91d68b75a15bfe6596
9-
content/2: c89b46f8b2f582e06111a6c96b82e8bf
10-
content/3: 417995a6cdfb7ab127e5431b5b5ef720
11-
content/4: aa9c76dbf759c838e8bd62ae85825e52
12-
content/5: 5704f51f430cbaa8d6452b38c91ea485
13-
content/6: 8db8789e2a220825c9df6c3706bb8389
14-
content/7: 6278ebdd79f1ea718aabeb8e40b5f999
15-
content/8: 37ad0f04abb0e32b88e3bd6b79bb7110
16-
content/9: f3103fdf8e9bd164be82af6c84e17b81
17-
content/10: f030df31e8f24b9890bc9b7d7d387a69
18-
content/11: da348e7e947e0d6054f2b177abc6060b
19-
content/12: 83e15bc1599d243ca5efee3bb6da3152
20-
content/13: 3c176fdcdcc855b44cb42da632312e73
21-
content/14: cecd264ec97755c0100c8bc7d5b0bd70
22-
content/15: 426e9e0abc16c001e04cfb03c9611a6b
23-
content/16: a42f584c463c26a44c5c6d0f6cb8ace0
24-
content/17: e54125a6e2a6fea17309a2c8949e2490
25-
content/18: 79ef1a72bb4e09c347e3a0afae68c18d
26-
content/19: 3feea98e670a946eefdd2fc48d7b99b5
27-
content/20: 51adf33450cab2ef392e93147386647c
28-
content/21: 66ba09daf8e0ae94effa4b98f19ded22
29-
content/22: fed9e643c4a407e5fa118690285a85ed
30-
content/23: 5975348444539ca25e20d05e53b87105
31-
content/24: 7f019348c6dd5d97e746f32741241c55
32-
content/25: 5678250e0f9cff6a5b71f42ff222bd2d

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

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ describe("bucket loaders", () => {
294294
});
295295

296296
it("should save html data", async () => {
297-
const input = `
297+
const input = dedent`
298298
<html>
299299
<head>
300300
<title>My Page</title>
@@ -320,26 +320,16 @@ describe("bucket loaders", () => {
320320
"body/2/3/0": "texto en negrita y ",
321321
"body/2/3/1/0": "texto en cursiva",
322322
};
323-
const expectedOutput = `
324-
<html lang="es">
325-
<head>
326-
<title>Mi Página</title>
327-
<meta name="description" content="Descripción de la página" />
328-
</head>
329-
<body>
330-
texto simple sin etiqueta html
331-
<h1>¡Hola, mundo!</h1>
332-
<p>
333-
Este es un párrafo con un
334-
<a href="https://example.com">enlace</a>
335-
y
336-
<b>
337-
texto en negrita y
338-
<i>texto en cursiva</i>
339-
</b>
340-
</p>
341-
</body>
342-
</html>
323+
const expectedOutput = dedent`
324+
<html lang="es"><head>
325+
<title>Mi Página</title>
326+
<meta name="description" content="Descripción de la página">
327+
</head>
328+
<body>texto simple sin etiqueta html<h1>¡Hola, mundo!</h1>
329+
<p>Este es un párrafo con un <a href="https://example.com">enlace</a> y <b>texto en negrita y <i>texto en cursiva</i></b>
330+
</p>
331+
332+
</body></html>
343333
`.trim();
344334

345335
mockFileOperations(input);
@@ -437,7 +427,14 @@ describe("bucket loaders", () => {
437427

438428
const input = { messages: ["foo", "bar"] };
439429
const payload = { "messages/0": "foo", "messages/1": "bar" };
440-
const expectedOutput = `{\n "messages\": [\"foo\", \"bar\"]\n}`;
430+
const expectedOutput = dedent`
431+
{
432+
"messages": [
433+
"foo",
434+
"bar"
435+
]
436+
}
437+
`.trim();
441438

442439
mockFileOperations(JSON.stringify(input));
443440

@@ -907,7 +904,7 @@ Another paragraph with **bold** and *italic* text.`;
907904
"md-section-0": "# Heading 1",
908905
"md-section-1": "This is a paragraph.",
909906
"md-section-2": "## Heading 2",
910-
"md-section-3": "Another paragraph with **bold** and _italic_ text.",
907+
"md-section-3": "Another paragraph with **bold** and *italic* text.",
911908
};
912909

913910
mockFileOperations(input);

packages/cli/src/cli/loaders/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Z from "zod";
2+
import jsdom from "jsdom";
23
import { bucketTypeSchema } from "@lingo.dev/_spec";
34
import { composeLoaders } from "./_utils";
45
import createJsonLoader from "./json";

packages/cli/src/cli/loaders/mdx2/code-placeholder.spec.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,50 @@ describe("MDX Code Placeholder Loader", () => {
267267
expect(pushed).toBe(md);
268268
});
269269

270+
it("round-trips an image block with surrounding blank lines unchanged", async () => {
271+
const md = dedent`
272+
Text above.
273+
274+
![](https://example.com/img.png)
275+
276+
Text below.
277+
`;
278+
279+
const pulled = await loader.pull("en", md);
280+
const pushed = await loader.push("es", pulled);
281+
expect(pushed).toBe(md);
282+
});
283+
284+
it("round-trips and adds blank lines around an image block when missing", async () => {
285+
const md = dedent`
286+
Text above.
287+
![](https://example.com/img.png)
288+
Text below.
289+
`;
290+
291+
const expected = dedent`
292+
Text above.
293+
294+
![](https://example.com/img.png)
295+
296+
Text below.
297+
`;
298+
299+
const pulled = await loader.pull("en", md);
300+
const pushed = await loader.push("es", pulled);
301+
expect(pushed).toBe(expected);
302+
});
303+
304+
it("keeps image inside blockquote as-is", async () => {
305+
const md = dedent`
306+
> ![](https://example.com/img.png)
307+
`;
308+
309+
const pulled = await loader.pull("en", md);
310+
const pushed = await loader.push("es", pulled);
311+
expect(pushed).toBe(md);
312+
});
313+
270314
it("leaves incomplete fences untouched", async () => {
271315
const md = "```js\nno close";
272316
const pulled = await loader.pull("en", md);
@@ -275,6 +319,87 @@ describe("MDX Code Placeholder Loader", () => {
275319
const pushed = await loader.push("es", pulled);
276320
expect(pushed).toBe(md);
277321
});
322+
323+
// Edge cases for image spacing
324+
325+
it("adds blank line after image when only before exists", async () => {
326+
const md = dedent`
327+
Before.
328+
329+
![alt](https://example.com/i.png)
330+
After.
331+
`;
332+
333+
const expected = dedent`
334+
Before.
335+
336+
![alt](https://example.com/i.png)
337+
338+
After.
339+
`;
340+
341+
const pulled = await loader.pull("en", md);
342+
const pushed = await loader.push("es", pulled);
343+
expect(pushed).toBe(expected);
344+
});
345+
346+
it("adds blank line before image when only after exists", async () => {
347+
const md = dedent`
348+
Before.
349+
![alt](https://example.com/i.png)
350+
351+
After.
352+
`;
353+
354+
const expected = dedent`
355+
Before.
356+
357+
![alt](https://example.com/i.png)
358+
359+
After.
360+
`;
361+
362+
const pulled = await loader.pull("en", md);
363+
const pushed = await loader.push("es", pulled);
364+
expect(pushed).toBe(expected);
365+
});
366+
367+
it("inserts spacing between consecutive images", async () => {
368+
const md = dedent`
369+
![](a.png)
370+
![](b.png)
371+
`;
372+
373+
const expected = dedent`
374+
![](a.png)
375+
376+
![](b.png)
377+
`;
378+
379+
const pulled = await loader.pull("en", md);
380+
const pushed = await loader.push("es", pulled);
381+
expect(pushed).toBe(expected);
382+
});
383+
384+
it("handles image inside JSX component - adds blank lines", async () => {
385+
const md = dedent`
386+
<Wrapper>
387+
![](pic.png)
388+
</Wrapper>
389+
`;
390+
391+
const expected = dedent`
392+
<Wrapper>
393+
394+
![](pic.png)
395+
396+
</Wrapper>
397+
`;
398+
399+
const pulled = await loader.pull("en", md);
400+
const pushed = await loader.push("es", pulled);
401+
expect(pushed).toBe(expected);
402+
});
278403
});
279404

280405
describe("inline code placeholder", () => {

0 commit comments

Comments
 (0)