From b4605e7e969c9caef1e39d43921176da0b3b50a8 Mon Sep 17 00:00:00 2001 From: Carlgo11 Date: Wed, 20 Nov 2024 18:34:39 +0100 Subject: [PATCH] Only load required languages --- src/components/search.js | 56 ++++++++++++++++++------------------- src/hooks/useTranslation.js | 14 ++++------ src/i18n.js | 42 ++++++++++++++++++---------- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/components/search.js b/src/components/search.js index 2d1d5d6..88991af 100644 --- a/src/components/search.js +++ b/src/components/search.js @@ -1,12 +1,10 @@ -import { html } from "htm/preact"; -import { render } from "preact"; -import { useEffect, useState } from "preact/hooks"; -import algoliasearch from "algoliasearch"; -import Table from "./table"; +import { html } from 'htm/preact'; +import { render } from 'preact'; +import { useEffect, useState, useRef } from 'preact/hooks'; +import algoliasearch from 'algoliasearch'; +import Table from './table'; import useTranslation from '../hooks/useTranslation.js'; -const t = useTranslation(); - const client = algoliasearch( import.meta.env.VITE_ALGOLIA_APP_ID, import.meta.env.VITE_ALGOLIA_API_KEY, @@ -119,32 +117,32 @@ function sendSearch(query) { } function Search() { - const [query, setQuery] = useState(""); - let timeout = null; - - useEffect(async () => { - const searchParams = new URLSearchParams(window.location.search); - if (searchParams.has("q")) { - const query = searchParams.get("q"); - setQuery(query); - sendSearch(query); - } + const [query, setQuery] = useState(''); + const timeout = useRef(null); + const t = useTranslation(); + + useEffect(() => { + const fetchInitialQuery = async () => { + const searchParams = new URLSearchParams(window.location.search); + if (searchParams.has('q')) { + const query = searchParams.get('q'); + setQuery(query); + sendSearch(query); + } + }; + fetchInitialQuery(); }, []); - /** - * Search and update query parameter without reloading the page - * - * @param {string} query - The query - */ const search = (query) => { sendSearch(query); if (query) { - // Source: https://stackoverflow.com/a/70591485 const url = new URL(window.location.href); - url.searchParams.set("q", query); - window.history.pushState(null, "", url.toString()); - } else window.history.pushState(null, "", window.location.pathname); + url.searchParams.set('q', query); + window.history.pushState(null, '', url.toString()); + } else { + window.history.pushState(null, '', window.location.pathname); + } }; return html` @@ -156,8 +154,8 @@ function Search() { spellcheck="false" aria-keyshortcuts="s" onInput=${(event) => { - if (timeout) clearTimeout(timeout); - timeout = setTimeout(() => search(event.target.value), 1000); + if (timeout.current) clearTimeout(timeout.current); + timeout.current = setTimeout(() => search(event.target.value), 1000); }} value=${query} /> @@ -166,4 +164,4 @@ function Search() { `; } -render(html`<${Search} />`, document.getElementById("search")); +render(html`<${Search} />`, document.getElementById('search')); diff --git a/src/hooks/useTranslation.js b/src/hooks/useTranslation.js index 3223870..09cb46e 100644 --- a/src/hooks/useTranslation.js +++ b/src/hooks/useTranslation.js @@ -1,18 +1,16 @@ -import { useState, useEffect } from 'preact/hooks'; +import { useState, useEffect, useMemo } from 'preact/hooks'; import i18n from '../i18n'; function useTranslation() { - const [loaded, setLoaded] = useState(i18n.isLoaded); + const [, forceUpdate] = useState(0); useEffect(() => { - if (!i18n.isLoaded) { - const onLoad = () => setLoaded(true); - i18n.subscribe(onLoad); - return () => i18n.unsubscribe(onLoad); - } + const onLoad = () => forceUpdate((n) => n + 1); + i18n.subscribe(onLoad); + return () => i18n.unsubscribe(onLoad); }, []); - return i18n.get.bind(i18n); + return useMemo(() => i18n.get.bind(i18n), [i18n.translations]); } export default useTranslation; diff --git a/src/i18n.js b/src/i18n.js index 2cb17ea..57c3762 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -9,19 +9,31 @@ class i18n { } async _loadLanguages() { - const languageFiles = import.meta.glob('../lang/*.json'); // Import all JSON files in the lang folder - const translations = {}; - try { - await Promise.all( - Object.entries(languageFiles).map(async ([path, load]) => { - const language = path.match(/\.\/lang\/(.*)\.json$/)[1]; // Extract language code - const content = await load(); // Dynamically import the JSON file - translations[language] = content.default; // Store the language data - }) - ); - console.debug('Languages loaded:', Object.keys(translations)); - this.translations = translations; + // Use import.meta.glob to create a mapping of language files + const languageFiles = import.meta.glob('../lang/*.json'); + + // Load the default language + const defaultLangPath = `../lang/${this.defaultLanguage}.json`; + if (languageFiles[defaultLangPath]) { + const defaultLangModule = await languageFiles[defaultLangPath](); + this.translations[this.defaultLanguage] = defaultLangModule.default; + } else { + console.error(`Default language file not found at ${defaultLangPath}`); + } + + // If current language is different from default, load it as well + if (this.currentLanguage !== this.defaultLanguage) { + const currentLangPath = `../lang/${this.currentLanguage}.json`; + if (languageFiles[currentLangPath]) { + const currentLangModule = await languageFiles[currentLangPath](); + this.translations[this.currentLanguage] = currentLangModule.default; + } else { + console.warn(`Language file for ${this.currentLanguage} not found at ${currentLangPath}, falling back to default language.`); + } + } + + console.debug('Languages loaded:', Object.keys(this.translations)); this.isLoaded = true; this._notifyListeners(); } catch (error) { @@ -35,14 +47,14 @@ class i18n { return translations[currentLanguage][key]; } else if (translations[defaultLanguage] && translations[defaultLanguage][key]) { return translations[defaultLanguage][key]; - } else { - return key; // Fallback to the key if not found } } // Subscription management subscribe(listener) { - this.listeners.push(listener); + if (!this.listeners.includes(listener)) { + this.listeners.push(listener); + } } unsubscribe(listener) {