diff options
Diffstat (limited to 'apps/web-shared/src')
| -rw-r--r-- | apps/web-shared/src/components/blowout-toolbelt.svelte | 2 | ||||
| -rw-r--r-- | apps/web-shared/src/components/stopwatch.svelte | 35 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/en/index.ts | 13 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/formatters.ts | 11 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/i18n-types.ts | 66 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/i18n-util.async.ts | 27 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/i18n-util.sync.ts | 27 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/i18n-util.ts | 31 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/i18n/nb/index.ts | 13 | ||||
| -rw-r--r-- | apps/web-shared/src/lib/locale.ts | 21 |
10 files changed, 234 insertions, 12 deletions
diff --git a/apps/web-shared/src/components/blowout-toolbelt.svelte b/apps/web-shared/src/components/blowout-toolbelt.svelte index 69e9902..b611a2d 100644 --- a/apps/web-shared/src/components/blowout-toolbelt.svelte +++ b/apps/web-shared/src/components/blowout-toolbelt.svelte @@ -32,7 +32,7 @@ right: 0 !important; } </style> -<aside class="blowout position-fixed bg-light inner-glow shadow-xs padding-xxs bottom-50% right-0 z-index-2 {expanded ? 'expanded' : ''}"> +<aside class="blowout position-fixed bg-light inner-glow shadow-xs padding-xxs bottom-50% right-0 z-index-popover {expanded ? 'expanded' : ''}"> <LocaleSwitcher bind:show="{localeSwitcher.show}" glow="{false}" on:change={locale_change} diff --git a/apps/web-shared/src/components/stopwatch.svelte b/apps/web-shared/src/components/stopwatch.svelte index 3ed0d0e..1c602c8 100644 --- a/apps/web-shared/src/components/stopwatch.svelte +++ b/apps/web-shared/src/components/stopwatch.svelte @@ -2,6 +2,10 @@ import Button from "$shared/components/button.svelte"; import {Textarea} from "$shared/components/form"; import {StorageKeys} from "$shared/lib/configuration"; + import {TranslationFunctions} from "$shared/lib/i18n/i18n-types"; + import {loadLocaleAsync} from "$shared/lib/i18n/i18n-util.async"; + import {i18nObject} from "$shared/lib/i18n/i18n-util"; + import {currentLocale} from "$shared/lib/locale"; import {StoreType, writable_persistent} from "$shared/lib/persistent-store"; import {Temporal} from "@js-temporal/polyfill"; import {createEventDispatcher, onMount} from "svelte"; @@ -24,6 +28,7 @@ }); let timeString; + let LL = i18nObject($currentLocale); $: if ($state.hours || $state.minutes || $state.seconds) { timeString = $state.hours.toLocaleString(undefined, {minimumIntegerDigits: 2}) @@ -33,15 +38,22 @@ timeString = "--:--:--"; } - onMount(() => { + currentLocale.subscribe(async val => { + await loadLocaleAsync(val); + LL = i18nObject(val); + }); + + onMount(async () => { start_if_running(); + await loadLocaleAsync($currentLocale); + LL = i18nObject($currentLocale); }); function start_if_running() { if ($state.isRunning) { if (Temporal.PlainDateTime.compare($state.lastStep, Temporal.Now.plainDateTimeISO()) == -1) { const duration = Temporal.Now.plainDateTimeISO().since($state.lastStep, {smallestUnit: "second"}); - console.log("lastStep",$state.lastStep.toString()); + console.log("lastStep", $state.lastStep.toString()); console.log("duration", duration.toString()); console.log(duration.seconds); // for (let i = 0; i < steps; i++) { @@ -152,23 +164,23 @@ on:click={on_start_stop}/> {#if $state.startTime} - <Button title="Reset" - text="Reset" + <Button title="{LL.stopwatch.reset()}" + text="{LL.stopwatch.reset()}" variant="link" class="bg-error-lighter@hover color-white@hover" on:click={reset}/> {#if !$state.isRunning} - <Button title="Round up" - text="Round up" + <Button title="{LL.stopwatch.roundUp()}" + text="{LL.stopwatch.roundUp()}" variant="link" on:click={on_round_up}/> - <Button title="Round down" - text="Round down" + <Button title="{LL.stopwatch.roundDown()}" + text="{LL.stopwatch.roundDown()}" variant="link" on:click={on_round_down}/> {#if $state.minutes > 0 || $state.hours > 0} - <Button title="Create entry" - text="Create entry" + <Button title="{LL.stopwatch.createEntry()}" + text="{LL.stopwatch.createEntry()}" variant="link" on:click={on_create_entry}/> {/if} @@ -176,8 +188,9 @@ {/if} </div> </div> + <Textarea class="width-100% margin-top-xs" - placeholder="What's your focus?" + placeholder="{LL.stopwatch.whatsYourFocus()}" rows="1" bind:value={$state.note} /> diff --git a/apps/web-shared/src/lib/i18n/en/index.ts b/apps/web-shared/src/lib/i18n/en/index.ts new file mode 100644 index 0000000..65fc0df --- /dev/null +++ b/apps/web-shared/src/lib/i18n/en/index.ts @@ -0,0 +1,13 @@ +import type {BaseTranslation} from "../i18n-types"; + +const en: BaseTranslation = { + stopwatch: { + roundUp: "Round up", + roundDown: "Round down", + createEntry: "Create entry", + whatsYourFocus: "What's your focus?", + reset: "Reset" + } +}; + +export default en; diff --git a/apps/web-shared/src/lib/i18n/formatters.ts b/apps/web-shared/src/lib/i18n/formatters.ts new file mode 100644 index 0000000..78734f9 --- /dev/null +++ b/apps/web-shared/src/lib/i18n/formatters.ts @@ -0,0 +1,11 @@ +import type { FormattersInitializer } from 'typesafe-i18n' +import type { Locales, Formatters } from './i18n-types' + +export const initFormatters: FormattersInitializer<Locales, Formatters> = (locale: Locales) => { + + const formatters: Formatters = { + // add your formatter functions here + } + + return formatters +} diff --git a/apps/web-shared/src/lib/i18n/i18n-types.ts b/apps/web-shared/src/lib/i18n/i18n-types.ts new file mode 100644 index 0000000..2048802 --- /dev/null +++ b/apps/web-shared/src/lib/i18n/i18n-types.ts @@ -0,0 +1,66 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ +import type { BaseTranslation as BaseTranslationType, LocalizedString } from 'typesafe-i18n' + +export type BaseTranslation = BaseTranslationType +export type BaseLocale = 'en' + +export type Locales = + | 'en' + | 'nb' + +export type Translation = RootTranslation + +export type Translations = RootTranslation + +type RootTranslation = { + stopwatch: { + /** + * Round up + */ + roundUp: string + /** + * Round down + */ + roundDown: string + /** + * Create entry + */ + createEntry: string + /** + * What's your focus? + */ + whatsYourFocus: string + /** + * Reset + */ + reset: string + } +} + +export type TranslationFunctions = { + stopwatch: { + /** + * Round up + */ + roundUp: () => LocalizedString + /** + * Round down + */ + roundDown: () => LocalizedString + /** + * Create entry + */ + createEntry: () => LocalizedString + /** + * What's your focus? + */ + whatsYourFocus: () => LocalizedString + /** + * Reset + */ + reset: () => LocalizedString + } +} + +export type Formatters = {} diff --git a/apps/web-shared/src/lib/i18n/i18n-util.async.ts b/apps/web-shared/src/lib/i18n/i18n-util.async.ts new file mode 100644 index 0000000..90e55a7 --- /dev/null +++ b/apps/web-shared/src/lib/i18n/i18n-util.async.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters' +import type { Locales, Translations } from './i18n-types.js' +import { loadedFormatters, loadedLocales, locales } from './i18n-util' + +const localeTranslationLoaders = { + en: () => import('./en/index.js'), + nb: () => import('./nb/index.js'), +} + +const updateDictionary = (locale: Locales, dictionary: Partial<Translations>) => + loadedLocales[locale] = { ...loadedLocales[locale], ...dictionary } + +export const loadLocaleAsync = async (locale: Locales): Promise<void> => { + updateDictionary( + locale, + (await localeTranslationLoaders[locale]()).default as unknown as Translations + ) + loadFormatters(locale) +} + +export const loadAllLocalesAsync = (): Promise<void[]> => Promise.all(locales.map(loadLocaleAsync)) + +export const loadFormatters = (locale: Locales): void => + void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/apps/web-shared/src/lib/i18n/i18n-util.sync.ts b/apps/web-shared/src/lib/i18n/i18n-util.sync.ts new file mode 100644 index 0000000..8909831 --- /dev/null +++ b/apps/web-shared/src/lib/i18n/i18n-util.sync.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters' +import type { Locales, Translations } from './i18n-types.js' +import { loadedFormatters, loadedLocales, locales } from './i18n-util' + +import en from './en/index.js' +import nb from './nb/index.js' + +const localeTranslations = { + en, + nb, +} + +export const loadLocale = (locale: Locales): void => { + if (loadedLocales[locale]) return + + loadedLocales[locale] = localeTranslations[locale] as unknown as Translations + loadFormatters(locale) +} + +export const loadAllLocales = (): void => locales.forEach(loadLocale) + +export const loadFormatters = (locale: Locales): void => { + loadedFormatters[locale] = initFormatters(locale) +} diff --git a/apps/web-shared/src/lib/i18n/i18n-util.ts b/apps/web-shared/src/lib/i18n/i18n-util.ts new file mode 100644 index 0000000..5a9dd0d --- /dev/null +++ b/apps/web-shared/src/lib/i18n/i18n-util.ts @@ -0,0 +1,31 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { i18n as initI18n, i18nObject as initI18nObject, i18nString as initI18nString } from 'typesafe-i18n' +import type { LocaleDetector } from 'typesafe-i18n/detectors' +import { detectLocale as detectLocaleFn } from 'typesafe-i18n/detectors' +import type { Formatters, Locales, Translations, TranslationFunctions } from './i18n-types.js' + +export const baseLocale: Locales = 'en' + +export const locales: Locales[] = [ + 'en', + 'nb' +] + +export const loadedLocales = {} as Record<Locales, Translations> + +export const loadedFormatters = {} as Record<Locales, Formatters> + +export const i18nString = (locale: Locales) => initI18nString<Locales, Formatters>(locale, loadedFormatters[locale]) + +export const i18nObject = (locale: Locales) => + initI18nObject<Locales, Translations, TranslationFunctions, Formatters>( + locale, + loadedLocales[locale], + loadedFormatters[locale] + ) + +export const i18n = () => initI18n<Locales, Translations, TranslationFunctions, Formatters>(loadedLocales, loadedFormatters) + +export const detectLocale = (...detectors: LocaleDetector[]) => detectLocaleFn<Locales>(baseLocale, locales, ...detectors) diff --git a/apps/web-shared/src/lib/i18n/nb/index.ts b/apps/web-shared/src/lib/i18n/nb/index.ts new file mode 100644 index 0000000..d7f557d --- /dev/null +++ b/apps/web-shared/src/lib/i18n/nb/index.ts @@ -0,0 +1,13 @@ +import type {Translation} from "../i18n-types"; + +const nb: Translation = { + stopwatch: { + roundUp: "Rund opp", + roundDown: "Rund ned", + createEntry: "Opprett tidsoppføring", + whatsYourFocus: "Hva skal du fokusere på?", + reset: "Tilbakestill" + } +}; + +export default nb; diff --git a/apps/web-shared/src/lib/locale.ts b/apps/web-shared/src/lib/locale.ts new file mode 100644 index 0000000..acb9ae5 --- /dev/null +++ b/apps/web-shared/src/lib/locale.ts @@ -0,0 +1,21 @@ +import {writable} from "svelte/store"; +import {base_domain, CookieNames} from "./configuration"; +import {get_cookie, set_cookie} from "./helpers"; + +export function preffered_or_default() { + if (/^en\b/i.test(navigator.language)) { + return "en"; + } + if (/^nb\b/i.test(navigator.language) || /^nn\b/i.test(navigator.language)) { + return "nb"; + } + return "en"; +} + +type Locales = "en"|"nb"; +export const currentLocale = writable<Locales>((get_cookie(CookieNames.locale) ?? preffered_or_default()) as Locales); +currentLocale.subscribe(locale => { + //@ts-ignore + if (locale === "preffered") set_cookie(CookieNames.locale, preffered_or_default(), base_domain()); + set_cookie(CookieNames.locale, locale, base_domain()); +}); |
