fix: add built-in Thai banner translations
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / API Lint (push) Blocked by required conditions
CI / API Tests (push) Blocked by required conditions
CI / Scanner Lint (push) Blocked by required conditions
CI / Scanner Tests (push) Blocked by required conditions
CI / Banner Lint & Typecheck (push) Blocked by required conditions
CI / Banner Tests (push) Blocked by required conditions
CI / Banner Build (push) Blocked by required conditions
CI / Admin UI Typecheck (push) Blocked by required conditions
CI / Admin UI Tests (push) Blocked by required conditions
CI / Admin UI Build (push) Blocked by required conditions
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / API Lint (push) Blocked by required conditions
CI / API Tests (push) Blocked by required conditions
CI / Scanner Lint (push) Blocked by required conditions
CI / Scanner Tests (push) Blocked by required conditions
CI / Banner Lint & Typecheck (push) Blocked by required conditions
CI / Banner Tests (push) Blocked by required conditions
CI / Banner Build (push) Blocked by required conditions
CI / Admin UI Typecheck (push) Blocked by required conditions
CI / Admin UI Tests (push) Blocked by required conditions
CI / Admin UI Build (push) Blocked by required conditions
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import {
|
||||
DEFAULT_TRANSLATIONS,
|
||||
THAI_TRANSLATIONS,
|
||||
detectLocale,
|
||||
fetchTranslations,
|
||||
interpolate,
|
||||
@@ -46,6 +47,43 @@ describe('i18n', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('THAI_TRANSLATIONS', () => {
|
||||
it('should have all required keys', () => {
|
||||
expect(THAI_TRANSLATIONS.title).toBe('เรามีการใช้คุ๊กกี้เพื่อเก็บข้อมูล');
|
||||
expect(THAI_TRANSLATIONS.acceptAll).toBe('ยอมรับทั้งหมด');
|
||||
expect(THAI_TRANSLATIONS.rejectAll).toBe('ปฏิเสธทั้งหมด');
|
||||
expect(THAI_TRANSLATIONS.managePreferences).toBe('ตั้งค่า');
|
||||
expect(THAI_TRANSLATIONS.savePreferences).toBe('บันทึก');
|
||||
expect(THAI_TRANSLATIONS.privacyPolicyLink).toBe('นโยบายความเป็นส่วนตัว');
|
||||
expect(THAI_TRANSLATIONS.closeLabel).toBe('ปิด');
|
||||
});
|
||||
|
||||
it('should have all category translations', () => {
|
||||
expect(THAI_TRANSLATIONS.categoryNecessary).toBe('จำเป็น');
|
||||
expect(THAI_TRANSLATIONS.categoryFunctional).toBe('ฟังก์ชั่น');
|
||||
expect(THAI_TRANSLATIONS.categoryAnalytics).toBe('การวิเคราะห์');
|
||||
expect(THAI_TRANSLATIONS.categoryMarketing).toBe('การตลาด');
|
||||
expect(THAI_TRANSLATIONS.categoryPersonalisation).toBe('ส่วนตัว');
|
||||
});
|
||||
|
||||
it('should have category descriptions', () => {
|
||||
expect(THAI_TRANSLATIONS.categoryNecessaryDesc).toContain('การจดจำตะกร้าสินค้า');
|
||||
expect(THAI_TRANSLATIONS.categoryFunctionalDesc).toContain('ฟังก์ชั่นพิเศษ');
|
||||
expect(THAI_TRANSLATIONS.categoryAnalyticsDesc).toContain('ผู้เข้าชมใช้งานเว็บไซต์อย่างไร');
|
||||
expect(THAI_TRANSLATIONS.categoryMarketingDesc).toContain('Facebook และ Google');
|
||||
expect(THAI_TRANSLATIONS.categoryPersonalisationDesc).toContain('เก็บข้อมูลส่วนตัว');
|
||||
});
|
||||
|
||||
it('should have cookie count template with placeholder', () => {
|
||||
expect(THAI_TRANSLATIONS.cookieCount).toContain('{{count}}');
|
||||
});
|
||||
|
||||
it('should preserve legal link placeholders in description', () => {
|
||||
expect(THAI_TRANSLATIONS.description).toContain('{{privacy_policy}}');
|
||||
expect(THAI_TRANSLATIONS.description).toContain('{{terms}}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('normaliseLocale', () => {
|
||||
it('should extract language code from locale', () => {
|
||||
expect(normaliseLocale('en-GB')).toBe('en');
|
||||
@@ -140,16 +178,31 @@ describe('i18n', () => {
|
||||
expect(t.acceptAll).toBe(DEFAULT_TRANSLATIONS.acceptAll);
|
||||
});
|
||||
|
||||
it('should merge raw public API translations over defaults', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ title: 'เราใช้คุกกี้', acceptAll: 'ยอมรับทั้งหมด' }),
|
||||
}));
|
||||
it('should return built-in Thai without calling API', async () => {
|
||||
const fetchSpy = vi.fn();
|
||||
vi.stubGlobal('fetch', fetchSpy);
|
||||
|
||||
const t = await loadTranslations('https://api.example.com', 'site-123', 'th');
|
||||
|
||||
expect(t.title).toBe('เราใช้คุกกี้');
|
||||
expect(t.title).toBe('เรามีการใช้คุ๊กกี้เพื่อเก็บข้อมูล');
|
||||
expect(t.acceptAll).toBe('ยอมรับทั้งหมด');
|
||||
expect(t.rejectAll).toBe('ปฏิเสธทั้งหมด');
|
||||
// Should NOT have called fetch — Thai is built-in
|
||||
expect(fetchSpy).not.toHaveBeenCalled();
|
||||
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('should merge raw public API translations over defaults', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ title: 'Nous utilisons des cookies', acceptAll: 'Tout accepter' }),
|
||||
}));
|
||||
|
||||
const t = await loadTranslations('https://api.example.com', 'site-123', 'fr');
|
||||
|
||||
expect(t.title).toBe('Nous utilisons des cookies');
|
||||
expect(t.acceptAll).toBe('Tout accepter');
|
||||
// Missing keys should fall back to English
|
||||
expect(t.rejectAll).toBe(DEFAULT_TRANSLATIONS.rejectAll);
|
||||
|
||||
|
||||
@@ -51,6 +51,36 @@ export const DEFAULT_TRANSLATIONS: TranslationStrings = {
|
||||
cookieCount: '{{count}} cookies used on this site',
|
||||
};
|
||||
|
||||
/** Built-in Thai translations — no API call needed. */
|
||||
export const THAI_TRANSLATIONS: TranslationStrings = {
|
||||
title: 'เรามีการใช้คุ๊กกี้เพื่อเก็บข้อมูล',
|
||||
description:
|
||||
'เว็บไซซ์นี้ใช้คุกกี้เพื่อปรับปรุงประสบการณ์การใช้งาน วิเคราะห์การเข้าชม และแสดงโฆษณาที่เหมาะกับคุณ คุณสามารถเลือกได้ว่าจะอนุญาตคุกกี้ประเภทใด คุกกี้ที่จำเป็นจะถูกเปิดใช้งานเสมอเพื่อให้เว็บไซต์ทำงานได้ [นโยบายความเป็นส่วนตัว]({{privacy_policy}}) [ข้อกำหนดและเงื่อนไข]({{terms}})',
|
||||
acceptAll: 'ยอมรับทั้งหมด',
|
||||
rejectAll: 'ปฏิเสธทั้งหมด',
|
||||
managePreferences: 'ตั้งค่า',
|
||||
savePreferences: 'บันทึก',
|
||||
privacyPolicyLink: 'นโยบายความเป็นส่วนตัว',
|
||||
closeLabel: 'ปิด',
|
||||
categoryNecessary: 'จำเป็น',
|
||||
categoryNecessaryDesc: 'คุกกี้ที่จำเป็นสำหรับการทำงานพื้นฐานของเว็บไซต์ เช่น การจดจำตะกร้าสินค้า การเข้าสู่ระบบ และความปลอดภัย — เปิดใช้งานเสมอเพราะเว็บไซต์ไม่สามารถทำงานได้ถ้าไม่มี',
|
||||
categoryFunctional: 'ฟังก์ชั่น',
|
||||
categoryFunctionalDesc: 'คุกกี้การตลาดใช้เพื่อให้เว็บไชต์มีฟังก์ชั่นพิเศษ ถ้าปิดการทำงานอาจจะทำให้บางฟังก์ชั่นของเว็บไซต์ใช้งานไม่ได้',
|
||||
categoryAnalytics: 'การวิเคราะห์',
|
||||
categoryAnalyticsDesc: 'คุกกี้เหล่านี้ช่วยให้เราเข้าใจว่าผู้เข้าชมใช้งานเว็บไซต์อย่างไร เช่น หน้าไหนที่เข้าบ่อย คลิกที่ไหน - ข้อมูลเหล่านี้ช่วยเราพัฒนาเว็บไซต์ให้ดีขึ้นเรื่อยๆ',
|
||||
categoryMarketing: 'การตลาด',
|
||||
categoryMarketingDesc: 'คุกกี้การตลาดใช้ติดตามพฤติกรรมการเข้าชมเว็บไซต์เพื่อแสดงโฆษณาที่เกี่ยวข้องกับความสนใจของคุณบนแพลตฟอร์มอื่นด้วย เช่น Facebook และ Google',
|
||||
categoryPersonalisation: 'ส่วนตัว',
|
||||
categoryPersonalisationDesc: 'คุกกี้การตลาดใช้สำหรับเก็บข้อมูลส่วนตัว',
|
||||
cookieCount: 'มีคุกกี้ {{count}} บนเว็บไซต์นี้',
|
||||
};
|
||||
|
||||
/** Built-in translations that don't require an API call. */
|
||||
const BUILT_IN_TRANSLATIONS: Record<string, TranslationStrings> = {
|
||||
en: DEFAULT_TRANSLATIONS,
|
||||
th: THAI_TRANSLATIONS,
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect the user's preferred locale.
|
||||
*
|
||||
@@ -105,15 +135,17 @@ export async function fetchTranslations(
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations: try fetching from API, fall back to defaults.
|
||||
* Load translations: use built-in if available, otherwise fetch from API.
|
||||
*/
|
||||
export async function loadTranslations(
|
||||
apiBase: string,
|
||||
siteId: string,
|
||||
locale: string,
|
||||
): Promise<TranslationStrings> {
|
||||
if (locale === 'en') {
|
||||
return { ...DEFAULT_TRANSLATIONS };
|
||||
// Built-in translations (en, th, etc.) — no API call needed
|
||||
const builtIn = BUILT_IN_TRANSLATIONS[locale];
|
||||
if (builtIn) {
|
||||
return { ...builtIn };
|
||||
}
|
||||
|
||||
const remote = await fetchTranslations(apiBase, siteId, locale);
|
||||
|
||||
Reference in New Issue
Block a user