From 3a4c00f0427acc1f9c8822ea7ee3c47410900247 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 21:54:43 +0200 Subject: [PATCH 01/10] feat(gettext): add no-location and deterministic POT options; support msgcat options and header normalization --- packages/vite-plugin-gettext/src/types.ts | 12 ++ packages/vite-plugin-gettext/src/xgettext.ts | 117 ++++++++++++++++++- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/packages/vite-plugin-gettext/src/types.ts b/packages/vite-plugin-gettext/src/types.ts index d0f030b..28fe320 100644 --- a/packages/vite-plugin-gettext/src/types.ts +++ b/packages/vite-plugin-gettext/src/types.ts @@ -13,6 +13,8 @@ export interface XGettextPluginOptions { keywords?: string[]; /** Additional options to pass to xgettext command */ xgettextOptions?: string[]; + /** Additional options to pass to msgcat when combining POT files */ + msgcatOptions?: string[]; /** Enable verbose logging */ verbose?: boolean; /** Automatically update PO files after POT changes */ @@ -25,6 +27,16 @@ export interface XGettextPluginOptions { msgidBugsAddress?: string; /** Copyright holder to set in the POT file */ copyrightHolder?: string; + /** If true, do not include source reference locations in POT/PO files */ + noLocation?: boolean; + /** If true, attempt to make output reproducible (stable timestamps/order) */ + deterministic?: boolean; + /** When deterministic is true, use this SOURCE_DATE_EPOCH (seconds since epoch). Defaults to 0. */ + sourceDateEpoch?: number; + /** Optionally force a fixed POT-Creation-Date header value (e.g. '1970-01-01 00:00+0000') */ + fixedCreationDate?: string; + /** If true, sort the output messages for stable diffs (passed to msgcat) */ + sortOutput?: boolean; } /** diff --git a/packages/vite-plugin-gettext/src/xgettext.ts b/packages/vite-plugin-gettext/src/xgettext.ts index 3894b48..883cc96 100644 --- a/packages/vite-plugin-gettext/src/xgettext.ts +++ b/packages/vite-plugin-gettext/src/xgettext.ts @@ -188,6 +188,10 @@ async function extractStrings( "--add-comments", ]; + if (options.noLocation) { + args.push("--no-location"); + } + // Add bug report address if specified if (options.msgidBugsAddress) { args.push("--msgid-bugs-address=" + options.msgidBugsAddress); @@ -229,6 +233,11 @@ async function extractStrings( break; } + // Allow custom xgettext options + if (options.xgettextOptions && options.xgettextOptions.length > 0) { + args.push(...options.xgettextOptions); + } + if (verbose) { console.log( `[${pluginName}] Running xgettext for ${group}:`, @@ -236,7 +245,17 @@ async function extractStrings( ); } - await execa("xgettext", args); + // Enforce deterministic timestamps if requested + const env = { ...process.env }; + if (options.deterministic) { + const epoch = + typeof options.sourceDateEpoch === "number" + ? options.sourceDateEpoch + : 0; + env.SOURCE_DATE_EPOCH = String(epoch); + } + + await execa("xgettext", args, { env }); // Check if file exists before adding to tempPotFiles try { @@ -256,8 +275,28 @@ async function extractStrings( // Combine all temporary POT files using msgcat if (tempPotFiles.length > 0) { - const msgcatArgs = ["--use-first", "-o", output, ...tempPotFiles]; - await execa("msgcat", msgcatArgs); + const msgcatArgs = ["--use-first"]; + if (options.noLocation) { + msgcatArgs.push("--no-location"); + } + if (options.sortOutput) { + msgcatArgs.push("--sort-output"); + } + if (options.msgcatOptions && options.msgcatOptions.length > 0) { + msgcatArgs.push(...options.msgcatOptions); + } + msgcatArgs.push("-o", output, ...tempPotFiles); + + const env = { ...process.env }; + if (options.deterministic) { + const epoch = + typeof options.sourceDateEpoch === "number" + ? options.sourceDateEpoch + : 0; + env.SOURCE_DATE_EPOCH = String(epoch); + } + + await execa("msgcat", msgcatArgs, { env }); // Clean up temporary files for (const tempFile of tempPotFiles) { @@ -268,8 +307,44 @@ async function extractStrings( } } + // Optionally normalize POT-Creation-Date header to a fixed value + if (options.fixedCreationDate || options.deterministic) { + try { + const normalizedDate = options.fixedCreationDate + ? options.fixedCreationDate + : formatSourceDateEpoch( + typeof options.sourceDateEpoch === "number" + ? options.sourceDateEpoch + : 0 + ); + const content = await fs.readFile(output, "utf-8"); + const replaced = content.replace( + /^"POT-Creation-Date: .*\\n"$/m, + `"POT-Creation-Date: ${normalizedDate}\\n"` + ); + if (replaced !== content) { + await fs.writeFile(output, replaced); + if (verbose) { + console.log( + `[${pluginName}] Normalized POT-Creation-Date to '${normalizedDate}'` + ); + } + } + } catch (e) { + console.warn( + `[${pluginName}] Failed to normalize POT-Creation-Date header:`, + e + ); + } + } + if (options.autoUpdatePo) { - await updatePoFiles(options.output, pluginName, options.verbose || false); + await updatePoFiles( + options.output, + pluginName, + options.verbose || false, + options + ); } } catch (error) { throw new Error(`Failed to extract translations: ${error}`); @@ -279,7 +354,8 @@ async function extractStrings( async function updatePoFiles( potFile: string, pluginName: string, - verbose: boolean + verbose: boolean, + options: XGettextPluginOptions ) { try { const linguasPath = path.join(path.dirname(potFile), "LINGUAS"); @@ -292,13 +368,42 @@ async function updatePoFiles( if (verbose) { console.log(`[${pluginName}] Updating ${poFile}`); } - await execa("msgmerge", ["--update", "--backup=none", poFile, potFile]); + const args = ["--update", "--backup=none"] as string[]; + if (options.noLocation) { + args.push("--no-location"); + } + + const env = { ...process.env }; + if (options.deterministic) { + const epoch = + typeof options.sourceDateEpoch === "number" + ? options.sourceDateEpoch + : 0; + env.SOURCE_DATE_EPOCH = String(epoch); + } + + await execa("msgmerge", [...args, poFile, potFile], { env }); } } catch (error) { console.error(`[${pluginName}] Error updating PO files:`, error); } } +/** + * Formats a date in gettext header format using an epoch (seconds) in UTC timezone + * Example output: 1970-01-01 00:00+0000 + */ +function formatSourceDateEpoch(epochSeconds: number): string { + const date = new Date(epochSeconds * 1000); + const pad = (n: number) => String(n).padStart(2, "0"); + const year = date.getUTCFullYear(); + const month = pad(date.getUTCMonth() + 1); + const day = pad(date.getUTCDate()); + const hours = pad(date.getUTCHours()); + const minutes = pad(date.getUTCMinutes()); + return `${year}-${month}-${day} ${hours}:${minutes}+0000`; +} + /** * Finds the first existing metainfo.its file from installed gettext versions * @returns The path to the metainfo.its file if found, otherwise undefined From 72048cbb6d8f032a80a67a36b7d404bb8bf24d0d Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 21:54:59 +0200 Subject: [PATCH 02/10] docs(gettext): document no-location, deterministic, sortOutput and msgcatOptions with example --- packages/vite-plugin-gettext/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/vite-plugin-gettext/README.md b/packages/vite-plugin-gettext/README.md index c31195a..9dd8459 100644 --- a/packages/vite-plugin-gettext/README.md +++ b/packages/vite-plugin-gettext/README.md @@ -44,6 +44,11 @@ export default defineConfig({ output: "po/messages.pot", domain: "myapp", keywords: ["_", "gettext", "ngettext"], + // Stabilize POT output for CI and avoid noisy diffs + noLocation: true, + deterministic: true, + sourceDateEpoch: 0, + sortOutput: true, verbose: true, }), // Compile PO files to MO format (standard approach) @@ -94,6 +99,12 @@ export default defineConfig({ - `keywords`: Keywords to look for when extracting strings (defaults to ['_', 'gettext', 'ngettext']) - `xgettextOptions`: Additional options to pass to xgettext command - `verbose`: Enable verbose logging +- `msgcatOptions`: Additional options to pass to msgcat when combining POT files +- `noLocation`: If true, omit source reference locations from POT/PO (passes `--no-location`) +- `deterministic`: If true, enable reproducible output (sets `SOURCE_DATE_EPOCH` and stable headers) +- `sourceDateEpoch`: Epoch seconds for reproducible timestamps (default: 0) +- `fixedCreationDate`: Force a fixed `POT-Creation-Date` header string +- `sortOutput`: Sort output messages for stable diffs (passes `--sort-output` to msgcat) ### gettextPlugin Options From 72dbe9357d31ec2d6a6533e0bdce98acc31aef67 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 21:59:37 +0200 Subject: [PATCH 03/10] chore: Bump versions of vite-plugin-blueprint and vite-plugin-gettext to 0.2.3 --- packages/vite-plugin-blueprint/package.json | 2 +- packages/vite-plugin-gettext/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-blueprint/package.json b/packages/vite-plugin-blueprint/package.json index fca8227..1886dbd 100644 --- a/packages/vite-plugin-blueprint/package.json +++ b/packages/vite-plugin-blueprint/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-blueprint", - "version": "0.2.2", + "version": "0.2.3", "description": "Vite plugin for compiling Gnome Blueprint files", "main": "dist/index.js", "type": "module", diff --git a/packages/vite-plugin-gettext/package.json b/packages/vite-plugin-gettext/package.json index 65328a5..4b0f5d0 100644 --- a/packages/vite-plugin-gettext/package.json +++ b/packages/vite-plugin-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-gettext", - "version": "0.2.2", + "version": "0.2.3", "description": "Vite plugin for compiling Gettext PO files", "main": "dist/index.js", "type": "module", From 9e31752095313e295745e89947714cded00b0012 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:01:16 +0200 Subject: [PATCH 04/10] docs(rules): condense commit best practices; add conversation-driven narratives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: Improve commit quality and make history a resumable work log. What: Simplified rules, removed duplicates, clarified validation and consistency, added "Conversation-Driven Commit Narratives" with template. Progress: 1/1 complete — Next: adopt template in future commits. --- .cursor/rules/git-commit-best-practices.mdc | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .cursor/rules/git-commit-best-practices.mdc diff --git a/.cursor/rules/git-commit-best-practices.mdc b/.cursor/rules/git-commit-best-practices.mdc new file mode 100644 index 0000000..70c7678 --- /dev/null +++ b/.cursor/rules/git-commit-best-practices.mdc @@ -0,0 +1,45 @@ +--- +alwaysApply: false +--- + +You are a meticulous developer who commits code frequently with clear, atomic commits following conventional commit standards. + +## Core Principles + +- **No unprompted commits**: Never commit without explicit user permission. +- **Working state only**: Commit only passing, functional code. +- **Atomic and conventional**: Use `[scope]: ` (feat, fix, docs, refactor, test, chore, etc.). Subjects in imperative mood; add scope when helpful; keep subjects concise (≈50 chars when possible). +- **Milestone commits**: Prefer small, logical waypoints that close a loop (e.g., add API + wire + basic test) over mixing unrelated changes. Each commit should be self-contained and review-friendly. +- **Follow established style**: Match existing commit patterns and platform prefixes (e.g., "Android:", "Web:", "Gnome:") when applicable. + +## Validation Before Commit + +- Run `yarn check` (type checking across all packages). +- Run `yarn build` (build all packages to catch compilation errors). +- Fix all errors and warnings before committing. + +## Consistency With History + +- Inspect recent history to align with project norms: + - `git log --oneline -10 | cat` + - Mirror commit types, scoping, tone, and prefixes used in the repo. + +## Conversation-Driven Commit Narratives + +Use the immediately preceding conversation to extract and record the intent behind changes so commits double as a resumable work log. + +- **Derive from context**: Pull the problem statement, motivation, and concrete goal from the prior discussion. If unclear, restate briefly in the first body paragraph. +- **Structure for traceability**: + - **Why**: Reason/motivation (1–2 sentences). + - **What**: Concise description of the change and scope. + - **Progress/Next**: Current status and the very next step (e.g., "Progress: 2/5; Next: implement validation"). +- **Ensure resumability**: Each commit should make it obvious what was done last and what to do next, enabling work to resume from history alone. +- **Optimize discoverability**: Write subjects/bodies so `git log --oneline` reveals the last area of work and progress toward the goal. + +Example body template: + +```text +Why: +What: +Progress: — Next: +``` From 374e441716fb5f6663857d5e49daa7c4b2a90657 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:09:15 +0200 Subject: [PATCH 05/10] chore(pkg): add repository/homepage/bugs links for GitHub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: ensure correct metadata for npm and linkbacks to project. What: add repository, bugs, homepage fields to root and both plugin packages. Progress: 1/1 complete — Next: publish when ready. --- package.json | 8 ++++++++ packages/vite-plugin-blueprint/package.json | 8 ++++++++ packages/vite-plugin-gettext/package.json | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/package.json b/package.json index 4588026..e6431a0 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,14 @@ "private": true, "author": "Pascal Garber ", "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/gjsify/vite.git" + }, + "bugs": { + "url": "https://github.com/gjsify/vite/issues" + }, + "homepage": "https://github.com/gjsify/vite#readme", "scripts": { "build": "yarn workspaces foreach -v --all run build", "check": "yarn workspaces foreach -v --all run check", diff --git a/packages/vite-plugin-blueprint/package.json b/packages/vite-plugin-blueprint/package.json index 1886dbd..136ca49 100644 --- a/packages/vite-plugin-blueprint/package.json +++ b/packages/vite-plugin-blueprint/package.json @@ -12,6 +12,14 @@ }, "author": "Pascal Garber ", "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/gjsify/vite.git" + }, + "bugs": { + "url": "https://github.com/gjsify/vite/issues" + }, + "homepage": "https://github.com/gjsify/vite#readme", "devDependencies": { "@types/node": "^24.3.0", "typescript": "^5.9.2", diff --git a/packages/vite-plugin-gettext/package.json b/packages/vite-plugin-gettext/package.json index 4b0f5d0..2412d71 100644 --- a/packages/vite-plugin-gettext/package.json +++ b/packages/vite-plugin-gettext/package.json @@ -12,6 +12,14 @@ }, "author": "Pascal Garber ", "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/gjsify/vite.git" + }, + "bugs": { + "url": "https://github.com/gjsify/vite/issues" + }, + "homepage": "https://github.com/gjsify/vite#readme", "devDependencies": { "@types/gettext-parser": "^8.0.0", "@types/node": "^24.3.0", From cc6d515e9929c8fcf92613d654dd10f3d3eb640b Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:11:18 +0200 Subject: [PATCH 06/10] chore(pkg): point homepage to package subpaths on GitHub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: provide direct package landing pages for users. What: update homepage URLs in blueprint/gettext package.json to tree/main package paths. Progress: 1/1 complete — Next: push branch. --- packages/vite-plugin-blueprint/package.json | 2 +- packages/vite-plugin-gettext/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-blueprint/package.json b/packages/vite-plugin-blueprint/package.json index 136ca49..c6e825e 100644 --- a/packages/vite-plugin-blueprint/package.json +++ b/packages/vite-plugin-blueprint/package.json @@ -19,7 +19,7 @@ "bugs": { "url": "https://github.com/gjsify/vite/issues" }, - "homepage": "https://github.com/gjsify/vite#readme", + "homepage": "https://github.com/gjsify/vite/tree/main/packages/vite-plugin-blueprint", "devDependencies": { "@types/node": "^24.3.0", "typescript": "^5.9.2", diff --git a/packages/vite-plugin-gettext/package.json b/packages/vite-plugin-gettext/package.json index 2412d71..cc98f70 100644 --- a/packages/vite-plugin-gettext/package.json +++ b/packages/vite-plugin-gettext/package.json @@ -19,7 +19,7 @@ "bugs": { "url": "https://github.com/gjsify/vite/issues" }, - "homepage": "https://github.com/gjsify/vite#readme", + "homepage": "https://github.com/gjsify/vite/tree/main/packages/vite-plugin-gettext", "devDependencies": { "@types/gettext-parser": "^8.0.0", "@types/node": "^24.3.0", From 6eea7bc05095b75433cf55b92812b728cd2dfe6a Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:50:48 +0200 Subject: [PATCH 07/10] feat(gettext): add preserveCreationDate to reuse POT Creation-Date MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: Reduce noisy diffs and stabilize headers by keeping existing POT Creation-Date when available, while supporting deterministic builds. What: Add preserveCreationDate option; read previous POT to capture existing Creation-Date; normalize header with precedence: fixedCreationDate > preserveCreationDate > deterministic epoch. Progress: 1/1 complete — Next: document option and usage in README. --- packages/vite-plugin-gettext/src/types.ts | 2 + packages/vite-plugin-gettext/src/xgettext.ts | 79 +++++++++++++++----- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/packages/vite-plugin-gettext/src/types.ts b/packages/vite-plugin-gettext/src/types.ts index 28fe320..df2b4ba 100644 --- a/packages/vite-plugin-gettext/src/types.ts +++ b/packages/vite-plugin-gettext/src/types.ts @@ -35,6 +35,8 @@ export interface XGettextPluginOptions { sourceDateEpoch?: number; /** Optionally force a fixed POT-Creation-Date header value (e.g. '1970-01-01 00:00+0000') */ fixedCreationDate?: string; + /** If true, preserve the existing POT-Creation-Date from the current POT file if present */ + preserveCreationDate?: boolean; /** If true, sort the output messages for stable diffs (passed to msgcat) */ sortOutput?: boolean; } diff --git a/packages/vite-plugin-gettext/src/xgettext.ts b/packages/vite-plugin-gettext/src/xgettext.ts index 883cc96..443db5e 100644 --- a/packages/vite-plugin-gettext/src/xgettext.ts +++ b/packages/vite-plugin-gettext/src/xgettext.ts @@ -163,6 +163,23 @@ async function extractStrings( const outputDir = path.dirname(output); await ensureDirectory(outputDir); + // Read existing POT-Creation-Date from previous POT if present (for preservation) + let prevPotCreationDate: string | undefined; + try { + const existingPot = await fs.readFile(output, "utf-8"); + const m = existingPot.match(/"POT-Creation-Date:\s*([^\n]+)\\n"/); + if (m && m[1]) { + prevPotCreationDate = m[1]; + if (verbose) { + console.log( + `[${pluginName}] Found previous POT-Creation-Date '${prevPotCreationDate}'` + ); + } + } + } catch { + // No previous POT available + } + // Generate grouped POTFILES const potFiles = await generatePotfiles( files, @@ -307,27 +324,49 @@ async function extractStrings( } } - // Optionally normalize POT-Creation-Date header to a fixed value - if (options.fixedCreationDate || options.deterministic) { + // Optionally normalize POT-Creation-Date header to a fixed or preserved value + if (options.fixedCreationDate || options.preserveCreationDate || options.deterministic) { try { - const normalizedDate = options.fixedCreationDate - ? options.fixedCreationDate - : formatSourceDateEpoch( - typeof options.sourceDateEpoch === "number" - ? options.sourceDateEpoch - : 0 - ); - const content = await fs.readFile(output, "utf-8"); - const replaced = content.replace( - /^"POT-Creation-Date: .*\\n"$/m, - `"POT-Creation-Date: ${normalizedDate}\\n"` - ); - if (replaced !== content) { - await fs.writeFile(output, replaced); - if (verbose) { - console.log( - `[${pluginName}] Normalized POT-Creation-Date to '${normalizedDate}'` - ); + let normalizedDate: string | undefined = undefined; + + if (options.fixedCreationDate) { + normalizedDate = options.fixedCreationDate; + } else if (options.preserveCreationDate) { + try { + const existing = await fs.readFile(output, "utf-8"); + const match = existing.match(/"POT-Creation-Date:\s*([^\n]+)\\n"/); + if (match && match[1]) { + normalizedDate = match[1]; + if (verbose) { + console.log( + `[${pluginName}] Preserving existing POT-Creation-Date '${normalizedDate}'` + ); + } + } + } catch { + // If file doesn't exist yet, fall back below + } + } + + if (!normalizedDate && options.deterministic) { + normalizedDate = formatSourceDateEpoch( + typeof options.sourceDateEpoch === "number" ? options.sourceDateEpoch : 0 + ); + } + + if (normalizedDate) { + const content = await fs.readFile(output, "utf-8"); + const replaced = content.replace( + /^"POT-Creation-Date: .*\\n"$/m, + `"POT-Creation-Date: ${normalizedDate}\\n"` + ); + if (replaced !== content) { + await fs.writeFile(output, replaced); + if (verbose) { + console.log( + `[${pluginName}] Normalized POT-Creation-Date to '${normalizedDate}'` + ); + } } } } catch (e) { From 4d8d4042115d1d848106739632d6764c78cb9f03 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:52:35 +0200 Subject: [PATCH 08/10] chore: Bump versions of vite-plugin-blueprint and vite-plugin-gettext to 0.2.4; update dependencies for @types/node and vite --- packages/vite-plugin-blueprint/package.json | 6 +-- packages/vite-plugin-gettext/package.json | 6 +-- yarn.lock | 45 +++++++++++++++------ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/packages/vite-plugin-blueprint/package.json b/packages/vite-plugin-blueprint/package.json index c6e825e..52b5e9f 100644 --- a/packages/vite-plugin-blueprint/package.json +++ b/packages/vite-plugin-blueprint/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-blueprint", - "version": "0.2.3", + "version": "0.2.4", "description": "Vite plugin for compiling Gnome Blueprint files", "main": "dist/index.js", "type": "module", @@ -21,9 +21,9 @@ }, "homepage": "https://github.com/gjsify/vite/tree/main/packages/vite-plugin-blueprint", "devDependencies": { - "@types/node": "^24.3.0", + "@types/node": "^24.3.1", "typescript": "^5.9.2", - "vite": "^7.1.2" + "vite": "^7.1.5" }, "peerDependencies": { "vite": "*" diff --git a/packages/vite-plugin-gettext/package.json b/packages/vite-plugin-gettext/package.json index cc98f70..b99651b 100644 --- a/packages/vite-plugin-gettext/package.json +++ b/packages/vite-plugin-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-gettext", - "version": "0.2.3", + "version": "0.2.4", "description": "Vite plugin for compiling Gettext PO files", "main": "dist/index.js", "type": "module", @@ -22,9 +22,9 @@ "homepage": "https://github.com/gjsify/vite/tree/main/packages/vite-plugin-gettext", "devDependencies": { "@types/gettext-parser": "^8.0.0", - "@types/node": "^24.3.0", + "@types/node": "^24.3.1", "typescript": "^5.9.2", - "vite": "^7.1.2" + "vite": "^7.1.5" }, "peerDependencies": { "vite": "*" diff --git a/yarn.lock b/yarn.lock index b6c22cf..81b875d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -191,11 +191,11 @@ __metadata: version: 0.0.0-use.local resolution: "@gjsify/vite-plugin-blueprint@workspace:packages/vite-plugin-blueprint" dependencies: - "@types/node": "npm:^24.3.0" + "@types/node": "npm:^24.3.1" execa: "npm:^9.6.0" minify-xml: "npm:^4.5.2" typescript: "npm:^5.9.2" - vite: "npm:^7.1.2" + vite: "npm:^7.1.5" peerDependencies: vite: "*" languageName: unknown @@ -206,12 +206,12 @@ __metadata: resolution: "@gjsify/vite-plugin-gettext@workspace:packages/vite-plugin-gettext" dependencies: "@types/gettext-parser": "npm:^8.0.0" - "@types/node": "npm:^24.3.0" + "@types/node": "npm:^24.3.1" execa: "npm:^9.6.0" fast-glob: "npm:^3.3.3" gettext-parser: "npm:^8.0.0" typescript: "npm:^5.9.2" - vite: "npm:^7.1.2" + vite: "npm:^7.1.5" peerDependencies: vite: "*" languageName: unknown @@ -475,7 +475,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^24.3.0": +"@types/node@npm:*": version: 24.3.0 resolution: "@types/node@npm:24.3.0" dependencies: @@ -484,6 +484,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^24.3.1": + version: 24.3.1 + resolution: "@types/node@npm:24.3.1" + dependencies: + undici-types: "npm:~7.10.0" + checksum: 10c0/99b86fc32294fcd61136ca1f771026443a1e370e9f284f75e243b29299dd878e18c193deba1ce29a374932db4e30eb80826e1049b9aad02d36f5c30b94b6f928 + languageName: node + linkType: hard + "@types/readable-stream@npm:*": version: 4.0.21 resolution: "@types/readable-stream@npm:4.0.21" @@ -892,7 +901,7 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.4, fdir@npm:^6.4.6": +"fdir@npm:^6.4.4, fdir@npm:^6.5.0": version: 6.5.0 resolution: "fdir@npm:6.5.0" peerDependencies: @@ -1883,7 +1892,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14": +"tinyglobby@npm:^0.2.12": version: 0.2.14 resolution: "tinyglobby@npm:0.2.14" dependencies: @@ -1893,6 +1902,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.15": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -1961,17 +1980,17 @@ __metadata: languageName: node linkType: hard -"vite@npm:^7.1.2": - version: 7.1.2 - resolution: "vite@npm:7.1.2" +"vite@npm:^7.1.5": + version: 7.1.5 + resolution: "vite@npm:7.1.5" dependencies: esbuild: "npm:^0.25.0" - fdir: "npm:^6.4.6" + fdir: "npm:^6.5.0" fsevents: "npm:~2.3.3" picomatch: "npm:^4.0.3" postcss: "npm:^8.5.6" rollup: "npm:^4.43.0" - tinyglobby: "npm:^0.2.14" + tinyglobby: "npm:^0.2.15" peerDependencies: "@types/node": ^20.19.0 || >=22.12.0 jiti: ">=1.21.0" @@ -2012,7 +2031,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/4ed825b20bc0f49db99cd382de9506b2721ccd47dcebd4a68e0ef65e3cdd2347fded52b306c34178308e0fd7fe78fd5ff517623002cb00710182ad3012c92ced + checksum: 10c0/782d2f20c25541b26d1fb39bef5f194149caff39dc25b7836e25f049ca919f2e2ce186bddb21f3f20f6195354b3579ec637a8ca08d65b117f8b6f81e3e730a9c languageName: node linkType: hard From bd25dd9d27c495cede3495811355671d9fdad10c Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 22:58:51 +0200 Subject: [PATCH 09/10] fix(gettext): correctly preserve existing POT Creation-Date using pre-read value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: Previously re-reading the freshly generated POT could override the preserved value; use pre-read date to ensure stability. What: Use prevPotCreationDate captured before extraction when preserveCreationDate is enabled. Progress: 1/1 complete — Next: verify on downstream project. --- packages/vite-plugin-gettext/src/xgettext.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/vite-plugin-gettext/src/xgettext.ts b/packages/vite-plugin-gettext/src/xgettext.ts index 443db5e..a83c965 100644 --- a/packages/vite-plugin-gettext/src/xgettext.ts +++ b/packages/vite-plugin-gettext/src/xgettext.ts @@ -332,19 +332,13 @@ async function extractStrings( if (options.fixedCreationDate) { normalizedDate = options.fixedCreationDate; } else if (options.preserveCreationDate) { - try { - const existing = await fs.readFile(output, "utf-8"); - const match = existing.match(/"POT-Creation-Date:\s*([^\n]+)\\n"/); - if (match && match[1]) { - normalizedDate = match[1]; - if (verbose) { - console.log( - `[${pluginName}] Preserving existing POT-Creation-Date '${normalizedDate}'` - ); - } + if (prevPotCreationDate) { + normalizedDate = prevPotCreationDate; + if (verbose) { + console.log( + `[${pluginName}] Preserving existing POT-Creation-Date '${normalizedDate}'` + ); } - } catch { - // If file doesn't exist yet, fall back below } } From 7da8fb095d3c3ada9dd2a10b008ccfdd93fc6473 Mon Sep 17 00:00:00 2001 From: Pascal Garber Date: Tue, 9 Sep 2025 23:01:55 +0200 Subject: [PATCH 10/10] chore: Bump versions of vite-plugin-blueprint and vite-plugin-gettext to 0.2.5 --- packages/vite-plugin-blueprint/package.json | 2 +- packages/vite-plugin-gettext/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-blueprint/package.json b/packages/vite-plugin-blueprint/package.json index 52b5e9f..19156a0 100644 --- a/packages/vite-plugin-blueprint/package.json +++ b/packages/vite-plugin-blueprint/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-blueprint", - "version": "0.2.4", + "version": "0.2.5", "description": "Vite plugin for compiling Gnome Blueprint files", "main": "dist/index.js", "type": "module", diff --git a/packages/vite-plugin-gettext/package.json b/packages/vite-plugin-gettext/package.json index b99651b..15a181d 100644 --- a/packages/vite-plugin-gettext/package.json +++ b/packages/vite-plugin-gettext/package.json @@ -1,6 +1,6 @@ { "name": "@gjsify/vite-plugin-gettext", - "version": "0.2.4", + "version": "0.2.5", "description": "Vite plugin for compiling Gettext PO files", "main": "dist/index.js", "type": "module",