summaryrefslogtreecommitdiffstats
path: root/apps/web-shared/src
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web-shared/src')
-rw-r--r--apps/web-shared/src/components/blowout-toolbelt.svelte2
-rw-r--r--apps/web-shared/src/components/stopwatch.svelte35
-rw-r--r--apps/web-shared/src/lib/i18n/en/index.ts13
-rw-r--r--apps/web-shared/src/lib/i18n/formatters.ts11
-rw-r--r--apps/web-shared/src/lib/i18n/i18n-types.ts66
-rw-r--r--apps/web-shared/src/lib/i18n/i18n-util.async.ts27
-rw-r--r--apps/web-shared/src/lib/i18n/i18n-util.sync.ts27
-rw-r--r--apps/web-shared/src/lib/i18n/i18n-util.ts31
-rw-r--r--apps/web-shared/src/lib/i18n/nb/index.ts13
-rw-r--r--apps/web-shared/src/lib/locale.ts21
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());
+});