From a91e1eeb632cc0f34aea7f43590e1711d59431d1 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 5 Apr 2023 21:44:47 +0200 Subject: [PATCH 1/4] Add system module --- panel/src/panel/system.js | 16 ++++++++++++ panel/src/panel/system.test.js | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 panel/src/panel/system.js create mode 100644 panel/src/panel/system.test.js diff --git a/panel/src/panel/system.js b/panel/src/panel/system.js new file mode 100644 index 0000000000..f0dcf86b99 --- /dev/null +++ b/panel/src/panel/system.js @@ -0,0 +1,16 @@ +import Module from "./module.js"; + +export const defaults = () => { + return { + ascii: {}, + csrf: null, + isLocal: null, + locales: {}, + slugs: [], + title: null + }; +}; + +export default () => { + return Module("$system", defaults()); +}; diff --git a/panel/src/panel/system.test.js b/panel/src/panel/system.test.js new file mode 100644 index 0000000000..ec7319fe41 --- /dev/null +++ b/panel/src/panel/system.test.js @@ -0,0 +1,45 @@ +/** + * @vitest-environment node + */ + +import { describe, expect, it } from "vitest"; +import System from "./system"; + +describe.concurrent("panel.system()", () => { + it("should have a default state", async () => { + const system = System(); + + const state = { + ascii: {}, + csrf: null, + isLocal: null, + locales: {}, + slugs: [], + title: null + }; + + expect(system.key()).toStrictEqual("$system"); + expect(system.state()).toStrictEqual(state); + }); + + it("should set and reset", async () => { + const system = System(); + + const state = { + ...system.defaults(), + csrf: "dev", + title: "Kirby" + }; + + system.set({ + csrf: "dev", + title: "Kirby" + }); + + expect(system.state()).toStrictEqual(state); + + system.reset(); + + expect(system.state()).toStrictEqual(system.defaults()); + }); +}); From 6de7042782b59644688b595a90e7dc99ec4e2d89 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 5 Apr 2023 21:46:19 +0200 Subject: [PATCH 2/4] Add language module --- panel/src/panel/language.js | 22 ++++++++++++++++++++ panel/src/panel/language.test.js | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 panel/src/panel/language.js create mode 100644 panel/src/panel/language.test.js diff --git a/panel/src/panel/language.js b/panel/src/panel/language.js new file mode 100644 index 0000000000..b516527863 --- /dev/null +++ b/panel/src/panel/language.js @@ -0,0 +1,22 @@ +import Module from "./module.js"; + +export const defaults = () => { + return { + code: null, + default: false, + direction: "ltr", + name: null, + rules: [] + }; +}; + +export default () => { + const parent = Module("$language", defaults()); + + return { + ...parent, + get isDefault() { + return this.default; + } + }; +}; diff --git a/panel/src/panel/language.test.js b/panel/src/panel/language.test.js new file mode 100644 index 0000000000..ea120812d6 --- /dev/null +++ b/panel/src/panel/language.test.js @@ -0,0 +1,35 @@ +/** + * @vitest-environment node + */ + +import { describe, expect, it } from "vitest"; +import Language from "./language.js"; + +describe.concurrent("panel.language()", () => { + it("should have a default state", async () => { + const language = Language(); + + const state = { + code: null, + default: false, + direction: "ltr", + name: null, + rules: [] + }; + + expect(language.key()).toStrictEqual("$language"); + expect(language.state()).toStrictEqual(state); + }); + + it("should have isDefault getter", async () => { + const language = Language(); + + expect(language.isDefault).toStrictEqual(false); + + language.set({ + default: true + }); + + expect(language.isDefault).toStrictEqual(true); + }); +}); From 40c7bae705ef2d445146eff783df17191caa056b Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 5 Apr 2023 21:49:03 +0200 Subject: [PATCH 3/4] Add user module --- panel/src/panel/user.js | 15 ++++++++++++ panel/src/panel/user.test.js | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 panel/src/panel/user.js create mode 100644 panel/src/panel/user.test.js diff --git a/panel/src/panel/user.js b/panel/src/panel/user.js new file mode 100644 index 0000000000..61402d4182 --- /dev/null +++ b/panel/src/panel/user.js @@ -0,0 +1,15 @@ +import Module from "./module.js"; + +export const defaults = () => { + return { + email: null, + id: null, + language: null, + role: null, + username: null + }; +}; + +export default () => { + return Module("$user", defaults()); +}; diff --git a/panel/src/panel/user.test.js b/panel/src/panel/user.test.js new file mode 100644 index 0000000000..85d76b8cbd --- /dev/null +++ b/panel/src/panel/user.test.js @@ -0,0 +1,44 @@ +/** + * @vitest-environment node + */ + +import { describe, expect, it } from "vitest"; +import User from "./user.js"; + +describe.concurrent("panel.user()", () => { + it("should have a default state", async () => { + const user = User(); + + const state = { + email: null, + id: null, + language: null, + role: null, + username: null + }; + + expect(user.key()).toStrictEqual("$user"); + expect(user.state()).toStrictEqual(state); + }); + + it("should set and reset", async () => { + const user = User(); + + const state = { + ...user.defaults(), + id: "abc", + username: "Kirby" + }; + + user.set({ + id: "abc", + username: "Kirby" + }); + + expect(user.state()).toStrictEqual(state); + + user.reset(); + + expect(user.state()).toStrictEqual(user.defaults()); + }); +}); From 18de616749d7472007a49341e45ef6d333b0ff81 Mon Sep 17 00:00:00 2001 From: Bastian Allgeier Date: Wed, 5 Apr 2023 21:57:24 +0200 Subject: [PATCH 4/4] Add translation module --- panel/src/panel/language.test.js | 2 +- panel/src/panel/system.test.js | 2 +- panel/src/panel/translation.js | 73 +++++++++++++++++++++++++++++ panel/src/panel/translation.test.js | 68 +++++++++++++++++++++++++++ panel/src/panel/user.test.js | 2 +- 5 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 panel/src/panel/translation.js create mode 100644 panel/src/panel/translation.test.js diff --git a/panel/src/panel/language.test.js b/panel/src/panel/language.test.js index ea120812d6..b74adb3a58 100644 --- a/panel/src/panel/language.test.js +++ b/panel/src/panel/language.test.js @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import Language from "./language.js"; -describe.concurrent("panel.language()", () => { +describe.concurrent("panel.language", () => { it("should have a default state", async () => { const language = Language(); diff --git a/panel/src/panel/system.test.js b/panel/src/panel/system.test.js index ec7319fe41..c7a061aea1 100644 --- a/panel/src/panel/system.test.js +++ b/panel/src/panel/system.test.js @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import System from "./system"; -describe.concurrent("panel.system()", () => { +describe.concurrent("panel.system", () => { it("should have a default state", async () => { const system = System(); diff --git a/panel/src/panel/translation.js b/panel/src/panel/translation.js new file mode 100644 index 0000000000..255c1d6323 --- /dev/null +++ b/panel/src/panel/translation.js @@ -0,0 +1,73 @@ +import { template } from "@/helpers/string.js"; +import Module from "./module.js"; + +export const defaults = () => { + return { + code: null, + data: {}, + direction: "ltr", + name: null + }; +}; + +/** + * Represents the current interface + * translation + */ +export default () => { + const parent = Module("$translation", defaults()); + + return { + ...parent, + + /** + * When the active state of a translation + * changes, the document language and reading + * direction will also be updated + * + * @param {Object} state + * @returns {Object} The new state + */ + set(state) { + parent.set.call(this, state); + + /** + * Update the document language for better accessibility + */ + document.documentElement.lang = this.code; + + /** + * Some elements – i.e. drag ghosts - + * are injected into the body and not the panel div. + * They need the dir to be displayed correctly + */ + document.body.dir = this.direction; + + return this.state(); + }, + + /** + * Fetches a translation string and + * can optionally replace placeholders + * with values from the data object + * + * @param {String} key + * @param {Object} data + * @param {String} fallback + * @returns {String} + */ + translate(key, data, fallback = null) { + if (typeof key !== "string") { + return; + } + + const string = this.data[key] || fallback; + + if (typeof string !== "string") { + return string; + } + + return template(string, data); + } + }; +}; diff --git a/panel/src/panel/translation.test.js b/panel/src/panel/translation.test.js new file mode 100644 index 0000000000..feea1a4f1e --- /dev/null +++ b/panel/src/panel/translation.test.js @@ -0,0 +1,68 @@ +import { describe, expect, it } from "vitest"; +import Translation from "./translation.js"; + +describe.concurrent("panel.translation", () => { + it("should have a default state", async () => { + const translation = Translation(); + + const state = { + code: null, + data: {}, + direction: "ltr", + name: null + }; + + expect(translation.key()).toStrictEqual("$translation"); + expect(translation.state()).toStrictEqual(state); + }); + + it("should set lang & direction", async () => { + const translation = Translation(); + + translation.set({ + code: "en", + direction: "ltr" + }); + + expect(document.documentElement.lang).toStrictEqual("en"); + expect(document.body.dir).toStrictEqual("ltr"); + + translation.set({ + code: "fr", + direction: "rtl" + }); + + expect(document.documentElement.lang).toStrictEqual("fr"); + expect(document.body.dir).toStrictEqual("rtl"); + }); + + it("should translate", async () => { + const translation = Translation(); + + translation.set({ + data: { + simple: "Test", + template: "Hello {{ name }}", + object: { theme: "dark" } + } + }); + + // simple + expect(translation.translate("simple")).toStrictEqual("Test"); + + // with fallback + expect(translation.translate("does-not-exist", {}, "Test")).toStrictEqual( + "Test" + ); + + // with object as result + expect(translation.translate("object")).toStrictEqual({ + theme: "dark" + }); + + // with data + expect(translation.translate("template", { name: "Peter" })).toStrictEqual( + "Hello Peter" + ); + }); +}); diff --git a/panel/src/panel/user.test.js b/panel/src/panel/user.test.js index 85d76b8cbd..a296ca20b1 100644 --- a/panel/src/panel/user.test.js +++ b/panel/src/panel/user.test.js @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import User from "./user.js"; -describe.concurrent("panel.user()", () => { +describe.concurrent("panel.user", () => { it("should have a default state", async () => { const user = User();