add more i18n

This commit is contained in:
ari melody 2026-02-25 17:26:24 +00:00
parent 47130ed6c2
commit a42ac20e2d
Signed by: ari
GPG key ID: CF99829C92678188
3 changed files with 87 additions and 58 deletions

View file

@ -13,5 +13,28 @@
"section_settings_mta": "Mail Transfer Settings", "section_settings_mta": "Mail Transfer Settings",
"section_settings_version": "Running:", "section_settings_version": "Running:",
"dashboard_n_accounts_active": "Active: {count}" "dashboard_n_accounts_active": "Active: {count}",
"clipboard_email": "Email copied to clipboard.",
"account_configuration": "Account Configuration",
"account_actions": "Actions",
"account_action_send_email": "Send Email",
"account_action_reset_password": "Reset Password",
"account_action_delete_account": "Delete Account",
"account_action_delete_account_confirm": "Are you sure you wish to delete this account?\nThis action is irreversible.\n\nTo confirm, please enter {email}",
"account_action_delete_account_failed": "Failed to delete account:",
"account_action_delete_account_success": "Account deleted successfully.",
"account_details": "Details",
"account_detail_mail_directory": "Mail Directory:",
"warn_account_not_activated": "This account is not activated yet.",
"create_account": "Create Account",
"create_account_display_name": "Display Name",
"create_account_display_name_placeholder": "Example User",
"create_account_username": "Username",
"create_account_username_placeholder": "user",
"create_account_domain": "Domain",
"create_account_domain_placeholder": "example.org",
"create_account_failed": "Failed to create account:",
"create_account_succeess": "Account created successfully."
} }

View file

@ -6,6 +6,7 @@
import Label from '@jupiter/components/ui/Label.svelte'; import Label from '@jupiter/components/ui/Label.svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import * as api from '@jupiter/lib/api'; import * as api from '@jupiter/lib/api';
import { m } from '@jupiter/paraglide/messages.js';
const { data } = $props(); const { data } = $props();
@ -17,7 +18,7 @@
"text/plain": email, "text/plain": email,
})]); })]);
pushToast("Email copied to clipboard.", ToastType.SUCCESS); pushToast(m.clipboard_email(), ToastType.SUCCESS);
} }
async function resetPassword() { async function resetPassword() {
@ -25,21 +26,18 @@
} }
async function deleteAccount() { async function deleteAccount() {
if (prompt( if (prompt(m.account_action_delete_account_confirm({ email })) !== email) return;
"Are you sure you wish to delete this account? " +
"This action is irreversible.\n\n" +
`To confirm, please enter ${email}:`) !== email) return;
const res = await fetch(api.BASE_URL + "/api/v1/accounts/" + email, { const res = await fetch(api.BASE_URL + "/api/v1/accounts/" + email, {
method: "DELETE", method: "DELETE",
}) })
if (!res.ok) { if (!res.ok) {
const text = await res.text(); const text = await res.text();
pushToast("Failed to delete account: " + text, ToastType.ERROR); pushToast(m.account_action_delete_account_failed() + " " + text, ToastType.ERROR);
return return
} }
pushToast("Account deleted successfully.", ToastType.SUCCESS); pushToast(m.account_action_delete_account_success(), ToastType.SUCCESS);
goto("/accounts"); goto("/accounts");
} }
</script> </script>
@ -47,49 +45,49 @@
<div class="page-container"> <div class="page-container">
<Header> <Header>
<User /> <User />
<h1>Account Configuration</h1> <h1>{m.account_configuration()}</h1>
</Header> </Header>
<main> <main>
{#if account} <div class="account-title-container">
<div class="account-title-container"> <div class="account-title-icon">
<div class="account-title-icon"> <User />
<User />
</div>
<hr>
<h2 class="account-title">
<span>
{#if !account.activated}
<span class="warning-badge"><CircleAlert /></span>
{/if}
{account.display_name}
</span>
<button class="email" onclick={() => { copyEmail() }}>{email} <Copy /></button>
</h2>
</div> </div>
<hr> <hr>
<h2 class="account-title">
<span>
{#if !account.activated}
<span class="warning-badge"><CircleAlert /></span>
{/if}
{account.display_name}
</span>
<button class="email" onclick={() => { copyEmail() }}>{email} <Copy /></button>
</h2>
</div>
{#if !account.activated} <hr>
<p class="warning">* This account is not activated yet.</p>
{/if}
<Label>Actions</Label> {#if !account.activated}
<p class="warning">{m.warn_account_not_activated()}</p>
{/if}
<Label>{m.account_actions()}</Label>
<div class="account-actions"> <div class="account-actions">
<Button href="mailto:{email}"><Mail /> Send Email</Button> <Button href="mailto:{email}">
<Button onclick={() => resetPassword()}><KeyRound /> Reset Password</Button> <Mail /> {m.account_action_send_email()}
</Button>
<Button onclick={() => resetPassword()}>
<KeyRound /> {m.account_action_reset_password()}
</Button>
<Button onclick={() => deleteAccount()} class="delete"> <Button onclick={() => deleteAccount()} class="delete">
<Trash /> Delete Account <Trash /> {m.account_action_delete_account()}
</Button> </Button>
</div> </div>
<Label>Details</Label> <Label>{m.account_details()}</Label>
<div class="account-details"> <div class="account-details">
<p>Mail Directory: <code>{account.mail_directory}</code></p> <p>{m.account_detail_mail_directory()} <code>{account.mail_directory}</code></p>
</div> </div>
{:else}
<p>Just a moment...</p>
{/if}
</main> </main>
</div> </div>

View file

@ -8,6 +8,7 @@
import { type Account } from '@jupiter/lib/account'; import { type Account } from '@jupiter/lib/account';
import AccountListItem from '@jupiter/components/ui/AccountListItem.svelte'; import AccountListItem from '@jupiter/components/ui/AccountListItem.svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { m } from '@jupiter/paraglide/messages';
let domainInput: HTMLInputElement; let domainInput: HTMLInputElement;
@ -35,12 +36,12 @@
}); });
if (!res.ok) { if (!res.ok) {
const text = await res.text(); const text = await res.text();
const err = new Error("Failed to create account: " + text); const err = new Error(m.create_account_failed() + " " + text);
pushToast(err.message, ToastType.ERROR); pushToast(err.message, ToastType.ERROR);
throw err; throw err;
} }
pushToast("Account created successfully.", ToastType.SUCCESS); pushToast(m.create_account_succeess(), ToastType.SUCCESS);
goto("/accounts"); goto("/accounts");
} }
@ -50,32 +51,39 @@
<div class="page-container"> <div class="page-container">
<Header> <Header>
<UserRoundPlus /> <UserRoundPlus />
<h1>Create Account</h1> <h1>{m.create_account()}</h1>
</Header> </Header>
<main> <main>
<div class="form"> <div class="form">
<Label>Display Name</Label> <Label>{m.create_account_display_name()}</Label>
<input type="text" placeholder="Example User" bind:value={newAccount.display_name}> <input
type="text"
placeholder="{m.create_account_display_name_placeholder()}"
bind:value={newAccount.display_name}>
<Label>Username</Label> <Label>{m.create_account_username()}</Label>
<input <input
type="text" type="text"
placeholder="user" placeholder="{m.create_account_username_placeholder()}"
bind:value={newAccount.username} bind:value={newAccount.username}
onkeydown={(event: KeyboardEvent) => { onkeydown={(event: KeyboardEvent) => {
if (event.key === "@") { if (event.key === "@") {
event.preventDefault(); event.preventDefault();
domainInput.focus(); domainInput.focus();
} }
}}> }}>
<Label>Domain</Label> <Label>{m.create_account_domain()}</Label>
<input type="text" placeholder="example.org" bind:value={newAccount.domain} bind:this={domainInput}> <input
type="text"
placeholder="{m.create_account_domain_placeholder()}"
bind:value={newAccount.domain}
bind:this={domainInput}>
<AccountListItem account={newAccount} /> <AccountListItem account={newAccount} />
<Button onclick={() => {createAccount()}}>Create Account</Button> <Button onclick={() => {createAccount()}}>{m.create_account()}</Button>
</div> </div>
</main> </main>
</div> </div>