diff --git a/src/lang/en_GB.json b/src/lang/en_GB.json new file mode 100644 index 0000000..ea6a3b6 --- /dev/null +++ b/src/lang/en_GB.json @@ -0,0 +1,88 @@ +{ + "compose_placeholders": [ + "What's cooking, $1?", + "Speak your mind!", + "Federate something...", + "I sure love posting!", + "Another day, another $1 post!" + ], + + "login": { + "welcome": "Welcome, fediverse user!", + "enter_domain": "Please enter your server domain to log in.", + "experimental": "Please note this is\nextremely experimental software;\nthings are likely to break!\n
\nIf that's all cool with you, welcome aboard!", + "button": "Log in", + "error": { + "no_domain": "Please enter an server domain.", + "connection_failed": "Failed to connect to the server.\nCheck the browser console for details!", + "create_app": "Failed to create an application for this server." + }, + "made_with_tagline": "made with ❤ by bliss town" + }, + + "navigation": { + "timeline": "Timeline", + "notifications": "Notifications", + "explore": "Explore", + "lists": "Lists", + + "favourites": "Favourites", + "bookmarks": "Bookmarks", + "hashtags": "Hashtags", + + "profile_information": "Profile information", + "settings": "Settings", + "log_out": "Log out" + }, + + "timeline": { + "home": "Home", + "local": "Local", + "federated": "Federated", + "fetching": "getting the feed..." + }, + + "notification": { + "and_others": "and %1 others", + "mention": "%1 mentioned you.", + "reblog": "%1 boosted your post.", + "reaction": "%1 reacted to your post.", + "follow": "%1 followed you.", + "follow_request": "%1 requested to follow you.", + "favourite": "%1 favourited your post.", + "poll": "%1's poll as ended.", + "update": "%1 updated their post.", + "default": "%1 poked you!", + "fetching": "fetching notifications..." + }, + + "post": { + "time": "%1 ago", + "boosted": "%1 boosted this post.", + "actions": { + "reply": "Reply", + "boost": "Boost", + "favourite": "Favourite", + "quote": "Quote", + "react": "React", + "more": "More", + "delete": "Delete" + }, + "warning": { + "show": "(click to reveal)", + "hide": "(click to hide)" + }, + "visibility": { + "public": "public", + "unlisted": "unlisted", + "private": "private", + "direct": "direct" + } + }, + + "compose": "Post", + "search": "Search", + + "source": "source", + "issues": "issues" +} diff --git a/src/lib/app.css b/src/lib/app.css index 83ae632..0959dd5 100644 --- a/src/lib/app.css +++ b/src/lib/app.css @@ -1,17 +1,11 @@ @import url("../font/inter/inter.css"); :root { - --bg-1000: #fffbf2; - --bg-900: #fff7e2; - --bg-800: #eee7d3; - --bg-700: #c8c0ac; - --bg-600: #edf5ba; - --accent: #899911; - --text: #11100d; - --bg-1000: #fffcf7; + --bg-900: #faf4e4; --bg-800: #f2e8d7; --bg-700: #d9ccad; + --bg-600: #edf5ba; --accent: #92a40a; --text: #322e1f; } diff --git a/src/lib/lang.js b/src/lib/lang.js new file mode 100644 index 0000000..8e90901 --- /dev/null +++ b/src/lib/lang.js @@ -0,0 +1,60 @@ +import * as en_GB from '@cf/lang/en_GB.json'; + +/** + * @param {string} lang IETH language tag (i.e. en_GB) + * @returns Map + */ +export default function init(lang) { + let i18n = new Object(); + let language; + + // TODO: dynamic imports seem to fail here; it can't find the file. + // try { + // language = import(`../lang/${lang}.json`); + // } catch (error) { + // throw error; + // } + + language = en_GB; + + i18n.lang = language; + i18n.lang_code = lang; + i18n.string = function(/* @type string */ key) { + const tokens = key.split('.'); + + let i = 0; + let token = tokens[i]; + let res = this.lang; + while (true) { + res = res[token]; + if (res === undefined) { + console.warn(`${key} not found for language ${this.lang_code}`); + return key; + } + if (typeof res === 'string' || res instanceof String) + return res; + i++; + token = tokens[i]; + } + } + i18n.stringArray = function(/* @type string */ key) { + const tokens = key.split('.'); + + let i = 0; + let token = tokens[i]; + let res = this.lang; + while (true) { + res = res[token]; + if (res === undefined) { + console.warn(`${key} not found for language ${this.lang_code}`); + return key; + } + if (Array.isArray(res)) + return res; + i++; + token = tokens[i]; + } + } + + return i18n; +} diff --git a/src/lib/time.js b/src/lib/time.js index 27ff200..4717b74 100644 --- a/src/lib/time.js +++ b/src/lib/time.js @@ -1,3 +1,6 @@ +import Lang from '$lib/lang.js'; +const lang = Lang('en_GB'); + const denoms = [ { unit: 's', min: 0 }, { unit: 'm', min: 60 }, @@ -18,6 +21,6 @@ export function shorthand(date) { unit = denoms[index].unit; } if (value > 0) - return Math.floor(value) + unit + " ago"; + return lang.string('post.time').replaceAll('%1', Math.floor(value) + unit); return "in " + Math.floor(value) + unit; } diff --git a/src/lib/ui/Composer.svelte b/src/lib/ui/Composer.svelte index b290d14..4935038 100644 --- a/src/lib/ui/Composer.svelte +++ b/src/lib/ui/Composer.svelte @@ -7,6 +7,7 @@ import { timeline } from '$lib/timeline.js'; import { createEventDispatcher } from 'svelte'; import { playSound } from '$lib/sound'; + import Lang from '$lib/lang.js' import Button from '@cf/ui/Button.svelte'; import PostIcon from '@cf/icons/post.svg'; @@ -19,6 +20,8 @@ import FollowersVisIcon from '@cf/icons/followers.svg'; import PrivateVisIcon from '@cf/icons/dm.svg'; + const lang = Lang('en_GB'); + export let reply_id; let content_warning = "" @@ -27,15 +30,9 @@ let show_cw = false; let visibility = "Public"; - const placeholders = [ - "What's cooking, $1?", - "Speak your mind!", - "Federate something...", - "I sure love posting!", - "Another day, another $1 post!", - ]; - let placeholder = placeholders[Math.floor(placeholders.length * Math.random())] - .replaceAll("$1", $account.username); + const placeholders = lang.stringArray('compose_placeholders'); + let placeholder = Array.isArray(placeholders) ? placeholders[Math.floor(placeholders.length * Math.random())] + .replaceAll("$1", $account.username) : placeholders; const dispatch = createEventDispatcher(); diff --git a/src/lib/ui/LoginForm.svelte b/src/lib/ui/LoginForm.svelte index 1a64f88..fe3b08f 100644 --- a/src/lib/ui/LoginForm.svelte +++ b/src/lib/ui/LoginForm.svelte @@ -3,9 +3,12 @@ import { server, createServer } from '$lib/client/server.js'; import { app } from '$lib/client/app.js'; import { get } from 'svelte/store'; + import Lang from '$lib/lang.js'; import Logo from '$lib/../img/campfire-logo.svg'; + const lang = Lang('en_GB'); + let display_error = false; let logging_in = false; @@ -17,21 +20,21 @@ const host = event.target.host.value; if (!host || host === "") { - display_error = "Please enter an server domain."; + display_error = lang.string('login.error.no_domain'); logging_in = false; return; } server.set(await createServer(host)); if (!get(server)) { - display_error = "Failed to connect to the server.\nCheck the browser console for details!" + display_error = lang.string('login.error.connection_failed'); logging_in = false; return; } app.set(await api.createApp(get(server).host)); if (!get(app)) { - display_error = "Failed to create an application for this server." + display_error = lang.string('login.error.create_app'); logging_in = false; return; } @@ -44,8 +47,8 @@ -

Welcome, fediverse user!

-

Please enter your server domain to log in.

+

{lang.string('login.welcome')}

+

{lang.string('login.enter_domain')}

{#if display_error} @@ -53,16 +56,10 @@ {/if}

- -

- Please note this is - extremely experimental software; - things are likely to break! -
- If that's all cool with you, welcome aboard! -

+ +

{@html lang.string('login.experimental')}

- +