From 8de7c07dd2970546e5f766f467b40e8bbffac43b Mon Sep 17 00:00:00 2001 From: Partik Date: Fri, 8 Nov 2024 11:44:06 +0530 Subject: [PATCH 1/5] feat: implemented vtt loader Signed-off-by: Partik --- packages/cli/package.json | 1 + packages/cli/src/loaders/index.spec.ts | 146 +++++++++++++++++++++++++ packages/cli/src/loaders/index.ts | 9 ++ packages/cli/src/loaders/vtt.ts | 14 +++ 4 files changed, 170 insertions(+) create mode 100644 packages/cli/src/loaders/vtt.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index cf56eb69..0d3cc70b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -38,6 +38,7 @@ "markdown-it": "^14.1.0", "markdown-it-front-matter": "^0.2.4", "marked": "^14.1.3", + "node-webvtt": "^1.9.4", "object-hash": "^3.0.0", "open": "^10.1.0", "ora": "^8.1.0", diff --git a/packages/cli/src/loaders/index.spec.ts b/packages/cli/src/loaders/index.spec.ts index 651cb00e..dab2c370 100644 --- a/packages/cli/src/loaders/index.spec.ts +++ b/packages/cli/src/loaders/index.spec.ts @@ -859,6 +859,152 @@ user.password=Contraseña ); }); }); + + describe('vtt bucket loader', () => { + it('should load complex vtt data', async () => { + setupFileMocks(); + + // Complex VTT input + const input = ` + WEBVTT + +00:00:00.000 --> 00:00:01.000 +Hello world! + +00:00:30.000 --> 00:00:31.000 align:start line:0% +This is a subtitle + +00:01:00.000 --> 00:01:01.000 +Foo + +00:01:50.000 --> 00:01:51.000 +Bar + `.trim(); + + const expectedOutput ={ + "0": { + "end": 1, + "identifier": "", + "start": 0, + "styles": "", + "text": "Hello world!", + }, + "1": { + "end": 31, + "identifier": "", + "start": 30, + "styles": "align:start line:0%", + "text": "This is a subtitle", + }, + "2": { + "end": 61, + "identifier": "", + "start": 60, + "styles": "", + "text": "Foo", + }, + "3": { + "end": 111, + "identifier": "", + "start": 110, + "styles": "", + "text": "Bar", + }, + } + + mockFileOperations(input); + + const vttLoader = createBucketLoader('vtt', 'i18n/[locale].vtt'); + vttLoader.setDefaultLocale('en'); + const data = await vttLoader.pull('en'); + + expect(data).toEqual(expectedOutput); + }); + + it('should save complex vtt data', async () => { + setupFileMocks(); + const input = ` + WEBVTT + +00:00:00.000 --> 00:00:01.000 +Hello world! + +00:00:30.000 --> 00:00:31.000 align:start line:0% +This is a subtitle + +00:01:00.000 --> 00:01:01.000 +Foo + +00:01:50.000 --> 00:01:51.000 +Bar + `.trim(); + + + // Complex VTT payload to save + const payload = [ + { + end: 1, + identifier: "", + start: 0, + styles: "", + text: "¡Hola mundo!", + }, + { + end: 31, + identifier: "", + start: 30, + styles: "align:start line:0%", + text: "Este es un subtítulo", + }, + { + end: 61, + identifier: "", + start: 60, + styles: "", + text: "Foo", + }, + { + end: 111, + identifier: "", + start: 110, + styles: "", + text: "Bar", + }, + ]; + + + const expectedOutput = ` + WEBVTT + + 00:00:00.000 --> 00:00:01.000 + ¡Hola mundo! + + 00:00:30.000 --> 00:00:31.000 align:start line:0% + Este es un subtítulo + + 00:01:00.000 --> 00:01:01.000 + Foo + + 00:01:50.000 --> 00:01:51.000 + Bar + `.trim(); + + mockFileOperations(input); // Initial empty VTT + + const vttLoader = createBucketLoader('vtt', 'i18n/[locale].vtt'); + vttLoader.setDefaultLocale('en'); + await vttLoader.pull('en'); // Load initial data + + await vttLoader.push('es', payload); + + expect(fs.writeFile).toHaveBeenCalledWith( + 'i18n/es.vtt', + expectedOutput, + { encoding: 'utf-8', flag: 'w' }, + ); + }); + }); + }); // Helper functions diff --git a/packages/cli/src/loaders/index.ts b/packages/cli/src/loaders/index.ts index d59b5b2a..e6bcef8e 100644 --- a/packages/cli/src/loaders/index.ts +++ b/packages/cli/src/loaders/index.ts @@ -19,6 +19,7 @@ import createXcodeXcstringsLoader from './xcode-xcstrings'; import createPrettierLoader from './prettier'; import createUnlocalizableLoader from './unlocalizable'; import createPoLoader from './po'; +import createVttLoader from './vtt'; export default function createBucketLoader( bucketType: Z.infer, @@ -109,5 +110,13 @@ export default function createBucketLoader( createFlatLoader(), createUnlocalizableLoader(), ); + case 'vtt': return composeLoaders( + createTextFileLoader(bucketPathPattern), + // createPrettierLoader({ parser: 'json' }), + // createJsonLoader(), + createVttLoader(), + // createFlatLoader(), + createUnlocalizableLoader(), + ) } } diff --git a/packages/cli/src/loaders/vtt.ts b/packages/cli/src/loaders/vtt.ts new file mode 100644 index 00000000..3477da8b --- /dev/null +++ b/packages/cli/src/loaders/vtt.ts @@ -0,0 +1,14 @@ +import webvtt from 'node-webvtt'; +import { ILoader } from "./_types"; +import { createLoader } from './_utils'; + +export default function createVttLoader(): ILoader> { + return createLoader({ + async pull(locale, input) { + return webvtt.parse(input)?.cues || {}; + }, + async push(locale, payload) { + return webvtt.compile(payload); + } + }); +} From 5819c7523fbf4397ebe03ef34a0788250584d1f9 Mon Sep 17 00:00:00 2001 From: Partik Date: Sun, 24 Nov 2024 13:32:21 +0530 Subject: [PATCH 2/5] chore: changesets Signed-off-by: Partik --- .changeset/little-lizards-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/little-lizards-brake.md diff --git a/.changeset/little-lizards-brake.md b/.changeset/little-lizards-brake.md new file mode 100644 index 00000000..3c677a0b --- /dev/null +++ b/.changeset/little-lizards-brake.md @@ -0,0 +1,5 @@ +--- +"@replexica/cli": minor +--- + +feat: implemented the vtt loader From c04fa08f5a1cbe834f22dc64a5f86c62ac889a4e Mon Sep 17 00:00:00 2001 From: Partik Date: Sun, 24 Nov 2024 13:34:16 +0530 Subject: [PATCH 3/5] chore: deleted comments and updated versions Signed-off-by: Partik --- packages/cli/package.json | 2 +- packages/cli/src/loaders/index.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 1888d81c..4bc36205 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -37,7 +37,7 @@ "lodash": "^4.17.21", "markdown-it": "^14.1.0", "markdown-it-front-matter": "^0.2.4", - "marked": "^14.1.3", + "marked": "^15.0.0", "node-webvtt": "^1.9.4", "object-hash": "^3.0.0", "open": "^10.1.0", diff --git a/packages/cli/src/loaders/index.ts b/packages/cli/src/loaders/index.ts index b63cab83..01d979b8 100644 --- a/packages/cli/src/loaders/index.ts +++ b/packages/cli/src/loaders/index.ts @@ -115,7 +115,6 @@ export default function createBucketLoader( case 'vtt': return composeLoaders( createTextFileLoader(bucketPathPattern), createVttLoader(), - // createFlatLoader(), createUnlocalizableLoader(), ) case 'xml': return composeLoaders( From fb32b7bea927ebd765ccaa397b2b3c9540bb25ae Mon Sep 17 00:00:00 2001 From: Partik Date: Sun, 24 Nov 2024 21:13:14 +0530 Subject: [PATCH 4/5] chore: action fix Signed-off-by: Partik --- pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca268e96..19f5d3cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,8 +150,8 @@ importers: specifier: ^0.2.4 version: 0.2.4 marked: - specifier: ^14.1.3 - version: 14.1.4 + specifier: ^15.0.0 + version: 15.0.2 node-webvtt: specifier: ^1.9.4 version: 1.9.4 @@ -2455,8 +2455,8 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true - marked@14.1.4: - resolution: {integrity: sha512-vkVZ8ONmUdPnjCKc5uTRvmkRbx4EAi2OkTOXmfTDhZz3OFqMNBM1oTTWwTr4HY4uAEojhzPf+Fy8F1DWa3Sndg==} + marked@15.0.2: + resolution: {integrity: sha512-85RUkoYKIVB21PbMKrnD6aCl9ws+XKEyhJNMbLn206NyD3jbBo7Ec7Wi4Jrsn4dV1a2ng7K/jfkmIN0DNoS41w==} engines: {node: '>= 18'} hasBin: true @@ -5688,7 +5688,7 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - marked@14.1.4: {} + marked@15.0.2: {} mdurl@2.0.0: {} From 667b0d32000f39399b7f2bb16ef4ad67a34c7d30 Mon Sep 17 00:00:00 2001 From: Partik Date: Sat, 18 Jan 2025 19:44:40 +0530 Subject: [PATCH 5/5] chore: formatted code Signed-off-by: Partik --- packages/cli/src/loaders/index.spec.ts | 89 +++++++++++++------------- packages/cli/src/loaders/vtt.ts | 29 +++++---- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/packages/cli/src/loaders/index.spec.ts b/packages/cli/src/loaders/index.spec.ts index dd8494c3..3d5c6432 100644 --- a/packages/cli/src/loaders/index.spec.ts +++ b/packages/cli/src/loaders/index.spec.ts @@ -915,10 +915,10 @@ user.password=Contraseña }); }); - describe('vtt bucket loader', () => { - it('should load complex vtt data', async () => { + describe("vtt bucket loader", () => { + it("should load complex vtt data", async () => { setupFileMocks(); - + const input = ` WEBVTT @@ -934,24 +934,24 @@ Foo 00:01:50.000 --> 00:01:51.000 Bar `.trim(); - - const expectedOutput ={ + + const expectedOutput = { "0#0-1#": "Hello world!", "1#30-31#": "This is a subtitle", "2#60-61#": "Foo", "3#110-111#": "Bar", - } - + }; + mockFileOperations(input); - - const vttLoader = createBucketLoader('vtt', 'i18n/[locale].vtt'); - vttLoader.setDefaultLocale('en'); - const data = await vttLoader.pull('en'); - + + const vttLoader = createBucketLoader("vtt", "i18n/[locale].vtt"); + vttLoader.setDefaultLocale("en"); + const data = await vttLoader.pull("en"); + expect(data).toEqual(expectedOutput); }); - - it('should save complex vtt data', async () => { + + it("should save complex vtt data", async () => { setupFileMocks(); const input = ` WEBVTT @@ -968,17 +968,17 @@ Foo 00:01:50.000 --> 00:01:51.000 Bar `.trim(); - -// // Complex VTT payload to save - const payload ={ + + // // Complex VTT payload to save + const payload = { "0#0-1#": "¡Hola mundo!", "1#30-31#": "Este es un subtítulo", "2#60-61#": "Foo", "3#110-111#": "Bar", - } - - - const expectedOutput = ` + }; + + const expectedOutput = + ` WEBVTT 00:00:00.000 --> 00:00:01.000 @@ -991,26 +991,25 @@ Este es un subtítulo Foo 00:01:50.000 --> 00:01:51.000 -Bar`.trim()+"\n"; - +Bar`.trim() + "\n"; + mockFileOperations(input); - - const vttLoader = createBucketLoader('vtt', 'i18n/[locale].vtt'); - vttLoader.setDefaultLocale('en'); - await vttLoader.pull('en'); - - await vttLoader.push('es', payload); - - expect(fs.writeFile).toHaveBeenCalledWith( - 'i18n/es.vtt', - expectedOutput, - { encoding: 'utf-8', flag: 'w' }, - ); - }) -}) - - describe('XML bucket loader', () => { - it('should load XML data', async () => { + + const vttLoader = createBucketLoader("vtt", "i18n/[locale].vtt"); + vttLoader.setDefaultLocale("en"); + await vttLoader.pull("en"); + + await vttLoader.push("es", payload); + + expect(fs.writeFile).toHaveBeenCalledWith("i18n/es.vtt", expectedOutput, { + encoding: "utf-8", + flag: "w", + }); + }); + }); + + describe("XML bucket loader", () => { + it("should load XML data", async () => { setupFileMocks(); const input = ` @@ -1034,11 +1033,11 @@ Bar`.trim()+"\n"; }; mockFileOperations(input); - - const xmlLoader = createBucketLoader('xml', 'i18n/[locale].xml'); - xmlLoader.setDefaultLocale('en'); - const data = await xmlLoader.pull('en'); - + + const xmlLoader = createBucketLoader("xml", "i18n/[locale].xml"); + xmlLoader.setDefaultLocale("en"); + const data = await xmlLoader.pull("en"); + expect(data).toEqual(expectedOutput); }); diff --git a/packages/cli/src/loaders/vtt.ts b/packages/cli/src/loaders/vtt.ts index c3f61d28..9e51003b 100644 --- a/packages/cli/src/loaders/vtt.ts +++ b/packages/cli/src/loaders/vtt.ts @@ -1,17 +1,19 @@ -import webvtt from 'node-webvtt'; +import webvtt from "node-webvtt"; import { ILoader } from "./_types"; -import { createLoader } from './_utils'; +import { createLoader } from "./_utils"; -export default function createVttLoader(): ILoader> { +export default function createVttLoader(): ILoader< + string, + Record +> { return createLoader({ async pull(locale, input) { - const vtt = webvtt.parse(input)?.cues; if (Object.keys(vtt).length === 0) { return {}; } else { - return vtt.reduce((result:any, cue:any, index:number) => { - const key = `${index}#${cue.start}-${cue.end}#${cue.identifier}` + return vtt.reduce((result: any, cue: any, index: number) => { + const key = `${index}#${cue.start}-${cue.end}#${cue.identifier}`; result[key] = cue.text; return result; }, {}); @@ -19,10 +21,9 @@ export default function createVttLoader(): ILoader> }, async push(locale, payload) { const output = Object.entries(payload).map(([key, text]) => { - - const [id, timeRange, identifier] = key.split('#'); - const [startTime, endTime] = timeRange.split('-'); - + const [id, timeRange, identifier] = key.split("#"); + const [startTime, endTime] = timeRange.split("-"); + return { end: Number(endTime), identifier: identifier, @@ -33,14 +34,14 @@ export default function createVttLoader(): ILoader> }); console.log(payload, output); - + const input = { valid: true, strict: true, - cues: output - } + cues: output, + }; return webvtt.compile(input); - } + }, }); }