From 683aa2379d7f94c0e347737ebe24f623cad23b5c Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Mon, 15 Jun 2026 18:30:02 +0700 Subject: [PATCH] fix: load translations from API instead of static CDN files The banner was fetching /translations-{locale}.json from the CDN as static files, but translations are stored in the DB and served via the public /api/v1/translations/{siteId}/{locale} endpoint. Fixes: - fetchTranslations() now calls the public API endpoint - loadTranslations() takes (apiBase, siteId, locale) - banner.ts passes apiBase and siteId to loadTranslations() - i18n.test.ts updated to match new signature --- apps/banner/package-lock.json | 5 +++-- apps/banner/src/__tests__/i18n.test.ts | 8 ++++---- apps/banner/src/banner.ts | 2 +- apps/banner/src/i18n.ts | 18 +++++++++++------- package-lock.json | 6 ++++++ 5 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 package-lock.json diff --git a/apps/banner/package-lock.json b/apps/banner/package-lock.json index 5ff3dc7..6c11824 100644 --- a/apps/banner/package-lock.json +++ b/apps/banner/package-lock.json @@ -1,12 +1,13 @@ { - "name": "@cmp/banner", + "name": "@consentos/banner", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@cmp/banner", + "name": "@consentos/banner", "version": "0.1.0", + "license": "Elastic-2.0", "devDependencies": { "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.1.2", diff --git a/apps/banner/src/__tests__/i18n.test.ts b/apps/banner/src/__tests__/i18n.test.ts index d79a48b..3e0a94e 100644 --- a/apps/banner/src/__tests__/i18n.test.ts +++ b/apps/banner/src/__tests__/i18n.test.ts @@ -135,7 +135,7 @@ describe('i18n', () => { describe('loadTranslations', () => { it('should return defaults for English locale', async () => { - const t = await loadTranslations('https://cdn.example.com', 'en'); + const t = await loadTranslations('https://api.example.com', 'site-123', 'en'); expect(t.title).toBe(DEFAULT_TRANSLATIONS.title); expect(t.acceptAll).toBe(DEFAULT_TRANSLATIONS.acceptAll); }); @@ -143,10 +143,10 @@ describe('i18n', () => { it('should merge remote translations over defaults', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, - json: () => Promise.resolve({ title: 'Wir verwenden Cookies', acceptAll: 'Alle akzeptieren' }), + json: () => Promise.resolve({ strings: { title: 'Wir verwenden Cookies', acceptAll: 'Alle akzeptieren' } }), })); - const t = await loadTranslations('https://cdn.example.com', 'de'); + const t = await loadTranslations('https://api.example.com', 'site-123', 'de'); expect(t.title).toBe('Wir verwenden Cookies'); expect(t.acceptAll).toBe('Alle akzeptieren'); @@ -159,7 +159,7 @@ describe('i18n', () => { it('should fall back to defaults when fetch fails', async () => { vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('fail'))); - const t = await loadTranslations('https://cdn.example.com', 'fr'); + const t = await loadTranslations('https://api.example.com', 'site-123', 'fr'); expect(t.title).toBe(DEFAULT_TRANSLATIONS.title); vi.unstubAllGlobals(); diff --git a/apps/banner/src/banner.ts b/apps/banner/src/banner.ts index 7779c1a..b12b90e 100644 --- a/apps/banner/src/banner.ts +++ b/apps/banner/src/banner.ts @@ -222,7 +222,7 @@ async function init(): Promise { // Load translations // Use site-configured default_language if set, otherwise auto-detect const locale = config.default_language ?? detectLocale(); - const t = await loadTranslations(cdnBase, locale); + const t = await loadTranslations(apiBase, siteId, locale); // Capture a closure that re-opens the banner with current consent // pre-filled. Called from the floating button and from diff --git a/apps/banner/src/i18n.ts b/apps/banner/src/i18n.ts index 7ca42e3..8df841d 100644 --- a/apps/banner/src/i18n.ts +++ b/apps/banner/src/i18n.ts @@ -84,34 +84,38 @@ export function normaliseLocale(locale: string): string { } /** - * Fetch translations for a locale from the CDN. + * Fetch translations for a locale from the public API endpoint. * Returns null if not found or on error. */ export async function fetchTranslations( - cdnBase: string, + apiBase: string, + siteId: string, locale: string, ): Promise | null> { try { - const resp = await fetch(`${cdnBase}/translations-${locale}.json`); + const resp = await fetch(`${apiBase}/api/v1/translations/${siteId}/${locale}`); if (!resp.ok) return null; - return (await resp.json()) as Partial; + // API returns { strings: { ... } } + const data = (await resp.json()) as { strings?: Partial }; + return data.strings ?? null; } catch { return null; } } /** - * Load translations: try fetching from CDN, fall back to defaults. + * Load translations: try fetching from API, fall back to defaults. */ export async function loadTranslations( - cdnBase: string, + apiBase: string, + siteId: string, locale: string, ): Promise { if (locale === 'en') { return { ...DEFAULT_TRANSLATIONS }; } - const remote = await fetchTranslations(cdnBase, locale); + const remote = await fetchTranslations(apiBase, siteId, locale); if (!remote) { return { ...DEFAULT_TRANSLATIONS }; } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ce944bc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "consentos", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}