diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs
index 7d0f73959..11284832d 100644
--- a/frontend/.eslintrc.cjs
+++ b/frontend/.eslintrc.cjs
@@ -19,7 +19,7 @@ module.exports = {
"**/dist/**",
"**/__generated__/**",
"**/coverage/**",
- "!.storybook",
+ "!.storybook/locales.ts",
"*/gql/*.ts",
],
overrides: [
diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts
new file mode 100644
index 000000000..9d51f3e6e
--- /dev/null
+++ b/frontend/.storybook/locales.ts
@@ -0,0 +1,102 @@
+export type LocalazyLanguage = {
+ language: string;
+ region: string;
+ script: string;
+ isRtl: boolean;
+ localizedName: string;
+ name: string;
+ pluralType: (n: number) => "zero" | "one" | "two" | "many" | "few" | "other";
+};
+export type LocalazyFile = {
+ cdnHash: string;
+ file: string;
+ path: string;
+ library: string;
+ module: string;
+ buildType: string;
+ productFlavors: string[];
+ cdnFiles: { [lang:string]: string };
+};
+export type LocalazyMetadata = {
+ projectUrl: string;
+ baseLocale: string;
+ languages: LocalazyLanguage[];
+ files: LocalazyFile[];
+};
+
+const localazyMetadata: LocalazyMetadata = {
+ projectUrl: "https://localazy.com/p/matrix-authentication-service",
+ baseLocale: "en",
+ languages: [
+ {
+ language: "de",
+ region: "",
+ script: "",
+ isRtl: false,
+ name: "German",
+ localizedName: "Deutsch",
+ pluralType: (n) => { return (n===1) ? "one" : "other"; }
+ },
+ {
+ language: "en",
+ region: "",
+ script: "",
+ isRtl: false,
+ name: "English",
+ localizedName: "English",
+ pluralType: (n) => { return (n===1) ? "one" : "other"; }
+ },
+ {
+ language: "fr",
+ region: "",
+ script: "",
+ isRtl: false,
+ name: "French",
+ localizedName: "Français",
+ pluralType: (n) => { return (n===0 || n===1) ? "one" : "other"; }
+ },
+ {
+ language: "zh",
+ region: "",
+ script: "Hans",
+ isRtl: false,
+ name: "Simplified Chinese",
+ localizedName: "简体中文",
+ pluralType: (n) => { return "other"; }
+ }
+ ],
+ files: [
+ {
+ cdnHash: "7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2",
+ file: "frontend.json",
+ path: "",
+ library: "",
+ module: "",
+ buildType: "",
+ productFlavors: [],
+ cdnFiles: {
+ "de#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json",
+ "en#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json",
+ "fr#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json",
+ "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json"
+ }
+ },
+ {
+ cdnHash: "5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e",
+ file: "file.json",
+ path: "",
+ library: "",
+ module: "",
+ buildType: "",
+ productFlavors: [],
+ cdnFiles: {
+ "de#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json",
+ "en#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json",
+ "fr#": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json",
+ "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json"
+ }
+ }
+ ]
+};
+
+export default localazyMetadata;
\ No newline at end of file
diff --git a/frontend/.storybook/preview-head.html b/frontend/.storybook/preview-head.html
index 05da1e9df..66d2626e7 100644
--- a/frontend/.storybook/preview-head.html
+++ b/frontend/.storybook/preview-head.html
@@ -1,3 +1,9 @@
\ No newline at end of file
+
+
+
diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx
index f77e7cc8b..7e2106107 100644
--- a/frontend/.storybook/preview.tsx
+++ b/frontend/.storybook/preview.tsx
@@ -19,6 +19,8 @@ import { useLayoutEffect } from "react";
import "../src/main.css";
import i18n from "../src/i18n";
+import localazyMetadata from "./locales";
+
export const parameters: Parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
@@ -29,39 +31,38 @@ export const parameters: Parameters = {
},
};
-export const globalTypes: ArgTypes = {
+export const globalTypes = {
theme: {
name: "Theme",
+ defaultValue: "system",
description: "Global theme for components",
- defaultValue: "light",
toolbar: {
icon: "circlehollow",
title: "Theme",
items: [
- {
- title: "Light",
- value: "light",
- icon: "sun",
- },
- {
- title: "Dark",
- value: "dark",
- icon: "moon",
- },
+ { title: "System", value: "system", icon: "browser" },
+ { title: "Light", value: "light", icon: "sun" },
+ { title: "Light (high contrast)", value: "light-hc", icon: "sun" },
+ { title: "Dark", value: "dark", icon: "moon" },
+ { title: "Dark (high contrast)", value: "darkhc", icon: "moon" },
],
},
},
-};
+} satisfies ArgTypes;
-const ThemeSwitcher: React.FC<{ theme?: "light" | "dark" }> = ({ theme }) => {
+const allThemesClasses = globalTypes.theme.toolbar.items.map(
+ ({ value }) => `cpd-theme-${value}`,
+);
+
+const ThemeSwitcher: React.FC<{
+ theme: string;
+}> = ({ theme }) => {
useLayoutEffect(() => {
- if (theme === "dark") {
- document.documentElement.classList.add("cpd-theme-dark");
- } else {
- document.documentElement.classList.remove("cpd-theme-dark");
+ document.documentElement.classList.remove(...allThemesClasses);
+ if (theme !== "system") {
+ document.documentElement.classList.add(`cpd-theme-${theme}`);
}
-
- return () => document.documentElement.classList.remove("cpd-theme-dark");
+ return () => document.documentElement.classList.remove(...allThemesClasses);
}, [theme]);
return null;
@@ -80,13 +81,17 @@ const withThemeProvider: Decorator = (Story, context) => {
export const decorators: Decorator[] = [withThemeProvider];
+const locales = Object.fromEntries(
+ localazyMetadata.languages.map(({ language, name, localizedName }) => [
+ language,
+ `${localizedName} (${name})`,
+ ]),
+);
+
const preview: Preview = {
globals: {
- locale: "en",
- locales: {
- en: "English",
- fr: "Français",
- },
+ locale: localazyMetadata.baseLocale,
+ locales,
},
parameters: {
i18n,
diff --git a/localazy.json b/localazy.json
index a9d46b293..a32c6fe85 100644
--- a/localazy.json
+++ b/localazy.json
@@ -17,6 +17,7 @@
}]
},
"download": {
+ "metadataFileTs": "frontend/.storybook/locales.ts",
"files": [{
"conditions": "equals: ${file}, file.json",
"output": "translations/${lang}.json"