fix(router,i18n): harden links, loading, and localized content

Make the custom router follow browser link conventions: resolve clicks from nested elements, preserve query strings and hashes, ignore modified, download, targeted, external, and in-page links, synchronize navigation listeners, and prevent stale lazy imports from replacing the newest route.

Keep language selection authoritative during translated navigation, reject unsupported stored locales, prevent stale translation requests from winning races, and synchronize the document language with standards-based et-EE and en-GB locale identifiers.

Route every YAML-backed page through one loader that checks HTTP responses, validates the parsed data shape against its fallback, and returns safe defaults. Render locale-neutral workshop months with Intl.DateTimeFormat and localize the embedded calendar URL from the active locale.

Replace HTML-bearing Helpdesk and workshop translations with structured plain-text segments rendered through escaped Vue bindings. This preserves emphasis and spacing without v-html, while direct MapLibre markers now build fixed DOM nodes through textContent and clean up safely after asynchronous loading.
This commit is contained in:
topsinoty
2026-07-04 15:55:05 +03:00
parent 13322e11cb
commit e5fc209203
19 changed files with 189 additions and 106 deletions

View File

@@ -5,7 +5,7 @@
Button,
} from "../components/index.js";
import { computed, onMounted, ref } from 'vue';
import yaml from 'js-yaml';
import { loadYaml } from '../lib/yaml.js';
import { usePageText } from "../lib/index.js";
const members = ref({ junior: [], senior: [] });
@@ -13,13 +13,7 @@
const joinFormUrl = "https://pilves.lapikud.ee/apps/forms/s/WXed8sbG2s45GMKGAiXCemgE";
onMounted(async () => {
try {
const response = await fetch('/_data/members.yml');
const yamlText = await response.text();
members.value = yaml.load(yamlText) || { junior: [], senior: [] };
} catch {
members.value = { junior: [], senior: [] };
}
members.value = await loadYaml('/_data/members.yml', { junior: [], senior: [] });
});
const scrollToJoin = () => {