aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-01-25 03:30:53 -0800
committerFuwn <[email protected]>2024-01-25 03:30:53 -0800
commit03345438ea0981882235a90bce97feda2e7df363 (patch)
tree1ab66f90a8aaeb00cffa52e715a88bf38dffdc94 /src
parentfix(wrapped): accidential user id overwrite (diff)
downloaddue.moe-03345438ea0981882235a90bce97feda2e7df363.tar.xz
due.moe-03345438ea0981882235a90bce97feda2e7df363.zip
feat(locale): localise profile page
Diffstat (limited to 'src')
-rw-r--r--src/lib/Locale/english.ts4
-rw-r--r--src/lib/Locale/japanese.ts5
-rw-r--r--src/lib/Locale/layout.ts4
-rw-r--r--src/lib/Settings/Categories/Display.svelte8
-rw-r--r--src/routes/user/[user]/+page.svelte33
-rw-r--r--src/stores/locale.ts68
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();