From b170a532f6d118a4aa79d4c9942c4923b70275c2 Mon Sep 17 00:00:00 2001 From: ari melody Date: Sun, 13 Jul 2025 19:04:50 +0100 Subject: [PATCH 1/2] use `fqn` for local account instead of building manually --- src/lib/account.js | 2 ++ src/lib/ui/Navigation.svelte | 2 +- src/routes/+layout.svelte | 2 +- src/routes/callback/+page.svelte | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/account.js b/src/lib/account.js index 7bfd696..15ee53c 100644 --- a/src/lib/account.js +++ b/src/lib/account.js @@ -31,6 +31,8 @@ export function parseAccount(data) { else account.host = get(server).host; + account.fqn = data.fqn || account.username + account.host; + account.mention = "@" + account.username; if (account.host != get(server).host) account.mention += "@" + account.host; diff --git a/src/lib/ui/Navigation.svelte b/src/lib/ui/Navigation.svelte index e977153..d580d2d 100644 --- a/src/lib/ui/Navigation.svelte +++ b/src/lib/ui/Navigation.svelte @@ -175,7 +175,7 @@ diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 8abb605..03842da 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -28,7 +28,7 @@ if (!data) return; account.set(parseAccount(data)); - console.log(`Logged in as @${$account.username}@${$account.host}`); + console.log(`Logged in as ${$account.fqn}`); // spin up async task to fetch notifications const notif_data = await api.getNotifications( diff --git a/src/routes/callback/+page.svelte b/src/routes/callback/+page.svelte index 8b6985e..751e4a3 100644 --- a/src/routes/callback/+page.svelte +++ b/src/routes/callback/+page.svelte @@ -30,7 +30,7 @@ if (!data) return goto("/"); account.set(parseAccount(data)); - console.log(`Logged in as @${get(account).username}@${get(account).host}`); + console.log(`Logged in as ${get(account).fqn}`); // spin up async task to fetch notifications return api.getNotifications( From 7752585488761e185a18f863b19a039e33ea4194 Mon Sep 17 00:00:00 2001 From: ari melody Date: Sun, 13 Jul 2025 20:44:54 +0100 Subject: [PATCH 2/2] add i18n for console logs --- src/lang/en_GB.json | 27 +++++++++++++++++-- src/lib/account.js | 7 +++-- src/lib/client/server.js | 10 +++---- src/lib/lang.js | 14 ++++++++-- src/lib/sound.js | 6 ++++- src/lib/time.js | 2 +- src/lib/timeline.js | 11 +++++--- src/lib/ui/Composer.svelte | 2 +- src/lib/ui/Navigation.svelte | 2 +- src/lib/ui/post/BoostContext.svelte | 2 +- src/routes/+layout.svelte | 2 +- src/routes/+page.svelte | 2 +- .../[server]/[account]/[post]/+page.svelte | 12 ++++----- src/routes/callback/+page.svelte | 9 ++++--- 14 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/lang/en_GB.json b/src/lang/en_GB.json index 0f80eb4..65379a8 100644 --- a/src/lang/en_GB.json +++ b/src/lang/en_GB.json @@ -1,10 +1,10 @@ { "compose_placeholders": [ - "What's cooking, $1?", + "What's cooking, %1?", "Speak your mind!", "Federate something...", "I sure love posting!", - "Another day, another $1 post!" + "Another day, another %1 post!" ], "login": { @@ -84,6 +84,29 @@ } }, + "logs": { + "logged_in": "Logged in as %1", + "server_detected": "Server detected as %1 (%2) with capabilities: {%3}}", + "server_unsupported": "Server %1 is unsupported (%2). Things may break, or not work as expected", + "no_hostname": "Attempted to connect to a server without providing a hostname", + "no_https": "Cowardly refusing to connect to an insecure server", + "connection_failed": "Failed to connect to %1", + "post_fetch_failed": "Failed to fetch post %1", + "post_parse_failed": "Failed to parse post", + "post_parse_failed_id": "Failed to parse post %1", + "token_revoke_failed": "Token revocation failed! Dumping data anyways", + "sound_does_not_exist": "Attempted to play sound \"%1\", which does not exist!", + "account_data_empty": "Attempted to parse account data but no data was provided", + "timeline_fetch_failed": "Failed to retrieve timeline." + }, + + "error": { + "bad_request": "Bad request", + "invalid_auth_code": "Invalid auth code provided", + "connection_failed": "Failed to connect to %1.", + "post_fetch_failed": "Failed to retrieve post %1." + }, + "compose": "Post", "search": "Search", "loading": "just a moment...", diff --git a/src/lib/account.js b/src/lib/account.js index 15ee53c..394fe0f 100644 --- a/src/lib/account.js +++ b/src/lib/account.js @@ -1,6 +1,9 @@ import { server } from '$lib/client/server.js'; import { parseEmoji, renderEmoji } from '$lib/emoji.js'; import { get, writable } from 'svelte/store'; +import Lang from '$lib/lang'; + +const lang = Lang('en_GB'); const cache = writable({}); @@ -11,7 +14,7 @@ const cache = writable({}); */ export function parseAccount(data) { if (!data) { - console.error("Attempted to parse account data but no data was provided"); + console.error(lang.string('logs.account_data_empty')); return null; } let account = get(cache)[data.id]; @@ -20,7 +23,7 @@ export function parseAccount(data) { account = {}; account.id = data.id; - account.nickname = data.display_name.trim(); + account.nickname = data.display_name.trim().replaceAll('<', '<').replaceAll('>', '>'); account.username = data.username; account.name = account.nickname || account.username; account.avatar_url = data.avatar; diff --git a/src/lib/client/server.js b/src/lib/client/server.js index 6b42ffe..3c85647 100644 --- a/src/lib/client/server.js +++ b/src/lib/client/server.js @@ -35,11 +35,11 @@ server.subscribe(server => { */ export async function createServer(host) { if (!host) { - console.error("Attempted to create server without providing a hostname"); + console.error(lang.string('logs.no_hostname')); return false; } if (host.startsWith("http://")) { - console.error("Cowardly refusing to connect to an insecure server"); + console.error(lang.string('logs.no_https')); return false; } @@ -49,7 +49,7 @@ export async function createServer(host) { if (host.startsWith("https://")) host = host.substring(8); const data = await api.getInstance(host); if (!data) { - console.error(`Failed to connect to ${host}`); + console.error(lang.string('logs.connection_failed', host)); return false; } @@ -58,9 +58,9 @@ export async function createServer(host) { server.capabilities = getCapabilities(server.type); if (server.type === server_types.UNSUPPORTED) { - console.warn(`Server ${host} is unsupported (${server.version}). Things may break, or not work as expected`); + console.warn(lang.string('logs.server_unsupported', host, server.version)); } else { - console.log(`Server detected as "${server.type}" (${server.version}) with capabilities: {${server.capabilities.join(', ')}}`); + console.log(lang.string('logs.server_detected', server.type, server.version, server.capabilities.join(', '))); } return server; diff --git a/src/lib/lang.js b/src/lib/lang.js index 8e90901..955a749 100644 --- a/src/lib/lang.js +++ b/src/lib/lang.js @@ -19,7 +19,7 @@ export default function init(lang) { i18n.lang = language; i18n.lang_code = lang; - i18n.string = function(/* @type string */ key) { + i18n.string = function(/* @type string */ key, ...args) { const tokens = key.split('.'); let i = 0; @@ -32,10 +32,20 @@ export default function init(lang) { return key; } if (typeof res === 'string' || res instanceof String) - return res; + break; i++; token = tokens[i]; } + + i = 1; + while (true) { + if (args.length < i || !res.includes('%' + i)) + break; + res = res.replaceAll('%' + i, args[i - 1]); + i++; + } + + return res; } i18n.stringArray = function(/* @type string */ key) { const tokens = key.split('.'); diff --git a/src/lib/sound.js b/src/lib/sound.js index 377b833..9c94547 100644 --- a/src/lib/sound.js +++ b/src/lib/sound.js @@ -1,3 +1,7 @@ +import Lang from '$lib/lang'; + +const lang = Lang('en_GB'); + import sound_log from '../sound/log.ogg'; import sound_hello from '../sound/hello.ogg'; import sound_success from '../sound/success.ogg'; @@ -16,7 +20,7 @@ export function playSound(name) { if (!name) name = "default"; const sound = sounds[name]; if (!sound) { - console.warn(`Attempted to play sound "${name}", which does not exist!`); + console.warn(lang.string('lang.sound_does_not_exist', name)); return; } sound.pause(); diff --git a/src/lib/time.js b/src/lib/time.js index 9a1c4eb..99811bf 100644 --- a/src/lib/time.js +++ b/src/lib/time.js @@ -21,6 +21,6 @@ export function shorthand(date) { unit = denoms[index].unit; } if (value > 0) - return lang.string('post.time').replaceAll('%1', Math.floor(value) + unit); + return lang.string('post.time', Math.floor(value) + unit); return "in " + Math.floor(value) + unit; } diff --git a/src/lib/timeline.js b/src/lib/timeline.js index ae8a5e3..03e5052 100644 --- a/src/lib/timeline.js +++ b/src/lib/timeline.js @@ -3,9 +3,12 @@ import { server } from '$lib/client/server.js'; import { app } from '$lib/client/app.js'; import { get, writable } from 'svelte/store'; import { parsePost } from '$lib/post.js'; +import Lang from '$lib/lang'; export const timeline = writable([]); +const lang = Lang('en_GB'); + let loading = false; export async function getTimeline(clean) { @@ -24,7 +27,7 @@ export async function getTimeline(clean) { ); if (!timeline_data) { - console.error(`Failed to retrieve timeline.`); + console.error(lang.string('logs.timeline_fetch_failed')); loading = false; return; } @@ -37,10 +40,10 @@ export async function getTimeline(clean) { if (!post) { if (post === null || post === undefined) { if (post_data.id) { - console.warn("Failed to parse post #" + post_data.id); + console.warn(lang.string('logs.post_parse_failed_id', post_data.id)); } else { - console.warn("Failed to parse post:"); - console.warn(post_data); + console.warn(lang.string('logs.post_parse_failed')); + console.debug(post_data); } } continue; diff --git a/src/lib/ui/Composer.svelte b/src/lib/ui/Composer.svelte index 2d5d231..7859a7e 100644 --- a/src/lib/ui/Composer.svelte +++ b/src/lib/ui/Composer.svelte @@ -32,7 +32,7 @@ const placeholders = lang.stringArray('compose_placeholders'); let placeholder = Array.isArray(placeholders) ? placeholders[Math.floor(placeholders.length * Math.random())] - .replaceAll("$1", $account.username) : placeholders; + .replaceAll("%1", $account.username) : placeholders; const dispatch = createEventDispatcher(); diff --git a/src/lib/ui/Navigation.svelte b/src/lib/ui/Navigation.svelte index d580d2d..96f4879 100644 --- a/src/lib/ui/Navigation.svelte +++ b/src/lib/ui/Navigation.svelte @@ -72,7 +72,7 @@ ); if (!res.ok) - console.warn("Token revocation failed! Dumping data anyways"); + console.warn(lang.string('logs.token_revoke_failed')); account.set(false); app.set(false); diff --git a/src/lib/ui/post/BoostContext.svelte b/src/lib/ui/post/BoostContext.svelte index 0e7aed1..06677e0 100644 --- a/src/lib/ui/post/BoostContext.svelte +++ b/src/lib/ui/post/BoostContext.svelte @@ -13,7 +13,7 @@ 🔁 { @html - lang.string('post.boosted').replaceAll('%1', + lang.string('post.boosted', `${post.account.rich_name}`) } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 03842da..7f84883 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -28,7 +28,7 @@ if (!data) return; account.set(parseAccount(data)); - console.log(`Logged in as ${$account.fqn}`); + console.log(lang.string('logs.logged_in', $account.fqn)); // spin up async task to fetch notifications const notif_data = await api.getNotifications( diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 6370b53..4776e7a 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -14,7 +14,7 @@ if (account) getTimeline(); }); - document.addEventListener("scroll", () => { + document.addEventListener('scroll', () => { if ($account && $page.url.pathname !== "/") return; if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) { getTimeline(); diff --git a/src/routes/[server]/[account]/[post]/+page.svelte b/src/routes/[server]/[account]/[post]/+page.svelte index 56a28a2..4ab384f 100644 --- a/src/routes/[server]/[account]/[post]/+page.svelte +++ b/src/routes/[server]/[account]/[post]/+page.svelte @@ -33,16 +33,16 @@ // TODO: make `server` a key/value pair to support multiple servers server.set(await createServer(data.server_host)); if (!$server) { - error = `Failed to connect to ${data.server_host}.`; - console.error(`Failed to connect to ${data.server_host}.`); + error = lang.string('error.connection_failed', data.server_host); + console.error(lang.string('logs.connection_failed', data.server_host)); return; } } const post_data = await api.getPost($server.host, token, post_id); if (!post_data || post_data.error) { - error = `Failed to retrieve post ${post_id}.`; - console.error(`Failed to retrieve post ${post_id}.`); + error = lang.string('error.post_fetch_failed', post_id); + console.error(lang.string('logs.post_fetch_failed', post_id)); return; } let post = await parsePost(post_data, 0); @@ -83,9 +83,9 @@ {/if} - +

- {@html lang.string('post.by').replaceAll('%1', post.account.rich_name)} + {@html lang.string('post.by', post.account.rich_name)}

diff --git a/src/routes/callback/+page.svelte b/src/routes/callback/+page.svelte index 751e4a3..8d9d0f8 100644 --- a/src/routes/callback/+page.svelte +++ b/src/routes/callback/+page.svelte @@ -8,17 +8,20 @@ import { error } from '@sveltejs/kit'; import { unread_notif_count, last_read_notif_id } from '$lib/notifications.js'; import { account } from '$lib/stores/account.js'; + import Lang from '$lib/lang'; export let data; + const lang = Lang('en_GB'); + let auth_code = data.code; if (!auth_code || !get(server) || !get(app)) { - error(400, { message: "Bad request" }); + error(400, { message: lang.string('error.bad_request') }); } else { api.getToken(get(server).host, get(app).id, get(app).secret, auth_code).then(token => { if (!token) { - error(400, { message: "Invalid auth code provided" }); + error(400, { message: lang.string('error.invalid_auth_code') }); } app.update(app => { @@ -30,7 +33,7 @@ if (!data) return goto("/"); account.set(parseAccount(data)); - console.log(`Logged in as ${get(account).fqn}`); + console.log(lang.string('logs.logged_in', get(account).fqn)); // spin up async task to fetch notifications return api.getNotifications(