mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
fix(i18n): key the catalog's cache by its content, not the release
The service worker serves the locale catalog's boot script cache-first,
and its URL carried the package version. Every build of one release
therefore shared one URL: an instance updated within a release (a beta,
a redeploy) kept the catalog of its first build, and every message added
since read as its raw key ("timeline.zoom.range", "timeline.selection.week")
or fell back to English.
next.config.ts now hashes the message catalogs at build time and the
layout keys the script by that hash, so a changed catalog is a new URL.
This commit is contained in:
1 parent
cd78415084
commit
3f47224825
5 files changed
+63
-3
No files matched your search
@@ -102,6 +102,8 @@ const NOT_OPERATOR_CONFIGURABLE: Readonly<Record<string, string>> = {
|
||||
// --- Baked at build time by the Dockerfile's ARG/ENV pairs. ---
|
||||
NEXT_PUBLIC_APP_VERSION:
|
||||
"Dockerfile build arg; a runtime value cannot change what is compiled in",
|
||||
NEXT_PUBLIC_I18N_CATALOG_VERSION:
|
||||
"computed by next.config.ts from the message catalogs at build time",
|
||||
NEXT_PUBLIC_APP_BUILD_SHA:
|
||||
"Dockerfile build arg, stamped from the release commit",
|
||||
NEXT_PUBLIC_APP_BUILT_AT: "Dockerfile build arg, stamped at image build",
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* The locale catalog's boot script is cached by its URL: the service worker
|
||||
* serves `/i18n/<locale>.js?v=…` cache-first. Keyed by the package version,
|
||||
* every build of one release shared one URL, so a beta updated within a
|
||||
* release kept its first catalog and every key added since read as its raw
|
||||
* name ("timeline.zoom.range"). The key is the catalogs' content hash now.
|
||||
*/
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const read = (rel: string) => readFileSync(join(process.cwd(), rel), "utf8");
|
||||
|
||||
describe("the locale catalog's cache key", () => {
|
||||
it("moves with the catalogs, not with the release", () => {
|
||||
const layout = read("src/app/layout.tsx");
|
||||
const src =
|
||||
/src=\{`\/i18n\/\$\{initialLocale\}\.js\?v=\$\{([^}]*)\}`\}/.exec(layout);
|
||||
expect(src?.[1]).toContain("NEXT_PUBLIC_I18N_CATALOG_VERSION");
|
||||
expect(src?.[1]).not.toContain("NEXT_PUBLIC_APP_VERSION");
|
||||
});
|
||||
|
||||
it("is computed from the message catalogs at build time", () => {
|
||||
const config = read("next.config.ts");
|
||||
expect(config).toMatch(
|
||||
/NEXT_PUBLIC_I18N_CATALOG_VERSION:\s*catalogVersion\(\)/,
|
||||
);
|
||||
expect(config).toMatch(/join\(process\.cwd\(\), "messages"\)/);
|
||||
});
|
||||
});
|
||||
+3
-1
@@ -131,7 +131,9 @@ export default async function RootLayout({
|
||||
id="healthlog-i18n-boot"
|
||||
strategy="beforeInteractive"
|
||||
nonce={nonce}
|
||||
src={`/i18n/${initialLocale}.js?v=${process.env.NEXT_PUBLIC_APP_VERSION || "dev"}`}
|
||||
// Keyed by the catalogs' content (`next.config.ts`), not the
|
||||
// release: the service worker serves this URL cache-first.
|
||||
src={`/i18n/${initialLocale}.js?v=${process.env.NEXT_PUBLIC_I18N_CATALOG_VERSION || "dev"}`}
|
||||
/>
|
||||
</head>
|
||||
<body className={`${inter.variable} font-sans antialiased`}>
|
||||
|
||||
Reference in new issue
Block a user