From ff01197ee6f307b6edea6bd4cab3df79f184252c Mon Sep 17 00:00:00 2001 From: Raine Date: Sun, 24 Dec 2023 20:40:28 +0100 Subject: [PATCH] feat: update locale to be more smart --- README.md | 30 ++++++++++++++++++------------ modules/locale.js | 46 +++++++++++++++++++++++++++++++++++++++------- test.html | 22 ++++++++++++++++------ test.json | 27 +++++++++++++++++++++++---- x0.js | 3 ++- 5 files changed, 98 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 3f655c1..2f06f10 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,27 @@ It has some attributes that simplify stuff with js. ### Top level attributes -These attributes only work on, and modify the root element (query selector: `html`). +These attributes only work on the html tag. -| attrib | description | default | -| ---------------- | ------------------------------- | --------------- | -| `x0-mods` | what modules to include | nothing | -| `x0-module-root` | where to fetch the modules from | `./x0/modules/` | -| `x0-init` | init x0? | `true` | +| attrib | description | default | module | +| -------------------- | ----------------------------------------------------- | --------------- | ------ | +| `x0-mods` | what modules to include | nothing | x0 | +| `x0-module-root` | where to fetch the modules from | `./x0/modules/` | x0 | +| `x0-init` | init x0? | `true` | x0 | +| `x0-locale-file` | which locale file to use | nothing | locale | +| `x0-locale-watch` | add an onchange listener to update locales | | locale | +| `x0-locale-no-cache` | do **not** use cached locales | | locale | +| `x0-locale-default` | default locale | `en` | locale | +| `x0-locale-prefer` | set a preferred locale; ignore users lang if possible | | locale | ### Element Attributes Attributes you can use -| module | attrib | description | example | -| --------- | ---------------- | ----------------------------------------------------------- | ------------------------- | -| http | `x-get` | set the element's contents to the result of the get request | `x-get="./content"` | -| http | `x-get-interval` | use with `x-get` to poll the endpoint (millis) | `x-get-interval=1000` | -| http,copy | `x-inner-html` | instead of using innerHTML use innerText | `x-inner-html` | -| copy | `x-copy-query` | copy contents of element matching query selector | `x-copy-query="#content"` | \ No newline at end of file +| module | attrib | description | example | +| --------- | ---------------- | ----------------------------------------------------------- | ------------------------------ | +| http | `x-get` | set the element's contents to the result of the get request | `x-get="./content"` | +| http | `x-get-interval` | use with `x-get` to poll the endpoint (millis) | `x-get-interval=1000` | +| http,copy | `x-inner-html` | instead of using innerHTML use innerText | `x-inner-html` | +| copy | `x-copy-query` | copy contents of element matching query selector | `x-copy-query="#content"` | +| locale | `x-locale-key` | fetch locale key and put it in innerHTML | `x-locale-key="main.greeting"` | \ No newline at end of file diff --git a/modules/locale.js b/modules/locale.js index 43fc5b2..5b1b5be 100644 --- a/modules/locale.js +++ b/modules/locale.js @@ -1,10 +1,22 @@ // [x-locale-key=""] -// html[x1-locale-file] - -// html[x1-locale-watch] - watch document for changes and update +// html[x0-locale-file=""] - which file to use for locale +// html[x0-locale-no-cache] - do not cache locale +// html[x0-locale-watch] - watch document for changes and update +// html[x0-locale-default="en"] - default "en" +// html[x0-locale-prefer="en"] - prefer locale "en" (async () => { - if (!document.querySelector("html").hasAttribute("x1-locale-file")) return; + if (!document.querySelector("html").hasAttribute("x0-locale-file")) return; + + const getLocale = async (url) => { + let locale = (document.querySelector("html").hasAttribute("x0-locale-no-cache") ? undefined : localStorage.getItem(url)) ?? (await (await fetch(url)).text()); + if (!document.querySelector("html").hasAttribute("x0-locale-no-cache")) + fetch(url).then(r => r.text().then(t => localStorage.setItem(url, t))); + localStorage.setItem(url, locale); + return JSON.parse(locale); + }; + let backupElements = window.x0?.registerStorage("locale") ?? {}; - let locale = (await (await fetch(document.querySelector("html").getAttribute("x1-locale-file"))).json()) ?? {}; + let locale = await getLocale(document.querySelector("html").getAttribute("x0-locale-file")) ?? {}; const getValueFromPath = (obj, path) => path.split(".").reduce((obj, key) => obj && obj[key], obj); @@ -13,8 +25,23 @@ .forEach(e => { let uuid = (Math.random() + new Date().getTime()).toString(36); e.setAttribute("x1-locale-uuid", uuid); - backupElements[uuid] = e.outerHTML; - e.innerHTML = getValueFromPath(locale, e.getAttribute("x-locale-key")); + backupElements[uuid] = e.innerHTML; + let v = getValueFromPath(locale, e.getAttribute("x-locale-key")); + if (typeof v === 'object') { + [ + document.querySelector("html").getAttribute("x0-locale-prefer"), + new URLSearchParams(window.location.search).get("locale"), + navigator.userLanguage || navigator.language || navigator.browserLanguage, + ...navigator.languages, + document.querySelector("html").getAttribute("x0-locale-default") ?? "en" + ] + .filter(l => l) + .map(l => l.toLowerCase()) + .forEach(l => v = v[l] ?? v) + if (typeof v === 'object') + v = '%%definition not found%%' + } + e.innerHTML = v; }) } @@ -26,9 +53,14 @@ window.x0?.registerModuleUpdateHook("locale", updateLocale); window.x0?.registerModuleRemoveHook("locale", (s) => { + console.log(s); Object.keys(s) .forEach(uuid => { - document.querySelector(`[x1-locale-uuid="${uuid}"]`).outerHTML = s[uuid]; + let el = document.querySelector(`[x1-locale-uuid="${uuid}"]`); + requestAnimationFrame(() => { + el.removeAttribute("x1-locale-uuid"); + el.innerHTML = s[uuid]; + }) }) }) })() \ No newline at end of file diff --git a/test.html b/test.html index dc6a44c..03f30f7 100644 --- a/test.html +++ b/test.html @@ -1,22 +1,32 @@ - + -

+

main.greeting

- + origin + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate + duplicate
diff --git a/test.json b/test.json index 13f2a75..8c11426 100644 --- a/test.json +++ b/test.json @@ -1,12 +1,31 @@ { + "debug-tools": { + "update": "Update x0", + "reload": { + "nl": "Herlaad Pagina", + "en": "Reload Page" + } + }, "main": { - "greeting": "Welcome to the test page!" + "greeting": { + "nl": "Welkom op de test pagina!", + "en": "Welcome on the test page!" + } }, "copy-section": { - "header": "Copy", - "content-span": "Original Content" + "header": { + "nl": "Kopiƫer functie", + "en": "Copy function" + }, + "content-span": { + "en": "Original Content", + "nl": "Originele Content" + } }, "http-section": { - "header": "http" + "header": { + "nl": "HTTP Functie", + "en": "HTTP function" + } } } \ No newline at end of file diff --git a/x0.js b/x0.js index 1990ad8..f1e92a5 100644 --- a/x0.js +++ b/x0.js @@ -77,7 +77,8 @@ class x0 { /** registerStorage * Register a storage. - * This can only happen once per module. + * This storage's lifetime is one page load. + * This can only happen once per module per page load. */ registerStorage(module) { if (this.#moduleStorage[module]) return null;