Files
friendolls/src/lib/i18n/index.ts
T

137 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { derived, writable } from "svelte/store";
import { commands, events, type LocaleChanged } from "$lib/bindings";
import * as compiledMessages from "../../paraglide/messages.js";
import {
baseLocale,
getLocale,
isLocale,
setLocale,
type Locale,
} from "../../paraglide/runtime.js";
export type MessageCatalog = typeof compiledMessages;
export const locale = writable<Locale>(baseLocale);
export const localePreference = writable("system");
// A new object is emitted for each locale so Svelte reevaluates every message
// call without requiring a provider in every Tauri window.
export const messages = derived(locale, () => ({ ...compiledMessages }));
export const languageOptions = [
{
value: "system",
label: (catalog: MessageCatalog) => catalog.language_system(),
},
{
value: "en",
label: (catalog: MessageCatalog) => catalog.language_english(),
},
{
value: "zh-CN",
label: (catalog: MessageCatalog) => catalog.language_chinese(),
},
] as const;
async function applyLocaleSettings(settings: LocaleChanged) {
const nextLocale = isLocale(settings.locale) ? settings.locale : baseLocale;
await setLocale(nextLocale, { reload: false });
localePreference.set(settings.preference);
locale.set(nextLocale);
document.documentElement.lang = nextLocale;
}
export async function initLocalization(): Promise<() => void> {
const unlisten = await events.localeChanged.listen((event) => {
void applyLocaleSettings(event.payload);
});
try {
await applyLocaleSettings(await commands.getLocaleSettings());
return unlisten;
} catch (error) {
unlisten();
const fallback = getLocale();
locale.set(fallback);
document.documentElement.lang = fallback;
throw error;
}
}
export async function setLanguagePreference(preference: string) {
await applyLocaleSettings(await commands.setLocalePreference(preference));
}
export function errorMessage(cause: unknown): string {
const value = cause instanceof Error ? cause.message : String(cause);
switch (value) {
case "Display name cannot be empty.":
return compiledMessages.error_display_name_empty();
case "Server address is required.":
return compiledMessages.error_server_address_required();
case "Port must be a whole number from 1 to 65535.":
return compiledMessages.error_port_invalid();
case "Identification key is required.":
return compiledMessages.error_friend_key_required();
case "No server was selected.":
return compiledMessages.error_server_not_selected();
case "This server no longer exists.":
return compiledMessages.error_server_missing();
case "The selected friend no longer exists.":
return compiledMessages.error_friend_missing();
case "Your profile is still loading.":
return compiledMessages.error_profile_loading();
case "Choose a 64×64 PNG skin before continuing.":
return compiledMessages.error_skin_required();
case "Identification key is not valid base64url.":
return compiledMessages.error_key_invalid_base64();
case "Identification key must encode a 32-byte public key.":
return compiledMessages.error_key_invalid_length();
case "Identification key is not a valid Ed25519 public key.":
return compiledMessages.error_key_invalid_ed25519();
case "You cannot add your own identification key.":
return compiledMessages.error_own_key();
case "The selected image is not a local file":
return compiledMessages.error_image_not_local();
case "The selected image could not be read":
return compiledMessages.error_image_unreadable();
case "Choose an image file":
return compiledMessages.error_image_choose();
case "The selected image could not be decoded":
return compiledMessages.error_image_decode();
case "Image compression failed":
return compiledMessages.error_image_compression();
case "Image is still too detailed after compression":
return compiledMessages.error_image_too_detailed();
case "No connected relay can currently reach this friend":
return compiledMessages.error_friend_unreachable();
case "Friend is busy; try again":
return compiledMessages.error_friend_busy();
case "Relay rejected the interaction":
return compiledMessages.error_interaction_rejected();
case "Friend is no longer available":
return compiledMessages.error_friend_unavailable();
case "Skin must be a valid PNG image":
return compiledMessages.error_skin_invalid_png();
default:
{
const imageLimit =
/^The selected image must be at most (\d+) MiB$/u.exec(value);
if (imageLimit) {
return compiledMessages.error_image_too_large({
max: Number(imageLimit[1]),
});
}
const skinDimensions = /^Skin must be (\d+)×(\d+) pixels$/u.exec(value);
if (skinDimensions) {
return compiledMessages.error_skin_dimensions({
width: Number(skinDimensions[1]),
height: Number(skinDimensions[2]),
});
}
}
if (getLocale() !== "en" && /[\u3400-\u9fff]/u.test(value)) return value;
return getLocale() === "en" ? value : compiledMessages.error_unexpected();
}
}