feat: prepare for i18n

main
Tomáš Mládek 2024-02-28 13:27:10 +01:00
parent 7a7dcd3662
commit ba6e54d7d5
18 changed files with 115 additions and 74 deletions

View File

@ -43,9 +43,11 @@
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tabler/icons-webfont": "^2.47.0",
"debug": "^4.3.4",
"i18next": "^23.10.0",
"lodash": "^4.17.21",
"normalize.css": "^8.0.1",
"svelte": "^4.2.7",
"svelte-i18next": "^2.2.2",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^5.0.3"

View File

@ -26,6 +26,9 @@ dependencies:
debug:
specifier: ^4.3.4
version: 4.3.4
i18next:
specifier: ^23.10.0
version: 23.10.0
lodash:
specifier: ^4.17.21
version: 4.17.21
@ -35,6 +38,9 @@ dependencies:
svelte:
specifier: ^4.2.7
version: 4.2.9
svelte-i18next:
specifier: ^2.2.2
version: 2.2.2(i18next@23.10.0)(svelte@4.2.9)
tslib:
specifier: ^2.4.1
version: 2.6.2
@ -139,7 +145,6 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.1
dev: true
/@esbuild/aix-ppc64@0.19.12:
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
@ -1802,6 +1807,12 @@ packages:
- supports-color
dev: true
/i18next@23.10.0:
resolution: {integrity: sha512-/TgHOqsa7/9abUKJjdPeydoyDc0oTi/7u9F8lMSj6ufg4cbC1Oj3f/Jja7zj7WRIhEQKB7Q4eN6y68I9RDxxGQ==}
dependencies:
'@babel/runtime': 7.23.9
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
@ -2396,7 +2407,6 @@ packages:
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: true
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
@ -2683,6 +2693,16 @@ packages:
svelte: 4.2.9
dev: false
/svelte-i18next@2.2.2(i18next@23.10.0)(svelte@4.2.9):
resolution: {integrity: sha512-IpJDZCH5cCgKfHQHgiLmGT4j9HCdg4fqsP3oP2deLu8PxmNj0Ui6khMiDoxAxedAiYEhr0xendv2xqh3Rq+uQQ==}
peerDependencies:
i18next: '*'
svelte: '*'
dependencies:
i18next: 23.10.0
svelte: 4.2.9
dev: false
/svelte-preprocess@5.1.3(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3):
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
engines: {node: '>= 16.0.0', pnpm: ^8.0.0}

View File

@ -1,6 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
import { i18n } from '$lib/i18n';
let screenResolution = '... x ...';
let windowResolution = '';
@ -24,11 +25,11 @@
<div class="info">
<div class="resolution">
<div class="title">Screen Resolution</div>
<div class="title">{$i18n.t('Screen Resolution')}</div>
<div class="value">{screenResolution}</div>
{#if windowResolution && windowResolution !== screenResolution}
<div class="window" transition:fade>
<div class="title">Window Resolution</div>
<div class="title">{$i18n.t('Window Resolution')}</div>
<div class="value">{windowResolution}</div>
</div>
{/if}

8
src/lib/i18n.ts Normal file
View File

@ -0,0 +1,8 @@
import i18next from 'i18next';
import { createI18nStore } from 'svelte-i18next';
i18next.init({
lng: 'en'
});
export const i18n = createI18nStore(i18next);

View File

@ -8,6 +8,7 @@
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { i18n } from '$lib/i18n';
let idleTimeout: NodeJS.Timeout | undefined;
onMount(() => {
@ -25,7 +26,7 @@
<TestCard full={onlyCard} on:focus={() => goto('/card')} />
<main class:content={!onlyCard} class:sub={!$page.data.root && !onlyCard}>
<a href=".." class="button button-back"><i class="ti ti-arrow-back" />Back</a>
<a href=".." class="button button-back"><i class="ti ti-arrow-back" />{$i18n.t('Back')}</a>
<slot />
</main>

View File

@ -1,5 +1,6 @@
<script>
import { version } from '../../package.json';
import { i18n } from '$lib/i18n';
</script>
<nav>
@ -8,39 +9,39 @@
<div class="options">
<a href="card">
<i class="ti ti-device-desktop"></i>
Screen
{$i18n.t('Screen')}
</a>
<a href="audio">
<i class="ti ti-volume"></i>
Audio
{$i18n.t('Audio')}
</a>
<a href="av-sync">
<i class="ti ti-time-duration-off"></i>
AV&nbsp;Sync
{$i18n.t('AV Sync')}
</a>
<a href="keyboard">
<i class="ti ti-keyboard"></i>
Keyboard
{$i18n.t('Keyboard')}
</a>
<a href="mouse" class="disabled">
<i class="ti ti-mouse"></i>
Mouse
{$i18n.t('Mouse')}
</a>
<a href="gamepad">
<i class="ti ti-device-gamepad"></i>
Gamepad
{$i18n.t('Gamepad')}
</a>
<a href="camera">
<i class="ti ti-camera"></i>
Camera
{$i18n.t('Camera')}
</a>
<a href="microphone" class="disabled">
<i class="ti ti-microphone"></i>
Microphone
{$i18n.t('Microphone')}
</a>
<a href="sensors" class="disabled">
<i class="ti ti-cpu-2"></i>
Sensors
{$i18n.t('Sensors')}
</a>
</div>
</nav>
@ -63,6 +64,7 @@
& a {
text-align: center;
text-decoration: none;
white-space: nowrap;
&.disabled {
pointer-events: none;

View File

@ -6,19 +6,20 @@
import rearLeftUrl from '@assets/audio/5.1/Rear_Left.mp3';
import rearRightUrl from '@assets/audio/5.1/Rear_Right.mp3';
import LfeUrl from '@assets/audio/5.1/LFE_Noise.mp3';
import { i18n } from '$lib/i18n';
</script>
<div class="row">
<Speaker src={frontLeftUrl} left>Front Left</Speaker>
<Speaker src={frontLeftUrl} left>{$i18n.t('Front Left')}</Speaker>
<div class="center">
<Speaker src={frontCenterUrl} center>Front Center</Speaker>
<Speaker src={frontCenterUrl} center>{$i18n.t('Front Center')}</Speaker>
</div>
<Speaker src={frontRightUrl} right>Front Right</Speaker>
<Speaker src={frontRightUrl} right>{$i18n.t('Front Right')}</Speaker>
</div>
<div class="row">
<Speaker src={rearLeftUrl} left>Rear Left</Speaker>
<Speaker src={rearRightUrl} right>Rear Right</Speaker>
<Speaker src={rearLeftUrl} left>{$i18n.t('Rear Left')}</Speaker>
<Speaker src={rearRightUrl} right>{$i18n.t('Rear Right')}</Speaker>
</div>
<Speaker src={LfeUrl} lfe>LFE</Speaker>
<Speaker src={LfeUrl} lfe>{$i18n.t('LFE')}</Speaker>
<div class="label">5.1</div>

View File

@ -8,24 +8,25 @@
import rearLeftUrl from '@assets/audio/7.1/Rear_Left.mp3';
import rearRightUrl from '@assets/audio/7.1/Rear_Right.mp3';
import LfeUrl from '@assets/audio/7.1/LFE_Noise.mp3';
import { i18n } from '$lib/i18n';
</script>
<div class="row">
<Speaker src={frontLeftUrl} left>Front Left</Speaker>
<Speaker src={frontLeftUrl} left>{$i18n.t('Front Left')}</Speaker>
<div class="center">
<Speaker src={frontCenterUrl} center>Front Center</Speaker>
<Speaker src={frontCenterUrl} center>{$i18n.t('Front Center')}</Speaker>
</div>
<Speaker src={frontRightUrl} right>Front Right</Speaker>
<Speaker src={frontRightUrl} right>{$i18n.t('Front Right')}</Speaker>
</div>
<div class="row">
<Speaker src={sideLeftUrl} left>Side Left</Speaker>
<Speaker src={sideRightUrl} right>Side Right</Speaker>
<Speaker src={sideLeftUrl} left>{$i18n.t('Side Left')}</Speaker>
<Speaker src={sideRightUrl} right>{$i18n.t('Side Right')}</Speaker>
</div>
<div class="row">
<Speaker src={rearLeftUrl} left>Rear Left</Speaker>
<Speaker src={rearRightUrl} right>Rear Right</Speaker>
<Speaker src={rearLeftUrl} left>{$i18n.t('Rear Left')}</Speaker>
<Speaker src={rearRightUrl} right>{$i18n.t('Rear Right')}</Speaker>
</div>
<Speaker src={LfeUrl} lfe>LFE</Speaker>
<Speaker src={LfeUrl} lfe>{$i18n.t('LFE')}</Speaker>
<div class="label">7.1</div>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import { i18n } from '$lib/i18n';
export let element: HTMLElement;
@ -46,8 +47,8 @@
<button on:click={onClick}>
<i class="ti ti-refresh"></i>
{#if cycling}
Stop Cycling
{$i18n.t('Stop Cycling')}
{:else}
Cycle through
{$i18n.t('Cycle through')}
{/if}
</button>

View File

@ -4,15 +4,16 @@
import rightUrl from '@assets/audio/stereo/Right.mp3';
import Speaker from './speaker.svelte';
import CycleButton from './cycle-button.svelte';
import { i18n } from '$lib/i18n';
let speakersEl: HTMLElement;
</script>
<div class="test">
<div class="speakers" bind:this={speakersEl}>
<Speaker src={leftUrl} left inline>Left</Speaker>
<Speaker src={centerUrl} center inline>Center</Speaker>
<Speaker src={rightUrl} right inline>Right</Speaker>
<Speaker src={leftUrl} left inline>{$i18n.t('Left')}</Speaker>
<Speaker src={centerUrl} center inline>{$i18n.t('Center')}</Speaker>
<Speaker src={rightUrl} right inline>{$i18n.t('Right')}</Speaker>
</div>
<CycleButton element={speakersEl} />
</div>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { i18n } from '$lib/i18n';
</script>
<h2><i class="ti ti-volume"></i> Audio test</h2>
<h2><i class="ti ti-volume"></i> {$i18n.t('Audio test')}</h2>
<slot />

View File

@ -1,22 +1,23 @@
<script lang="ts">
import StereoTest from './(channels)/stereo-test.svelte';
import PhaseTest from './phase.svelte';
import { i18n } from '$lib/i18n';
</script>
<article>
<h3>Channel tests</h3>
<h4>Stereo</h4>
<h3>{$i18n.t('Channel tests')}</h3>
<h4>{$i18n.t('Stereo')}</h4>
<section>
<StereoTest />
</section>
<h4>Surround audio</h4>
<h4>{$i18n.t('Surround audio')}</h4>
<section>
<ul>
<li><a class="button" href="channels-5.1">5.1 Surround</a></li>
<li><a class="button" href="channels-7.1">7.1 Surround</a></li>
<li><a class="button" href="channels-5.1">{$i18n.t('5.1 Surround')}</a></li>
<li><a class="button" href="channels-7.1">{$i18n.t('7.1 Surround')}</a></li>
</ul>
</section>
<h3>Phase test</h3>
<h3>{$i18n.t('Phase test')}</h3>
<PhaseTest />
</article>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { i18n } from '$lib/i18n';
let frequency = 60;
let playing = false;
@ -53,18 +54,13 @@
<div class="test">
<label>
Frequency <input
type="number"
bind:value={frequency}
min="20"
max="20000"
disabled={playing}
/>Hz
{$i18n.t('Frequency')}
<input type="number" bind:value={frequency} min="20" max="20000" disabled={playing} />Hz
</label>
<div class="controls">
<button on:click={() => start('inPhase')}>In Phase</button>
<button on:click={() => start('outOfPhase')}>Out of Phase</button>
<button class="stop" on:click={stop} disabled={!playing}>Stop</button>
<button on:click={() => start('inPhase')}>{$i18n.t('In Phase')}</button>
<button on:click={() => start('outOfPhase')}>{$i18n.t('Out of Phase')}</button>
<button class="stop" on:click={stop} disabled={!playing}>{$i18n.t('Stop')}</button>
</div>
</div>

View File

@ -1,9 +1,10 @@
<script lang="ts">
import videoUrl from '@assets/avsync.webm';
import { i18n } from '$lib/i18n';
let paused = true;
</script>
<h2><i class="ti ti-time-duration-off"></i> Audio/Video Synchronization</h2>
<h2><i class="ti ti-time-duration-off"></i> {$i18n.t('Audio/Video Synchronization')}</h2>
<!-- svelte-ignore a11y-media-has-caption -->
<video
class:playing={!paused}

View File

@ -2,6 +2,7 @@
import { onDestroy, onMount } from 'svelte';
import { browser } from '$app/environment';
import debug from 'debug';
import { i18n } from '$lib/i18n';
const dbg = debug('app:camera');
let video: HTMLVideoElement;
@ -78,26 +79,26 @@
}
</script>
<h2><i class="ti ti-camera"></i> Camera test</h2>
<h2><i class="ti ti-camera"></i> {$i18n.t('Camera test')}</h2>
<div class="controls">
<label>
Device
{$i18n.t('Device')}
<select bind:value={currentDevice} disabled={!devices.length}>
{#each devices as device}
<option value={device.deviceId}>{device.label || '???'}</option>
{:else}
<option>No camera found</option>
<option>{$i18n.t('No camera found')}</option>
{/each}
</select>
</label>
<button on:click={refreshDevices}>
<i class="ti ti-refresh"></i>
Refresh
{$i18n.t('Refresh')}
</button>
<div class="separator"></div>
<label>
Resolution
{$i18n.t('Resolution')}
<select bind:value={requestResolution}>
<option value="auto">Auto</option>
<option value={[4096, 2160]}>4096x2160</option>
@ -109,7 +110,7 @@
</select>
</label>
<label>
Frame rate
{$i18n.t('Frame rate')}
<select bind:value={requestFramerate}>
<option value="auto">Auto</option>
<option value={120}>120 fps</option>
@ -135,29 +136,29 @@
<footer>
{#if !currentDevice}
<span class="subdued">No camera selected</span>
<span class="subdued">{$i18n.t('No camera selected')}</span>
{:else}
<ul>
{#key currentDevice}
<li>
Resolution: <strong>{deviceInfo.resolution || '???'}</strong>
{$i18n.t('Resolution')}: <strong>{deviceInfo.resolution || '???'}</strong>
</li>
<li>
Frame rate: <strong>{deviceInfo.frameRate || '???'}</strong>
{$i18n.t('Frame rate')}: <strong>{deviceInfo.frameRate || '???'}</strong>
</li>
{/key}
</ul>
<div class="controls">
<button on:click={takeSnapshot}>
<i class="ti ti-camera"></i>
Take picture
{$i18n.t('Take picture')}
</button>
<button on:click={() => (flipped = !flipped)}>
<i class="ti ti-flip-vertical"></i>
{#if flipped}
Unflip image
{$i18n.t('Unflip image')}
{:else}
Flip image
{$i18n.t('Flip image')}
{/if}
</button>
</div>

View File

@ -1,7 +1,8 @@
<script>
import { i18n } from '$lib/i18n';
</script>
<a href="/" class="hide-idle"><i class="ti ti-arrow-back"></i> Back</a>
<a href="/" class="hide-idle"><i class="ti ti-arrow-back"></i> {$i18n.t('Back')}</a>
<style>
a {

View File

@ -2,6 +2,7 @@
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import debug from 'debug';
import { i18n } from '$lib/i18n';
const dbg = debug('app:camera');
@ -92,27 +93,27 @@
});
</script>
<h2><i class="ti ti-device-gamepad"></i> Gamepad & Joystick Tests</h2>
<h2><i class="ti ti-device-gamepad"></i> {$i18n.t('Gamepad & Joystick Tests')}</h2>
<div class="controls">
<label>
Device
{$i18n.t('Device')}
<select disabled={!gamepads.length}>
{#each gamepads as gamepad}
<option value={gamepad.index}>{gamepad.id}</option>
{:else}
<option>No gamepads detected. (Try pressing a button)</option>
<option>{$i18n.t('No gamepads detected. (Try pressing a button)')}</option>
{/each}
</select>
</label>
<button on:click={refreshGamepads}>
<i class="ti ti-refresh"></i>
Refresh
{$i18n.t('Refresh')}
</button>
</div>
{#if currentGamepad}
<section>
<h3>Buttons</h3>
<h3>{$i18n.t('Buttons')}</h3>
<ul class="buttons">
{#each buttons as button, i}
<li class:pressed={button.pressed}>{i}</li>
@ -120,7 +121,7 @@
</ul>
</section>
<section>
<h3>Axes</h3>
<h3>{$i18n.t('Axes')}</h3>
<div class="axes">
{#each axes as axis, i (i)}
<div class="axis">
@ -130,7 +131,7 @@
<span>{axis.toFixed(2)}</span>
</div>
<details>
<summary>History</summary>
<summary>{$i18n.t('History')}</summary>
<canvas width="512" height="128" data-axis={i}></canvas>
</details>
</div>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { i18n } from '$lib/i18n';
let key: string;
let code: string;
@ -14,8 +15,8 @@
});
</script>
<h2>Keyboard testing</h2>
<p>Press a key on the keyboard to see the event object and the key code.</p>
<h2>{$i18n.t('Keyboard testing')}</h2>
<p>{$i18n.t('Press a key on the keyboard to see the event object and the key code.')}</p>
<div class="current">
{#if key}
<span>{key}</span>
@ -25,7 +26,7 @@
{/if}
</div>
<p>Pressed keys:</p>
<p>{$i18n.t('Pressed keys:')}</p>
<ul>
{#each pressedKeys as key}
<li>{key}</li>