diff --git a/playwright.screenshot.config.ts b/playwright.screenshot.config.ts index 81264a4..985069a 100644 --- a/playwright.screenshot.config.ts +++ b/playwright.screenshot.config.ts @@ -34,9 +34,17 @@ export default defineConfig({ } }, { - name: 'MacBook Pro 14 inch', + name: 'MacBook Pro 14 inch NL locale', use: { - viewport: { width: 1512, height: 982 } + viewport: { width: 1512, height: 982 }, + locale: 'nl' + } + }, + { + name: 'MacBook Pro 14 inch nl-NL locale', + use: { + viewport: { width: 1512, height: 982 }, + locale: 'nl-NL' } }, { diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts index 2959787..fa817a7 100644 --- a/src/lib/i18n/index.ts +++ b/src/lib/i18n/index.ts @@ -8,11 +8,23 @@ register('nl', () => import('../locales/nl.json')); register('es', () => import('../locales/es.json')); register('de', () => import('../locales/de.json')); +const getInitialLocale = () => { + if (!browser) return defaultLocale; + + // Check localStorage first + const storedLocale = localStorage.getItem('locale'); + if (storedLocale) return storedLocale; + + // Get browser locale and normalize it + const browserLocale = window.navigator.language; + const normalizedLocale = browserLocale.split('-')[0].toLowerCase(); + + // Check if we support this locale + const supportedLocales = ['en', 'nl', 'es', 'de']; + return supportedLocales.includes(normalizedLocale) ? normalizedLocale : defaultLocale; +}; + init({ fallbackLocale: defaultLocale, - initialLocale: browser - ? browser && localStorage.getItem('locale') - ? localStorage.getItem('locale') - : window.navigator.language.slice(0, 2) - : defaultLocale + initialLocale: getInitialLocale() }); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index ae01278..0f1cc8a 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -17,6 +17,7 @@ import { page } from '$app/stores'; import { locale, locales, isLoading } from 'svelte-i18n'; import { ColorSchemeSwitcher } from '$lib/components'; + import { derived } from 'svelte/store'; export const setLocale = (lang: string) => () => { locale.set(lang); @@ -45,13 +46,14 @@ let languageNames = {}; - locale.subscribe(() => { - if ($locale) { - let newLanguageNames = new Intl.DisplayNames([$locale], { type: 'language' }); + const currentLocale = derived(locale, ($locale) => $locale || 'en'); - for (let l of $locales) { - languageNames[l] = newLanguageNames.of(l); - } + locale.subscribe(() => { + const localeToUse = $locale || 'en'; + let newLanguageNames = new Intl.DisplayNames([localeToUse], { type: 'language' }); + + for (let l of $locales) { + languageNames[l] = newLanguageNames.of(l) || l; } }); @@ -95,7 +97,10 @@ {#if !$isLoading} - {getFlagEmoji($locale)} {languageNames[$locale]} + {getFlagEmoji($currentLocale)} + {languageNames[$currentLocale] || 'English'} {#each $locales as locale} { - if (browser && localStorage.getItem('locale')) { - locale.set(localStorage.getItem('locale')); - } else if (browser) { - locale.set(window.navigator.language); + if (browser) { + if (localStorage.getItem('locale')) { + locale.set(localStorage.getItem('locale')); + } else { + // Normalize the browser locale + const browserLocale = window.navigator.language.split('-')[0].toLowerCase(); + const supportedLocales = ['en', 'nl', 'es', 'de']; + locale.set(supportedLocales.includes(browserLocale) ? browserLocale : 'en'); + } } await waitLocale(); }; diff --git a/tests/screenshots/viewport-screenshots.spec.ts b/tests/screenshots/viewport-screenshots.spec.ts index 5ec5569..4a27512 100644 --- a/tests/screenshots/viewport-screenshots.spec.ts +++ b/tests/screenshots/viewport-screenshots.spec.ts @@ -4,11 +4,47 @@ import { initMock, settingsJson, statusJson } from '../shared'; test.beforeEach(initMock); +// Define the translations for the headings +const headings = { + en: { + control: 'Control', + status: 'Status', + settings: 'Settings', + language: 'English' + }, + de: { + control: 'Steuerung', + status: 'Status', + settings: 'Einstellungen', + language: 'Deutsch' + }, + nl: { + control: 'Besturing', + status: 'Status', + settings: 'Instellingen', + language: 'Nederlands' + }, + es: { + control: 'Control', + status: 'Estado', + settings: 'Ajustes', + language: 'EspaƱol' + } +}; + test('capture screenshots across devices', async ({ page }, testInfo) => { + // Get the locale from the browser or default to 'en' + const locale = testInfo.project.use?.locale?.split('-')[0].toLowerCase() || 'en'; + const translations = headings[locale] || headings.en; + await page.goto('/'); - await expect(page.getByRole('heading', { name: 'Control' })).toBeVisible(); - await expect(page.getByRole('heading', { name: 'Status' })).toBeVisible(); - await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible(); + await expect(page.getByRole('heading', { name: translations.control })).toBeVisible(); + await expect(page.getByRole('heading', { name: translations.status })).toBeVisible(); + await expect(page.getByRole('heading', { name: translations.settings })).toBeVisible(); + + if (await page.locator('#nav-language-dropdown').isVisible()) { + await expect(page.getByRole('link', { name: translations.language })).toBeVisible(); + } const screenshot = await page.screenshot({ path: `./test-results/screenshots/default-${test.info().project.name.toLowerCase().replace(' ', '_')}.png` @@ -21,6 +57,9 @@ test('capture screenshots across devices', async ({ page }, testInfo) => { }); test('capture screenshots across devices with bitaxe screens', async ({ page }, testInfo) => { + const locale = testInfo.project.use?.locale?.split('-')[0].toLowerCase() || 'en'; + const translations = headings[locale] || headings.en; + settingsJson.screens = [ { id: 0, @@ -73,9 +112,14 @@ test('capture screenshots across devices with bitaxe screens', async ({ page }, statusJson.rendered = ['mdi:bitaxe', '', 'mdi:pickaxe', '6', '3', '7', 'GH/S']; await page.goto('/'); - await expect(page.getByRole('heading', { name: 'Control' })).toBeVisible(); - await expect(page.getByRole('heading', { name: 'Status' })).toBeVisible(); - await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible(); + + await expect(page.getByRole('heading', { name: translations.control })).toBeVisible(); + await expect(page.getByRole('heading', { name: translations.status })).toBeVisible(); + await expect(page.getByRole('heading', { name: translations.settings })).toBeVisible(); + + if (await page.locator('#nav-language-dropdown').isVisible()) { + await expect(page.getByRole('link', { name: translations.language })).toBeVisible(); + } await page.screenshot({ path: `./test-results/screenshots/bitaxe-${test.info().project.name.toLowerCase().replace(' ', '_')}.png` diff --git a/vite.config.ts b/vite.config.ts index 2c3749e..c9bdcf6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,5 @@ import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vitest/config'; +import { defineConfig } from 'vite'; import GithubActionsReporter from 'vitest-github-actions-reporter'; // import { visualizer } from 'rollup-plugin-visualizer'; @@ -102,5 +102,8 @@ export default defineConfig({ globals: true, environment: 'jsdom', reporters: process.env.GITHUB_ACTIONS ? ['default', new GithubActionsReporter()] : 'default' + }, + define: { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) } });