diff options
| author | Fuwn <[email protected]> | 2024-01-25 03:30:53 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-01-25 03:30:53 -0800 |
| commit | 03345438ea0981882235a90bce97feda2e7df363 (patch) | |
| tree | 1ab66f90a8aaeb00cffa52e715a88bf38dffdc94 /src | |
| parent | fix(wrapped): accidential user id overwrite (diff) | |
| download | due.moe-03345438ea0981882235a90bce97feda2e7df363.tar.xz due.moe-03345438ea0981882235a90bce97feda2e7df363.zip | |
feat(locale): localise profile page
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/Locale/english.ts | 4 | ||||
| -rw-r--r-- | src/lib/Locale/japanese.ts | 5 | ||||
| -rw-r--r-- | src/lib/Locale/layout.ts | 4 | ||||
| -rw-r--r-- | src/lib/Settings/Categories/Display.svelte | 8 | ||||
| -rw-r--r-- | src/routes/user/[user]/+page.svelte | 33 | ||||
| -rw-r--r-- | src/stores/locale.ts | 68 |
6 files changed, 92 insertions, 30 deletions
diff --git a/src/lib/Locale/english.ts b/src/lib/Locale/english.ts index 729c3a5b..8deca68b 100644 --- a/src/lib/Locale/english.ts +++ b/src/lib/Locale/english.ts @@ -144,6 +144,10 @@ const English: Locale = { or: 'or', delete: 'Delete (Click Twice)' } + }, + profile: { + statistics: '{username} has watched {anime} days of anime and read {manga} days of manga.', + badges: '{username} has collected {badges} badges using Badge Wall.' } } }; diff --git a/src/lib/Locale/japanese.ts b/src/lib/Locale/japanese.ts index 1d2b3f8b..60fc06e6 100644 --- a/src/lib/Locale/japanese.ts +++ b/src/lib/Locale/japanese.ts @@ -145,6 +145,11 @@ const Japanese: Locale = { or: 'または', delete: 'バッジを削除する(2回クリック)' } + }, + profile: { + statistics: + '{username}はAniListで{anime}日間のアニメ視聴と{manga}日間のマンガ読書を記録している。', + badges: '{username}はBadge Wallを使って{badges}個のバッジを収集しました。' } } }; diff --git a/src/lib/Locale/layout.ts b/src/lib/Locale/layout.ts index cefa8e05..485256ba 100644 --- a/src/lib/Locale/layout.ts +++ b/src/lib/Locale/layout.ts @@ -149,5 +149,9 @@ export interface Locale { delete: LocaleValue; }; }; + profile: { + statistics: LocaleValue; + badges: LocaleValue; + }; }; } diff --git a/src/lib/Settings/Categories/Display.svelte b/src/lib/Settings/Categories/Display.svelte index 9b63d179..24c8f7c1 100644 --- a/src/lib/Settings/Categories/Display.svelte +++ b/src/lib/Settings/Categories/Display.svelte @@ -108,10 +108,14 @@ /> <select bind:value={$settings.displayLanguage}> <option value="en"> - {$locale('en').settings.languages.english} + {$locale({ + locale: 'en' + }).settings.languages.english} </option> <option value="ja"> - {$locale('ja').settings.languages.japanese} + {$locale({ + locale: 'ja' + }).settings.languages.japanese} </option> </select> {$locale().settings.display.categories.motionAndAccessibility.fields.interfaceLanguage} diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte index d6248a3b..0fd32101 100644 --- a/src/routes/user/[user]/+page.svelte +++ b/src/routes/user/[user]/+page.svelte @@ -4,12 +4,21 @@ import { estimatedDayReading } from '$lib/Media/Manga/time'; import Skeleton from '$lib/Skeleton.svelte'; import root from '$lib/Utility/root.js'; + import locale from '$stores/locale.js'; import { onMount } from 'svelte'; export let data; let userData: User | undefined = undefined; + $: displayBadges = (username: string, badges: number | string) => + $locale({ + values: { + badges: badges, + username + } + }).user.profile.badges; + onMount(() => { user(data.username).then((profile) => { userData = profile; @@ -67,27 +76,29 @@ <a href={root(`/user/${userData.name}/badges`)}>Badge Wall</a> </p> - {data.username} has watched {(userData.statistics.anime.minutesWatched / 60 / 24).toFixed( - 1 - )} days of anime and read - {estimatedDayReading(userData.statistics.manga.chaptersRead).toFixed(1)} days of manga. + {$locale({ + values: { + username: data.username, + anime: (userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1), + manga: estimatedDayReading(userData.statistics.manga.chaptersRead).toFixed(1) + } + }).user.profile.statistics} <p /> - {data.username} has collected {#await fetch(root(`/api/badges?id=${userData.id}`))} - ... + {#await fetch(root(`/api/badges?id=${userData.id}`))} + {displayBadges(userData.name, '…')} {:then badges} {#await badges.json()} - ... + {displayBadges(userData.name, '…')} {:then badges} - {badges.length} + {displayBadges(userData.name, badges.length)} {:catch} - ? + {displayBadges(userData.name, '?')} {/await} {:catch} - ? + {displayBadges(userData.name, '?')} {/await} - badges using Badge Wall. </div> </div> </div> diff --git a/src/stores/locale.ts b/src/stores/locale.ts index ba657bf5..2105eb51 100644 --- a/src/stores/locale.ts +++ b/src/stores/locale.ts @@ -2,37 +2,71 @@ import { derived, type Readable } from 'svelte/store'; import { json } from 'svelte-i18n'; import type { Locale } from '$lib/Locale/layout'; -// type FormatXMLElementFn<T, R = string | T | (string | T)[]> = (parts: Array<string | T>) => R; - -// interface Options { -// id?: string; -// locale?: string; -// format?: string; -// default?: string; -// values?: -// | Record< -// string, -// string | number | boolean | Date | FormatXMLElementFn<unknown> | null | undefined -// > -// | undefined; -// } +type FormatXMLElementFn<T, R = string | T | (string | T)[]> = (parts: Array<string | T>) => R; + +type InterpolationValue = + | string + | number + | boolean + | Date + | FormatXMLElementFn<unknown> + | null + | undefined; + +type InterpolationValues = Record<string, InterpolationValue> | undefined; + +interface Options { + id?: string; + locale?: string; + format?: string; + default?: string; + values?: InterpolationValues; +} const createLocale = () => { return derived(json, ($json) => { - return (locale = undefined) => + return (options: Options = {}) => new Proxy( {}, { get(_target, key) { - const localisation = $json(key.toString(), locale); + const localisation = $json(key.toString(), options.locale); if (localisation === key.toString()) return undefined; + const replaceValues = ( + localisation: InterpolationValues, + values: InterpolationValues + ) => { + if (typeof localisation !== 'object' || localisation === null) return localisation; + + const updatedLocalisation: InterpolationValues = {}; + + for (const [key, value] of Object.entries(localisation)) { + if (typeof value === 'string') { + updatedLocalisation[key] = value.replace( + /\{(\w+)\}/g, + (match, name) => (values ? values[name] : match) as string + ); + } else { + updatedLocalisation[key] = replaceValues( + value as InterpolationValues, + values + ) as InterpolationValue; + } + } + + return updatedLocalisation; + }; + + if (options.values) + return replaceValues(localisation as unknown as InterpolationValues, options.values); + return localisation; } } ); - }) as Readable<(locale?: string) => Locale>; + }) as Readable<(options?: Options) => Locale>; }; const locale = createLocale(); |