Add per account locale setting

Add a per user account setting for the locale so that the server can
correctly render pages with localized time formatting.
This commit is contained in:
Hornwitser 2025-06-13 21:50:22 +02:00
parent fad1bb2482
commit fb7a60db28
5 changed files with 28 additions and 0 deletions

View file

@ -9,6 +9,7 @@ export default defineNuxtConfig({
vapidPrivateKeyFile: "",
public: {
defaultTimezone: "Europe/Oslo",
defaultLocale: "en-GB",
vapidPublicKey: "",
}
},

View file

@ -10,6 +10,10 @@
Timezone
<input type="text" v-model="timezone" :placeholder="accountStore.defaultTimezone">
</label>
<label>
Locale
<input type="text" v-model="locale" :placeholder="accountStore.defaultLocale">
</label>
<button type="submit">
Save
</button>
@ -38,6 +42,7 @@ const sessionStore = useSessionStore();
const accountStore = useAccountStore();
const timezone = ref(accountStore.timezone ?? "");
const locale = ref(accountStore.locale ?? "");
async function changeSettings() {
try {
@ -45,6 +50,7 @@ async function changeSettings() {
method: "patch",
body: {
timezone: timezone.value,
locale: locale.value,
}
});
await sessionStore.fetch();

View file

@ -24,6 +24,15 @@ export default defineEventHandler(async (event) => {
});
}
}
if (patch.locale?.length) {
const locale = DateTime.local({ locale: patch.locale }).resolvedLocaleOptions().locale;
if (locale !== patch.locale) {
throw createError({
status: 400,
message: `Invalid locale: the locale "${patch.locale}" is not supported (was treated as "${locale}")`
});
}
}
const accounts = await readAccounts();
const sessionAccount = accounts.find(account => account.id === session.accountId);
@ -51,6 +60,12 @@ export default defineEventHandler(async (event) => {
else
delete sessionAccount.timezone;
}
if (patch.locale !== undefined) {
if (patch.locale)
sessionAccount.locale = patch.locale;
else
delete sessionAccount.locale;
}
await writeAccounts(accounts);
// Update Schedule counts.

View file

@ -9,6 +9,7 @@ export interface ApiAccount {
interestedEventIds?: number[],
interestedEventSlotIds?: number[],
timezone?: string,
locale?: string,
}
export const apiAccountPatchSchema = z.object({
@ -16,6 +17,7 @@ export const apiAccountPatchSchema = z.object({
interestedEventIds: z.optional(z.array(z.number())),
interestedEventSlotIds: z.optional(z.array(z.number())),
timezone: z.optional(z.string()),
locale: z.optional(z.string()),
});
export type ApiAccountPatch = z.infer<typeof apiAccountPatchSchema>;

View file

@ -8,6 +8,7 @@ export const useAccountStore = defineStore("account", () => {
id: ref<number>(),
name: ref<string>(),
timezone: ref<string>(),
locale: ref<string>(),
type: ref<ApiAccount["type"]>(),
interestedEventIds: ref<Set<number>>(new Set()),
interestedEventSlotIds: ref<Set<number>>(new Set()),
@ -19,6 +20,7 @@ export const useAccountStore = defineStore("account", () => {
state.id.value = account?.id;
state.name.value = account?.name;
state.timezone.value = account?.timezone;
state.locale.value = account?.locale;
state.type.value = account?.type;
state.interestedEventIds.value = new Set(account?.interestedEventIds ?? []);
state.interestedEventSlotIds.value = new Set(account?.interestedEventSlotIds ?? []);
@ -30,6 +32,8 @@ export const useAccountStore = defineStore("account", () => {
canEditPublic: computed(() => state.type.value === "admin"),
activeTimezone: computed(() => state.timezone.value || runtimeConfig.public.defaultTimezone),
defaultTimezone: computed(() => runtimeConfig.public.defaultTimezone),
activeLocale: computed(() => state.locale.value || runtimeConfig.public.defaultLocale),
defaultLocale: computed(() => runtimeConfig.public.defaultLocale),
};
const actions = {