@geenius/i18n 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -1
- package/package.json +16 -3
- package/packages/convex/dist/index.d.ts +62 -0
- package/packages/convex/dist/index.js +157 -0
- package/packages/convex/dist/index.js.map +1 -0
- package/packages/react/README.md +1 -1
- package/packages/react/dist/index.d.ts +100 -0
- package/packages/react/dist/index.js +284 -0
- package/packages/react/dist/index.js.map +1 -0
- package/packages/react-css/README.md +1 -1
- package/packages/react-css/dist/index.d.ts +34 -0
- package/packages/react-css/dist/index.js +134 -0
- package/packages/react-css/dist/index.js.map +1 -0
- package/packages/shared/README.md +1 -1
- package/packages/shared/dist/index.d.ts +77 -0
- package/packages/shared/dist/index.js +158 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/solidjs/README.md +1 -1
- package/packages/solidjs/dist/index.d.ts +105 -0
- package/packages/solidjs/dist/index.js +328 -0
- package/packages/solidjs/dist/index.js.map +1 -0
- package/packages/solidjs-css/README.md +1 -1
- package/packages/solidjs-css/dist/index.d.ts +59 -0
- package/packages/solidjs-css/dist/index.js +244 -0
- package/packages/solidjs-css/dist/index.js.map +1 -0
- package/.changeset/config.json +0 -11
- package/.github/CODEOWNERS +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -29
- package/.nvmrc +0 -1
- package/.project/ACCOUNT.yaml +0 -4
- package/.project/IDEAS.yaml +0 -7
- package/.project/PROJECT.yaml +0 -11
- package/.project/ROADMAP.yaml +0 -15
- package/CODE_OF_CONDUCT.md +0 -16
- package/CONTRIBUTING.md +0 -26
- package/SECURITY.md +0 -15
- package/SUPPORT.md +0 -8
- package/packages/convex/package.json +0 -42
- package/packages/convex/src/index.ts +0 -3
- package/packages/convex/src/mutations.ts +0 -65
- package/packages/convex/src/queries.ts +0 -54
- package/packages/convex/src/schema.ts +0 -26
- package/packages/convex/tsconfig.json +0 -18
- package/packages/convex/tsup.config.ts +0 -17
- package/packages/react/package.json +0 -51
- package/packages/react/src/components/index.tsx +0 -87
- package/packages/react/src/hooks/index.ts +0 -4
- package/packages/react/src/hooks/useI18n.tsx +0 -50
- package/packages/react/src/hooks/useI18nAdmin.ts +0 -12
- package/packages/react/src/hooks/useLocaleDetect.ts +0 -10
- package/packages/react/src/hooks/useTranslations.ts +0 -11
- package/packages/react/src/index.tsx +0 -8
- package/packages/react/src/pages/I18nAdminPage.tsx +0 -42
- package/packages/react/src/pages/LocalePreviewPage.tsx +0 -54
- package/packages/react/src/pages/index.ts +0 -2
- package/packages/react/tsconfig.json +0 -19
- package/packages/react/tsup.config.ts +0 -12
- package/packages/react-css/package.json +0 -36
- package/packages/react-css/src/components/index.tsx +0 -66
- package/packages/react-css/src/hooks/index.ts +0 -4
- package/packages/react-css/src/index.tsx +0 -4
- package/packages/react-css/src/pages/LocaleSettingsPage.tsx +0 -74
- package/packages/react-css/src/pages/TranslationsPage.tsx +0 -98
- package/packages/react-css/src/styles.css +0 -210
- package/packages/react-css/tsconfig.json +0 -19
- package/packages/react-css/tsup.config.ts +0 -10
- package/packages/shared/package.json +0 -44
- package/packages/shared/src/__tests__/i18n.test.ts +0 -78
- package/packages/shared/src/config.ts +0 -344
- package/packages/shared/src/index.ts +0 -106
- package/packages/shared/src/types.ts +0 -51
- package/packages/shared/tsconfig.json +0 -18
- package/packages/shared/tsup.config.ts +0 -11
- package/packages/shared/vitest.config.ts +0 -4
- package/packages/solidjs/package.json +0 -47
- package/packages/solidjs/src/components/LocaleCard.tsx +0 -44
- package/packages/solidjs/src/components/LocaleStatsCard.tsx +0 -35
- package/packages/solidjs/src/components/LocaleSwitcher.tsx +0 -65
- package/packages/solidjs/src/components/MissingKeyAlert.tsx +0 -21
- package/packages/solidjs/src/components/RTLWrapper.tsx +0 -13
- package/packages/solidjs/src/components/TranslationKeyRow.tsx +0 -41
- package/packages/solidjs/src/components/index.ts +0 -6
- package/packages/solidjs/src/index.tsx +0 -8
- package/packages/solidjs/src/pages/I18nAdminPage.tsx +0 -188
- package/packages/solidjs/src/pages/LocalePreviewPage.tsx +0 -99
- package/packages/solidjs/src/pages/index.ts +0 -2
- package/packages/solidjs/src/primitives/I18nProvider.tsx +0 -56
- package/packages/solidjs/src/primitives/createI18nAdmin.ts +0 -7
- package/packages/solidjs/src/primitives/createLocaleDetect.ts +0 -8
- package/packages/solidjs/src/primitives/createTranslations.ts +0 -22
- package/packages/solidjs/src/primitives/index.ts +0 -4
- package/packages/solidjs/tsconfig.json +0 -20
- package/packages/solidjs/tsup.config.ts +0 -12
- package/packages/solidjs-css/package.json +0 -33
- package/packages/solidjs-css/src/components/LocaleCard.tsx +0 -45
- package/packages/solidjs-css/src/components/LocaleStatsCard.tsx +0 -43
- package/packages/solidjs-css/src/components/LocaleSwitcher.tsx +0 -51
- package/packages/solidjs-css/src/components/MissingKeyAlert.tsx +0 -24
- package/packages/solidjs-css/src/components/RTLWrapper.tsx +0 -16
- package/packages/solidjs-css/src/components/TranslationKeyRow.tsx +0 -47
- package/packages/solidjs-css/src/components/index.ts +0 -6
- package/packages/solidjs-css/src/i18n.css +0 -1322
- package/packages/solidjs-css/src/index.tsx +0 -3
- package/packages/solidjs-css/src/pages/I18nAdminPage.tsx +0 -134
- package/packages/solidjs-css/src/pages/LocalePreviewPage.tsx +0 -116
- package/packages/solidjs-css/src/pages/index.ts +0 -2
- package/packages/solidjs-css/src/primitives/index.ts +0 -1
- package/packages/solidjs-css/tsconfig.json +0 -20
- package/packages/solidjs-css/tsup.config.bundled_dcjc4sct21j.mjs +0 -18
- package/packages/solidjs-css/tsup.config.ts +0 -14
- package/pnpm-workspace.yaml +0 -2
- package/tsconfig.json +0 -23
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { createContext, useState, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
2
|
+
import { detectLocale, getDirection, formatCurrency, formatNumber, formatDate, t, isRTL, loadNamespace, LOCALE_INFO, ALL_LOCALES } from '@geenius/i18n-shared';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/hooks/useI18n.tsx
|
|
6
|
+
var I18nContext = createContext(null);
|
|
7
|
+
function I18nProvider({ children, config, translations }) {
|
|
8
|
+
const [locale, setLocaleState] = useState(() => {
|
|
9
|
+
if (config.persistLocale && typeof localStorage !== "undefined") {
|
|
10
|
+
const saved = localStorage.getItem("geenius-locale");
|
|
11
|
+
if (saved && config.supportedLocales.includes(saved)) return saved;
|
|
12
|
+
}
|
|
13
|
+
if (config.detectBrowser) return detectLocale(config.supportedLocales);
|
|
14
|
+
return config.defaultLocale;
|
|
15
|
+
});
|
|
16
|
+
const setLocale = useCallback((l) => {
|
|
17
|
+
setLocaleState(l);
|
|
18
|
+
if (config.persistLocale && typeof localStorage !== "undefined") localStorage.setItem("geenius-locale", l);
|
|
19
|
+
if (typeof document !== "undefined") {
|
|
20
|
+
document.documentElement.dir = getDirection(l);
|
|
21
|
+
document.documentElement.lang = l;
|
|
22
|
+
}
|
|
23
|
+
}, [config.persistLocale]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (typeof document !== "undefined") {
|
|
26
|
+
document.documentElement.dir = getDirection(locale);
|
|
27
|
+
document.documentElement.lang = locale;
|
|
28
|
+
}
|
|
29
|
+
}, [locale]);
|
|
30
|
+
const value = useMemo(() => ({
|
|
31
|
+
locale,
|
|
32
|
+
direction: getDirection(locale),
|
|
33
|
+
isRTL: isRTL(locale),
|
|
34
|
+
setLocale,
|
|
35
|
+
t: (key, params) => t(key, translations ?? {}, params),
|
|
36
|
+
formatDate: (date, opts) => formatDate(date, locale, opts),
|
|
37
|
+
formatNumber: (n, opts) => formatNumber(n, locale, opts),
|
|
38
|
+
formatCurrency: (amount, currency) => formatCurrency(amount, currency, locale)
|
|
39
|
+
}), [locale, setLocale, translations]);
|
|
40
|
+
return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
|
|
41
|
+
}
|
|
42
|
+
function useI18n() {
|
|
43
|
+
const ctx = useContext(I18nContext);
|
|
44
|
+
if (!ctx) throw new Error("useI18n must be used within I18nProvider");
|
|
45
|
+
return ctx;
|
|
46
|
+
}
|
|
47
|
+
function useLocaleDetect(supportedLocales) {
|
|
48
|
+
const [detectedLocale, setDetected] = useState(supportedLocales[0]);
|
|
49
|
+
const [isDetecting, setDetecting] = useState(true);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setDetected(detectLocale(supportedLocales));
|
|
52
|
+
setDetecting(false);
|
|
53
|
+
}, [supportedLocales]);
|
|
54
|
+
return { detectedLocale, isDetecting };
|
|
55
|
+
}
|
|
56
|
+
function useTranslations(locale, namespace) {
|
|
57
|
+
const [dict, setDict] = useState({});
|
|
58
|
+
const [isLoading, setLoading] = useState(true);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setLoading(true);
|
|
61
|
+
loadNamespace(locale, namespace).then((d) => {
|
|
62
|
+
setDict(d);
|
|
63
|
+
setLoading(false);
|
|
64
|
+
});
|
|
65
|
+
}, [locale, namespace]);
|
|
66
|
+
const t$1 = useCallback((key, params) => t(key, dict, params), [dict]);
|
|
67
|
+
return { dict, isLoading, t: t$1 };
|
|
68
|
+
}
|
|
69
|
+
function useI18nAdmin(data, mutations) {
|
|
70
|
+
const [search, setSearch] = useState("");
|
|
71
|
+
const filteredTranslations = useMemo(() => {
|
|
72
|
+
if (!search) return data.translations ?? [];
|
|
73
|
+
const q = search.toLowerCase();
|
|
74
|
+
return (data.translations ?? []).filter((t) => t.key.toLowerCase().includes(q) || t.value.toLowerCase().includes(q));
|
|
75
|
+
}, [data.translations, search]);
|
|
76
|
+
return { translations: filteredTranslations, missingKeys: data.missingKeys ?? [], localeStats: data.localeStats ?? [], search, setSearch, isLoading: data.translations === void 0, ...mutations };
|
|
77
|
+
}
|
|
78
|
+
function LocaleSwitcher({ locales, current, onChange }) {
|
|
79
|
+
const [open, setOpen] = useState(false);
|
|
80
|
+
const info = LOCALE_INFO[current];
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("button", { type: "button", onClick: () => setOpen(!open), className: "flex items-center gap-2 rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white hover:bg-white/10 transition-all", children: [
|
|
83
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg", children: info?.flag }),
|
|
84
|
+
/* @__PURE__ */ jsx("span", { children: info?.nativeName }),
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/30 text-xs ml-1", children: "\u25BC" })
|
|
86
|
+
] }),
|
|
87
|
+
open && /* @__PURE__ */ jsx("div", { className: "absolute top-full mt-1 right-0 z-50 min-w-[200px] rounded-xl border border-white/10 bg-[#111118] py-1 shadow-xl", children: locales.map((l) => {
|
|
88
|
+
const li = LOCALE_INFO[l];
|
|
89
|
+
return /* @__PURE__ */ jsxs(
|
|
90
|
+
"button",
|
|
91
|
+
{
|
|
92
|
+
type: "button",
|
|
93
|
+
onClick: () => {
|
|
94
|
+
onChange(l);
|
|
95
|
+
setOpen(false);
|
|
96
|
+
},
|
|
97
|
+
className: `flex w-full items-center gap-3 px-4 py-2.5 text-sm transition-colors ${current === l ? "bg-indigo-500/15 text-indigo-300" : "text-white/70 hover:bg-white/5"}`,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg", children: li?.flag }),
|
|
100
|
+
/* @__PURE__ */ jsx("span", { children: li?.nativeName }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-white/30 ml-auto", children: li?.name }),
|
|
102
|
+
li?.direction === "rtl" && /* @__PURE__ */ jsx("span", { className: "text-[10px] px-1 py-0.5 rounded bg-amber-500/15 text-amber-400", children: "RTL" })
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
l
|
|
106
|
+
);
|
|
107
|
+
}) })
|
|
108
|
+
] });
|
|
109
|
+
}
|
|
110
|
+
function RTLWrapper({ children, locale }) {
|
|
111
|
+
const dir = locale ? LOCALE_INFO[locale]?.direction ?? "ltr" : "ltr";
|
|
112
|
+
return /* @__PURE__ */ jsx("div", { dir, style: { textAlign: dir === "rtl" ? "right" : "left" }, children });
|
|
113
|
+
}
|
|
114
|
+
function TranslationEditor({ onSave, initialKey, initialLocale, namespaces }) {
|
|
115
|
+
const [locale, setLocale] = useState(initialLocale ?? "en");
|
|
116
|
+
const [ns, setNs] = useState(namespaces?.[0] ?? "common");
|
|
117
|
+
const [key, setKey] = useState(initialKey ?? "");
|
|
118
|
+
const [value, setValue] = useState("");
|
|
119
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-xl border border-white/8 bg-white/[0.02] p-5", children: [
|
|
120
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("select", { value: locale, onChange: (e) => setLocale(e.target.value), className: "rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-xs text-white outline-none", children: Object.entries(LOCALE_INFO).map(([code, info]) => /* @__PURE__ */ jsxs("option", { value: code, children: [
|
|
122
|
+
info.flag,
|
|
123
|
+
" ",
|
|
124
|
+
info.name
|
|
125
|
+
] }, code)) }),
|
|
126
|
+
/* @__PURE__ */ jsx("select", { value: ns, onChange: (e) => setNs(e.target.value), className: "rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-xs text-white outline-none", children: (namespaces ?? ["common", "auth", "dashboard", "billing", "errors"]).map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n)) })
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsx("input", { type: "text", placeholder: "Translation key (e.g. auth.login_button)", value: key, onChange: (e) => setKey(e.target.value), className: "w-full rounded-xl border border-white/10 bg-white/5 px-4 py-2.5 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/40" }),
|
|
129
|
+
/* @__PURE__ */ jsx("textarea", { placeholder: "Translation value\u2026", value, onChange: (e) => setValue(e.target.value), rows: 3, className: "w-full rounded-xl border border-white/10 bg-white/5 px-4 py-2.5 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/40 resize-none" }),
|
|
130
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => {
|
|
131
|
+
onSave(locale, ns, key, value);
|
|
132
|
+
setKey("");
|
|
133
|
+
setValue("");
|
|
134
|
+
}, disabled: !key || !value, className: "rounded-lg bg-indigo-600 px-4 py-2 text-xs font-medium text-white hover:bg-indigo-500 disabled:opacity-50", children: "Save Translation" })
|
|
135
|
+
] });
|
|
136
|
+
}
|
|
137
|
+
function TranslationTable({ translations, locale, onUpdate, onDelete }) {
|
|
138
|
+
if (translations.length === 0) return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center py-12", children: [
|
|
139
|
+
/* @__PURE__ */ jsx("div", { className: "mb-3 text-4xl opacity-20", children: "\u{1F310}" }),
|
|
140
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-white/40", children: "No translations for this locale" })
|
|
141
|
+
] });
|
|
142
|
+
return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-xl border border-white/8", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
143
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-white/8 bg-white/[0.02]", children: [
|
|
144
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-white/40 uppercase", children: "Key" }),
|
|
145
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-white/40 uppercase", children: "Value" }),
|
|
146
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-white/40 uppercase", children: "Namespace" }),
|
|
147
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-right text-xs font-medium text-white/40 uppercase", children: "Actions" })
|
|
148
|
+
] }) }),
|
|
149
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-white/5", children: translations.map((t) => /* @__PURE__ */ jsxs("tr", { className: "group hover:bg-white/[0.02]", children: [
|
|
150
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-xs text-indigo-300", children: t.key }),
|
|
151
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-white/70 max-w-xs truncate", children: t.value }),
|
|
152
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx("span", { className: "rounded bg-white/5 px-1.5 py-0.5 text-[10px] text-white/40", children: t.namespace }) }),
|
|
153
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right", children: onDelete && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onDelete(t.key), className: "rounded px-2 py-1 text-xs text-white/20 hover:text-red-400 opacity-0 group-hover:opacity-100", children: "Delete" }) })
|
|
154
|
+
] }, t.id)) })
|
|
155
|
+
] }) });
|
|
156
|
+
}
|
|
157
|
+
function MissingKeyAlert({ count, locale }) {
|
|
158
|
+
if (count === 0) return null;
|
|
159
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-red-500/20 bg-red-500/[0.05] px-4 py-2.5", children: [
|
|
160
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: "\u26A0\uFE0F" }),
|
|
161
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-red-300", children: [
|
|
162
|
+
count,
|
|
163
|
+
" missing key",
|
|
164
|
+
count > 1 ? "s" : "",
|
|
165
|
+
" for ",
|
|
166
|
+
/* @__PURE__ */ jsx("strong", { children: LOCALE_INFO[locale]?.name })
|
|
167
|
+
] })
|
|
168
|
+
] });
|
|
169
|
+
}
|
|
170
|
+
function LocaleStatsCard({ stats }) {
|
|
171
|
+
return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", children: stats.map((s) => {
|
|
172
|
+
const info = LOCALE_INFO[s.locale];
|
|
173
|
+
const color = s.coverage >= 90 ? "bg-emerald-500" : s.coverage >= 70 ? "bg-amber-500" : "bg-red-500";
|
|
174
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-white/8 bg-white/[0.02] p-4", children: [
|
|
175
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
176
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg", children: info?.flag }),
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-white/80", children: info?.nativeName })
|
|
178
|
+
] }),
|
|
179
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-1 flex justify-between text-[10px] text-white/40", children: [
|
|
180
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
181
|
+
s.totalKeys,
|
|
182
|
+
" keys"
|
|
183
|
+
] }),
|
|
184
|
+
/* @__PURE__ */ jsxs("span", { className: "font-bold", children: [
|
|
185
|
+
s.coverage,
|
|
186
|
+
"%"
|
|
187
|
+
] })
|
|
188
|
+
] }),
|
|
189
|
+
/* @__PURE__ */ jsx("div", { className: "h-1.5 rounded-full bg-white/5 overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: `h-full rounded-full ${color}`, style: { width: `${s.coverage}%` } }) }),
|
|
190
|
+
s.missingKeys > 0 && /* @__PURE__ */ jsxs("p", { className: "mt-1.5 text-[10px] text-red-400", children: [
|
|
191
|
+
s.missingKeys,
|
|
192
|
+
" missing"
|
|
193
|
+
] })
|
|
194
|
+
] }, s.locale);
|
|
195
|
+
}) });
|
|
196
|
+
}
|
|
197
|
+
function I18nAdminPage({ translations, missingKeys, localeStats, mutations }) {
|
|
198
|
+
const admin = useI18nAdmin({ translations, missingKeys, localeStats }, mutations);
|
|
199
|
+
const [selectedLocale, setSelectedLocale] = useState("en");
|
|
200
|
+
const [selectedNs, setSelectedNs] = useState("common");
|
|
201
|
+
const filteredTranslations = admin.translations.filter((t) => t.locale === selectedLocale && t.namespace === selectedNs);
|
|
202
|
+
if (admin.isLoading) return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-[#090a0f] px-6 py-12", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl", children: [
|
|
203
|
+
/* @__PURE__ */ jsx("div", { className: "mb-8 h-10 w-48 animate-pulse rounded-lg bg-white/5" }),
|
|
204
|
+
/* @__PURE__ */ jsx("div", { className: "mb-6 grid grid-cols-4 gap-3", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-20 animate-pulse rounded-xl bg-white/5" }, i)) }),
|
|
205
|
+
/* @__PURE__ */ jsx("div", { className: "h-96 animate-pulse rounded-xl bg-white/5" })
|
|
206
|
+
] }) });
|
|
207
|
+
return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-[#090a0f] text-white", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-6xl px-6 py-12", children: [
|
|
208
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight mb-8", children: "Translation Admin" }),
|
|
209
|
+
admin.localeStats.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
|
|
210
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-white/60 mb-4", children: "Locale Coverage" }),
|
|
211
|
+
/* @__PURE__ */ jsx(LocaleStatsCard, { stats: admin.localeStats })
|
|
212
|
+
] }),
|
|
213
|
+
admin.missingKeys.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsx(MissingKeyAlert, { count: admin.missingKeys.filter((m) => m.locale === selectedLocale).length, locale: selectedLocale }) }),
|
|
214
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-3", children: [
|
|
215
|
+
/* @__PURE__ */ jsxs("div", { className: "lg:col-span-2 space-y-4", children: [
|
|
216
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
217
|
+
/* @__PURE__ */ jsx("select", { value: selectedLocale, onChange: (e) => setSelectedLocale(e.target.value), className: "rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-sm text-white outline-none", children: ALL_LOCALES.map((l) => /* @__PURE__ */ jsxs("option", { value: l, children: [
|
|
218
|
+
LOCALE_INFO[l].flag,
|
|
219
|
+
" ",
|
|
220
|
+
LOCALE_INFO[l].name
|
|
221
|
+
] }, l)) }),
|
|
222
|
+
/* @__PURE__ */ jsx("select", { value: selectedNs, onChange: (e) => setSelectedNs(e.target.value), className: "rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-sm text-white outline-none", children: ["common", "auth", "dashboard", "billing", "errors"].map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n)) }),
|
|
223
|
+
/* @__PURE__ */ jsx("input", { type: "text", placeholder: "Search\u2026", value: admin.search, onChange: (e) => admin.setSearch(e.target.value), className: "ml-auto w-48 rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white placeholder-white/30 outline-none" })
|
|
224
|
+
] }),
|
|
225
|
+
/* @__PURE__ */ jsx(TranslationTable, { translations: filteredTranslations, locale: selectedLocale, onDelete: (key) => admin.deleteKey(selectedLocale, key) })
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(TranslationEditor, { onSave: (l, ns, k, v) => admin.upsert(l, ns, k, v), initialLocale: selectedLocale }) })
|
|
228
|
+
] })
|
|
229
|
+
] }) });
|
|
230
|
+
}
|
|
231
|
+
function PreviewContent() {
|
|
232
|
+
const { locale, t, direction, isRTL, setLocale, formatDate, formatNumber, formatCurrency } = useI18n();
|
|
233
|
+
const info = LOCALE_INFO[locale];
|
|
234
|
+
return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-[#090a0f] text-white", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-3xl px-6 py-12", children: [
|
|
235
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-8 flex items-center justify-between", children: [
|
|
236
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: "Locale Preview" }),
|
|
237
|
+
/* @__PURE__ */ jsx(LocaleSwitcher, { locales: ALL_LOCALES, current: locale, onChange: setLocale })
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6 grid grid-cols-2 gap-4 md:grid-cols-4", children: [
|
|
240
|
+
/* @__PURE__ */ jsx(InfoCard, { label: "Locale", value: locale.toUpperCase() }),
|
|
241
|
+
/* @__PURE__ */ jsx(InfoCard, { label: "Direction", value: direction, highlight: isRTL }),
|
|
242
|
+
/* @__PURE__ */ jsx(InfoCard, { label: "Native", value: info?.nativeName ?? "?" }),
|
|
243
|
+
/* @__PURE__ */ jsx(InfoCard, { label: "Flag", value: info?.flag ?? "?" })
|
|
244
|
+
] }),
|
|
245
|
+
/* @__PURE__ */ jsx(RTLWrapper, { locale, children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
246
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-white/8 bg-white/[0.02] p-5", children: [
|
|
247
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-white/80 mb-4", children: "Formatting Examples" }),
|
|
248
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3 text-sm", children: [
|
|
249
|
+
/* @__PURE__ */ jsx(Row, { label: "Date", value: formatDate(/* @__PURE__ */ new Date()) }),
|
|
250
|
+
/* @__PURE__ */ jsx(Row, { label: "Date (full)", value: formatDate(/* @__PURE__ */ new Date(), { dateStyle: "full" }) }),
|
|
251
|
+
/* @__PURE__ */ jsx(Row, { label: "Number", value: formatNumber(123456789e-2) }),
|
|
252
|
+
/* @__PURE__ */ jsx(Row, { label: "Currency (USD)", value: formatCurrency(9999.99, "USD") }),
|
|
253
|
+
/* @__PURE__ */ jsx(Row, { label: "Currency (EUR)", value: formatCurrency(4250.5, "EUR") }),
|
|
254
|
+
/* @__PURE__ */ jsx(Row, { label: "Percentage", value: formatNumber(0.85, { style: "percent" }) })
|
|
255
|
+
] })
|
|
256
|
+
] }),
|
|
257
|
+
isRTL && /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-amber-500/20 bg-amber-500/[0.05] px-4 py-3 text-sm text-amber-300", children: "\u26A1 RTL mode active \u2014 text flows right-to-left" }),
|
|
258
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-white/8 bg-white/[0.02] p-5", children: [
|
|
259
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-white/80 mb-3", children: "Sample Text" }),
|
|
260
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-white/60 leading-relaxed", children: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." })
|
|
261
|
+
] })
|
|
262
|
+
] }) })
|
|
263
|
+
] }) });
|
|
264
|
+
}
|
|
265
|
+
function InfoCard({ label, value, highlight }) {
|
|
266
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-white/8 bg-white/[0.02] p-4", children: [
|
|
267
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-white/40 mb-1 uppercase", children: label }),
|
|
268
|
+
/* @__PURE__ */ jsx("p", { className: `text-lg font-bold ${highlight ? "text-amber-400" : "text-white/90"}`, children: value })
|
|
269
|
+
] });
|
|
270
|
+
}
|
|
271
|
+
function Row({ label, value }) {
|
|
272
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
273
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/40", children: label }),
|
|
274
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/80 font-mono text-xs", children: value })
|
|
275
|
+
] });
|
|
276
|
+
}
|
|
277
|
+
function LocalePreviewPage({ config, translations }) {
|
|
278
|
+
const fullConfig = { defaultLocale: "en", supportedLocales: ALL_LOCALES, detectBrowser: true, persistLocale: true, ...config };
|
|
279
|
+
return /* @__PURE__ */ jsx(I18nProvider, { config: fullConfig, translations, children: /* @__PURE__ */ jsx(PreviewContent, {}) });
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export { I18nAdminPage, I18nProvider, LocalePreviewPage, LocaleStatsCard, LocaleSwitcher, MissingKeyAlert, RTLWrapper, TranslationEditor, TranslationTable, useI18n, useI18nAdmin, useLocaleDetect, useTranslations };
|
|
283
|
+
//# sourceMappingURL=index.js.map
|
|
284
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useI18n.tsx","../src/hooks/useLocaleDetect.ts","../src/hooks/useTranslations.ts","../src/hooks/useI18nAdmin.ts","../src/components/index.tsx","../src/pages/I18nAdminPage.tsx","../src/pages/LocalePreviewPage.tsx"],"names":["checkRTL","tFn","fmtDate","fmtNum","fmtCur","useState","useEffect","detectLocale","t","useCallback","useMemo","LOCALE_INFO","jsx","jsxs","ALL_LOCALES"],"mappings":";;;;;AAYA,IAAM,WAAA,GAAc,cAAuC,IAAI,CAAA;AAExD,SAAS,YAAA,CAAa,EAAE,QAAA,EAAU,MAAA,EAAQ,cAAa,EAAsF;AAClJ,EAAA,MAAM,CAAC,MAAA,EAAQ,cAAc,CAAA,GAAI,SAAiB,MAAM;AACtD,IAAA,IAAI,MAAA,CAAO,aAAA,IAAiB,OAAO,YAAA,KAAiB,WAAA,EAAa;AAC/D,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,gBAAgB,CAAA;AACnD,MAAA,IAAI,SAAS,MAAA,CAAO,gBAAA,CAAiB,QAAA,CAAS,KAAe,GAAG,OAAO,KAAA;AAAA,IACzE;AACA,IAAA,IAAI,MAAA,CAAO,aAAA,EAAe,OAAO,YAAA,CAAa,OAAO,gBAAgB,CAAA;AACrE,IAAA,OAAO,MAAA,CAAO,aAAA;AAAA,EAChB,CAAC,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,CAAA,KAAc;AAC3C,IAAA,cAAA,CAAe,CAAC,CAAA;AAChB,IAAA,IAAI,MAAA,CAAO,iBAAiB,OAAO,YAAA,KAAiB,aAAa,YAAA,CAAa,OAAA,CAAQ,kBAAkB,CAAC,CAAA;AACzG,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAAE,MAAA,QAAA,CAAS,eAAA,CAAgB,GAAA,GAAM,YAAA,CAAa,CAAC,CAAA;AAAG,MAAA,QAAA,CAAS,gBAAgB,IAAA,GAAO,CAAA;AAAA,IAAE;AAAA,EAC3H,CAAA,EAAG,CAAC,MAAA,CAAO,aAAa,CAAC,CAAA;AAEzB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAAE,MAAA,QAAA,CAAS,eAAA,CAAgB,GAAA,GAAM,YAAA,CAAa,MAAM,CAAA;AAAG,MAAA,QAAA,CAAS,gBAAgB,IAAA,GAAO,MAAA;AAAA,IAAO;AAAA,EACrI,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,KAAA,GAAQ,QAA0B,OAAO;AAAA,IAC7C,MAAA;AAAA,IAAQ,SAAA,EAAW,aAAa,MAAM,CAAA;AAAA,IAAG,KAAA,EAAOA,MAAS,MAAM,CAAA;AAAA,IAAG,SAAA;AAAA,IAClE,CAAA,EAAG,CAAC,GAAA,EAAK,MAAA,KAAWC,EAAI,GAAA,EAAK,YAAA,IAAgB,EAAC,EAAG,MAAM,CAAA;AAAA,IACvD,YAAY,CAAC,IAAA,EAAM,SAASC,UAAA,CAAQ,IAAA,EAAM,QAAQ,IAAI,CAAA;AAAA,IACtD,cAAc,CAAC,CAAA,EAAG,SAASC,YAAA,CAAO,CAAA,EAAG,QAAQ,IAAI,CAAA;AAAA,IACjD,gBAAgB,CAAC,MAAA,EAAQ,aAAaC,cAAA,CAAO,MAAA,EAAQ,UAAU,MAAM;AAAA,GACvE,CAAA,EAAI,CAAC,MAAA,EAAQ,SAAA,EAAW,YAAY,CAAC,CAAA;AAErC,EAAA,uBAAO,GAAA,CAAC,WAAA,CAAY,QAAA,EAAZ,EAAqB,OAAe,QAAA,EAAS,CAAA;AACvD;AAEO,SAAS,OAAA,GAAU;AACxB,EAAA,MAAM,GAAA,GAAM,WAAW,WAAW,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,0CAA0C,CAAA;AACpE,EAAA,OAAO,GAAA;AACT;AC7CO,SAAS,gBAAgB,gBAAA,EAA4B;AAC1D,EAAA,MAAM,CAAC,cAAA,EAAgB,WAAW,IAAIC,QAAAA,CAAiB,gBAAA,CAAiB,CAAC,CAAC,CAAA;AAC1E,EAAA,MAAM,CAAC,WAAA,EAAa,YAAY,CAAA,GAAIA,SAAS,IAAI,CAAA;AACjD,EAAAC,UAAU,MAAM;AAAE,IAAA,WAAA,CAAYC,YAAAA,CAAa,gBAAgB,CAAC,CAAA;AAAG,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EAAE,CAAA,EAAG,CAAC,gBAAgB,CAAC,CAAA;AACxG,EAAA,OAAO,EAAE,gBAAgB,WAAA,EAAY;AACvC;ACLO,SAAS,eAAA,CAAgB,QAAgB,SAAA,EAA0B;AACxE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIF,QAAAA,CAA0B,EAAE,CAAA;AACpD,EAAA,MAAM,CAAC,SAAA,EAAW,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC7C,EAAAC,UAAU,MAAM;AAAE,IAAA,UAAA,CAAW,IAAI,CAAA;AAAG,IAAA,aAAA,CAAc,MAAA,EAAQ,SAAS,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,KAAK;AAAE,MAAA,OAAA,CAAQ,CAAC,CAAA;AAAG,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAAE,CAAC,CAAA;AAAA,EAAE,CAAA,EAAG,CAAC,MAAA,EAAQ,SAAS,CAAC,CAAA;AACxI,EAAA,MAAME,GAAA,GAAIC,WAAAA,CAAY,CAAC,GAAA,EAAa,MAAA,KAA6CR,CAAAA,CAAI,GAAA,EAAK,IAAA,EAAM,MAAM,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAC/G,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,KAAWO,GAAA,EAAE;AAC9B;ACPO,SAAS,YAAA,CAAa,MAAqG,SAAA,EAAmS;AACna,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIH,SAAS,EAAE,CAAA;AACvC,EAAA,MAAM,oBAAA,GAAuBK,QAAQ,MAAM;AACzC,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,CAAK,gBAAgB,EAAC;AAC1C,IAAA,MAAM,CAAA,GAAI,OAAO,WAAA,EAAY;AAC7B,IAAA,OAAA,CAAQ,KAAK,YAAA,IAAgB,IAAI,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,GAAA,CAAI,WAAA,GAAc,QAAA,CAAS,CAAC,KAAK,CAAA,CAAE,KAAA,CAAM,aAAY,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,EACnH,CAAA,EAAG,CAAC,IAAA,CAAK,YAAA,EAAc,MAAM,CAAC,CAAA;AAC9B,EAAA,OAAO,EAAE,cAAc,oBAAA,EAAsB,WAAA,EAAa,KAAK,WAAA,IAAe,IAAI,WAAA,EAAa,IAAA,CAAK,eAAe,EAAC,EAAG,QAAQ,SAAA,EAAW,SAAA,EAAW,KAAK,YAAA,KAAiB,MAAA,EAAW,GAAG,SAAA,EAAU;AACrM;ACPO,SAAS,cAAA,CAAe,EAAE,OAAA,EAAS,OAAA,EAAS,UAAS,EAA0E;AACpI,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIL,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,IAAA,GAAOM,YAAY,OAAO,CAAA;AAChC,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAS,MAAM,QAAQ,CAAC,IAAI,CAAA,EAAG,SAAA,EAAU,oIAAA,EAC7D,QAAA,EAAA;AAAA,sBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,gBAAM,IAAA,EAAK,CAAA;AAAA,sBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,IAAA,EAAM,UAAA,EAAW,CAAA;AAAA,sBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8BAA6B,QAAA,EAAA,QAAA,EAAC;AAAA,KAAA,EAC5H,CAAA;AAAA,IACC,IAAA,oBACCA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,iHAAA,EACZ,QAAA,EAAA,OAAA,CAAQ,IAAI,CAAA,CAAA,KAAK;AAAE,MAAA,MAAM,EAAA,GAAKD,YAAY,CAAC,CAAA;AAAG,MAAA,uBAC7C,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAAe,IAAA,EAAK,QAAA;AAAA,UAAS,SAAS,MAAM;AAAE,YAAA,QAAA,CAAS,CAAC,CAAA;AAAG,YAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,UAAE,CAAA;AAAA,UACzE,SAAA,EAAW,CAAA,qEAAA,EAAwE,OAAA,KAAY,CAAA,GAAI,qCAAqC,gCAAgC,CAAA,CAAA;AAAA,UACxK,QAAA,EAAA;AAAA,4BAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,cAAI,IAAA,EAAK,CAAA;AAAA,4BAAOA,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,EAAA,EAAI,UAAA,EAAW,CAAA;AAAA,4BAAOA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAiC,cAAI,IAAA,EAAK,CAAA;AAAA,YACjI,EAAA,EAAI,cAAc,KAAA,oBAASA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEAAiE,QAAA,EAAA,KAAA,EAAG;AAAA;AAAA,SAAA;AAAA,QAHrG;AAAA,OAIb;AAAA,IACD,CAAC,CAAA,EACJ;AAAA,GAAA,EAEJ,CAAA;AAEJ;AAEO,SAAS,UAAA,CAAW,EAAE,QAAA,EAAU,MAAA,EAAO,EAAmD;AAC/F,EAAA,MAAM,MAAM,MAAA,GAASD,WAAAA,CAAY,MAAM,CAAA,EAAG,aAAa,KAAA,GAAQ,KAAA;AAC/D,EAAA,uBAAOC,GAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAU,KAAA,EAAO,EAAE,SAAA,EAAW,GAAA,KAAQ,KAAA,GAAQ,OAAA,GAAU,MAAA,EAAO,EAAI,QAAA,EAAS,CAAA;AAC1F;AAEO,SAAS,kBAAkB,EAAE,MAAA,EAAQ,UAAA,EAAY,aAAA,EAAe,YAAW,EAAqJ;AACrO,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIP,QAAAA,CAAiB,iBAAiB,IAAI,CAAA;AAClE,EAAA,MAAM,CAAC,IAAI,KAAK,CAAA,GAAIA,SAAS,UAAA,GAAa,CAAC,KAAK,QAAQ,CAAA;AACxD,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAIA,QAAAA,CAAS,cAAc,EAAE,CAAA;AAAG,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAS,EAAE,CAAA;AACvF,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gEAAA,EACb,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,YAAA,EACb,QAAA,EAAA;AAAA,sBAAAO,GAAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAO,MAAA,EAAQ,QAAA,EAAU,CAAA,CAAA,KAAK,SAAA,CAAU,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,EAAG,SAAA,EAAU,0FAAA,EAA4F,iBAAO,OAAA,CAAQD,WAAW,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,IAAI,CAAA,qBAAM,IAAA,CAAC,QAAA,EAAA,EAAkB,KAAA,EAAO,IAAA,EAAO,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,IAAA;AAAA,QAAK,GAAA;AAAA,QAAE,IAAA,CAAK;AAAA,OAAA,EAAA,EAArC,IAA0C,CAAS,CAAA,EAAE,CAAA;AAAA,sBAC3RC,GAAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAO,IAAI,QAAA,EAAU,CAAA,CAAA,KAAK,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,EAAG,SAAA,EAAU,4FAA6F,QAAA,EAAA,CAAA,UAAA,IAAc,CAAC,QAAA,EAAU,MAAA,EAAQ,WAAA,EAAa,SAAA,EAAW,QAAQ,CAAA,EAAG,IAAI,CAAA,CAAA,qBAAKA,GAAAA,CAAC,QAAA,EAAA,EAAe,KAAA,EAAO,CAAA,EAAI,QAAA,EAAA,CAAA,EAAA,EAAd,CAAgB,CAAS,CAAA,EAAE;AAAA,KAAA,EACvR,CAAA;AAAA,oBACAA,GAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,MAAA,EAAO,aAAY,0CAAA,EAA2C,KAAA,EAAO,GAAA,EAAK,QAAA,EAAU,OAAK,MAAA,CAAO,CAAA,CAAE,OAAO,KAAK,CAAA,EAAG,WAAU,iJAAA,EAAkJ,CAAA;AAAA,oBACzRA,GAAAA,CAAC,UAAA,EAAA,EAAS,WAAA,EAAY,yBAAA,EAAqB,OAAc,QAAA,EAAU,CAAA,CAAA,KAAK,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,WAAU,6JAAA,EAA8J,CAAA;AAAA,oBACnRA,GAAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,SAAS,MAAM;AAAE,MAAA,MAAA,CAAO,MAAA,EAAQ,EAAA,EAAI,GAAA,EAAK,KAAK,CAAA;AAAG,MAAA,MAAA,CAAO,EAAE,CAAA;AAAG,MAAA,QAAA,CAAS,EAAE,CAAA;AAAA,IAAE,CAAA,EAAG,UAAU,CAAC,GAAA,IAAO,CAAC,KAAA,EAAO,SAAA,EAAU,6GAA4G,QAAA,EAAA,kBAAA,EAAgB;AAAA,GAAA,EACrQ,CAAA;AAEJ;AAEO,SAAS,iBAAiB,EAAE,YAAA,EAAc,MAAA,EAAQ,QAAA,EAAU,UAAS,EAA4I;AACtN,EAAA,IAAI,aAAa,MAAA,KAAW,CAAA,yBAAU,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,kCAAA,EAAmC,QAAA,EAAA;AAAA,oBAAAA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0BAAA,EAA2B,QAAA,EAAA,WAAA,EAAE,CAAA;AAAA,oBAAMA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yBAAwB,QAAA,EAAA,iCAAA,EAA+B;AAAA,GAAA,EAAI,CAAA;AAClN,EAAA,uBACEA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oDACb,QAAA,kBAAA,IAAA,CAAC,OAAA,EAAA,EAAM,WAAU,gBAAA,EAAiB,QAAA,EAAA;AAAA,oBAAAA,GAAAA,CAAC,OAAA,EAAA,EAAM,QAAA,kBAAA,IAAA,CAAC,IAAA,EAAA,EAAG,WAAU,yCAAA,EAA0C,QAAA,EAAA;AAAA,sBAAAA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,iEAAA,EAAkE,QAAA,EAAA,KAAA,EAAG,CAAA;AAAA,sBAAKA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,mEAAkE,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,sBAAKA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,mEAAkE,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,sBAAKA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,oEAAmE,QAAA,EAAA,SAAA,EAAO;AAAA,KAAA,EAAK,CAAA,EAAK,CAAA;AAAA,oBACndA,GAAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,yBAAA,EAA2B,QAAA,EAAA,YAAA,CAAa,GAAA,CAAI,CAAA,CAAA,qBAC3D,IAAA,CAAC,IAAA,EAAA,EAAc,SAAA,EAAU,6BAAA,EACvB,QAAA,EAAA;AAAA,sBAAAA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,6CAAA,EAA+C,YAAE,GAAA,EAAI,CAAA;AAAA,sBACnEA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,2CAAA,EAA6C,YAAE,KAAA,EAAM,CAAA;AAAA,sBACnEA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,WAAA,EAAY,QAAA,kBAAAA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4DAAA,EAA8D,QAAA,EAAA,CAAA,CAAE,SAAA,EAAU,CAAA,EAAO,CAAA;AAAA,sBAC3HA,IAAC,IAAA,EAAA,EAAG,SAAA,EAAU,wBAAwB,QAAA,EAAA,QAAA,oBAAYA,IAAC,QAAA,EAAA,EAAO,IAAA,EAAK,UAAS,OAAA,EAAS,MAAM,SAAS,CAAA,CAAE,GAAG,GAAG,SAAA,EAAU,8FAAA,EAA+F,oBAAM,CAAA,EAAU;AAAA,KAAA,EAAA,EAJ1N,CAAA,CAAE,EAKX,CACD,CAAA,EAAE;AAAA,GAAA,EAAQ,CAAA,EACb,CAAA;AAEJ;AAEO,SAAS,eAAA,CAAgB,EAAE,KAAA,EAAO,MAAA,EAAO,EAAsC;AACpF,EAAA,IAAI,KAAA,KAAU,GAAG,OAAO,IAAA;AACxB,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2FAAA,EAA4F,QAAA,EAAA;AAAA,oBAAAA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU,QAAA,EAAA,cAAA,EAAE,CAAA;AAAA,oBAAO,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sBAAA,EAAwB,QAAA,EAAA;AAAA,MAAA,KAAA;AAAA,MAAM,cAAA;AAAA,MAAa,KAAA,GAAQ,IAAI,GAAA,GAAM,EAAA;AAAA,MAAG,OAAA;AAAA,sBAAKA,GAAAA,CAAC,QAAA,EAAA,EAAQ,UAAAD,WAAAA,CAAY,MAAM,GAAG,IAAA,EAAK;AAAA,KAAA,EAAS;AAAA,GAAA,EAAO,CAAA;AAC/R;AAEO,SAAS,eAAA,CAAgB,EAAE,KAAA,EAAM,EAA4B;AAClE,EAAA,uBACEC,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,sDAAA,EAAwD,QAAA,EAAA,KAAA,CAAM,IAAI,CAAA,CAAA,KAAK;AACpF,IAAA,MAAM,IAAA,GAAOD,WAAAA,CAAY,CAAA,CAAE,MAAM,CAAA;AACjC,IAAA,MAAM,KAAA,GAAQ,EAAE,QAAA,IAAY,EAAA,GAAK,mBAAmB,CAAA,CAAE,QAAA,IAAY,KAAK,cAAA,GAAiB,YAAA;AACxF,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAmB,SAAA,EAAU,sDAAA,EAC5B,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,8BAAA,EAA+B,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,gBAAM,IAAA,EAAK,CAAA;AAAA,wBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,gBAAM,UAAA,EAAW;AAAA,OAAA,EAAO,CAAA;AAAA,sBACxK,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qDAAA,EAAsD,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,UAAA,CAAA,CAAE,SAAA;AAAA,UAAU;AAAA,SAAA,EAAK,CAAA;AAAA,wBAAO,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,WAAA,EAAa,QAAA,EAAA;AAAA,UAAA,CAAA,CAAE,QAAA;AAAA,UAAS;AAAA,SAAA,EAAC;AAAA,OAAA,EAAO,CAAA;AAAA,sBACpJA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAgD,QAAA,kBAAAA,GAAAA,CAAC,SAAI,SAAA,EAAW,CAAA,oBAAA,EAAuB,KAAK,CAAA,CAAA,EAAI,KAAA,EAAO,EAAE,KAAA,EAAO,CAAA,EAAG,EAAE,QAAQ,CAAA,CAAA,CAAA,IAAO,CAAA,EAAE,CAAA;AAAA,MACpJ,EAAE,WAAA,GAAc,CAAA,oBAAK,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,iCAAA,EAAmC,QAAA,EAAA;AAAA,QAAA,CAAA,CAAE,WAAA;AAAA,QAAY;AAAA,OAAA,EAAQ;AAAA,KAAA,EAAA,EAJpF,EAAE,MAKZ,CAAA;AAAA,EAEJ,CAAC,CAAA,EAAE,CAAA;AAEP;AC9EO,SAAS,cAAc,EAAE,YAAA,EAAc,WAAA,EAAa,WAAA,EAAa,WAAU,EAAuB;AACvG,EAAA,MAAM,QAAQ,YAAA,CAAa,EAAE,cAAc,WAAA,EAAa,WAAA,IAAe,SAAS,CAAA;AAChF,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIP,SAAiB,IAAI,CAAA;AACjE,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,SAAS,QAAQ,CAAA;AAErD,EAAA,MAAM,oBAAA,GAAuB,KAAA,CAAM,YAAA,CAAa,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,MAAA,KAAW,cAAA,IAAkB,CAAA,CAAE,SAAA,KAAc,UAAU,CAAA;AAErH,EAAA,IAAI,KAAA,CAAM,SAAA,EAAW,uBACnBO,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sCAAA,EAAuC,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EACnE,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oDAAA,EAAqD,CAAA;AAAA,oBACpEA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+BAA+B,QAAA,EAAA,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAG,EAAE,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBAAMA,GAAAA,CAAC,SAAY,SAAA,EAAU,0CAAA,EAAA,EAAb,CAAwD,CAAE,CAAA,EAAE,CAAA;AAAA,oBAC5JA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0CAAA,EAA2C;AAAA,GAAA,EAC5D,CAAA,EAAM,CAAA;AAGR,EAAA,uBACEA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAuC,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACnE,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA,mBAAA,EAAiB,CAAA;AAAA,IACvE,KAAA,CAAM,YAAY,MAAA,GAAS,CAAA,oBAAKC,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,MAAA,EAAO,QAAA,EAAA;AAAA,sBAAAD,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,iBAAA,EAAe,CAAA;AAAA,sBAAKA,GAAAA,CAAC,eAAA,EAAA,EAAgB,KAAA,EAAO,MAAM,WAAA,EAAa;AAAA,KAAA,EAAE,CAAA;AAAA,IAChL,KAAA,CAAM,WAAA,CAAY,MAAA,GAAS,CAAA,oBAAKA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EAAO,QAAA,kBAAAA,GAAAA,CAAC,eAAA,EAAA,EAAgB,OAAO,KAAA,CAAM,WAAA,CAAY,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,KAAW,cAAc,CAAA,CAAE,MAAA,EAAQ,MAAA,EAAQ,cAAA,EAAgB,CAAA,EAAE,CAAA;AAAA,oBAC5KC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACb,QAAA,EAAA;AAAA,wBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mCAAA,EACb,QAAA,EAAA;AAAA,0BAAAD,GAAAA,CAAC,YAAO,KAAA,EAAO,cAAA,EAAgB,UAAU,CAAA,CAAA,KAAK,iBAAA,CAAkB,EAAE,MAAA,CAAO,KAAe,GAAG,SAAA,EAAU,wFAAA,EAA0F,sBAAY,GAAA,CAAI,CAAA,CAAA,qBAAKC,IAAAA,CAAC,QAAA,EAAA,EAAe,OAAO,CAAA,EAAI,QAAA,EAAA;AAAA,YAAAF,WAAAA,CAAY,CAAC,CAAA,CAAE,IAAA;AAAA,YAAK,GAAA;AAAA,YAAEA,WAAAA,CAAY,CAAC,CAAA,CAAE;AAAA,WAAA,EAAA,EAAnD,CAAwD,CAAS,CAAA,EAAE,CAAA;AAAA,0BACpSC,GAAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAA,KAAK,aAAA,CAAc,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,EAAG,WAAU,wFAAA,EAA0F,QAAA,EAAA,CAAC,QAAA,EAAU,MAAA,EAAQ,WAAA,EAAa,SAAA,EAAW,QAAQ,CAAA,CAAE,IAAI,CAAA,CAAA,qBAAKA,GAAAA,CAAC,QAAA,EAAA,EAAe,KAAA,EAAO,CAAA,EAAI,QAAA,EAAA,CAAA,EAAA,EAAd,CAAgB,CAAS,CAAA,EAAE,CAAA;AAAA,0BACnRA,GAAAA,CAAC,OAAA,EAAA,EAAM,MAAK,MAAA,EAAO,WAAA,EAAY,gBAAU,KAAA,EAAO,KAAA,CAAM,QAAQ,QAAA,EAAU,CAAA,CAAA,KAAK,MAAM,SAAA,CAAU,CAAA,CAAE,OAAO,KAAK,CAAA,EAAG,WAAU,0HAAA,EAA2H;AAAA,SAAA,EACrP,CAAA;AAAA,wBACAA,GAAAA,CAAC,gBAAA,EAAA,EAAiB,YAAA,EAAc,sBAAsB,MAAA,EAAQ,cAAA,EAAgB,QAAA,EAAU,CAAC,GAAA,KAAQ,KAAA,CAAM,SAAA,CAAU,cAAA,EAAgB,GAAG,CAAA,EAAG;AAAA,OAAA,EACzI,CAAA;AAAA,sBACAA,IAAC,KAAA,EAAA,EAAI,QAAA,kBAAAA,IAAC,iBAAA,EAAA,EAAkB,MAAA,EAAQ,CAAC,CAAA,EAAG,EAAA,EAAI,GAAG,CAAA,KAAM,KAAA,CAAM,OAAO,CAAA,EAAG,EAAA,EAAI,GAAG,CAAC,CAAA,EAAG,aAAA,EAAe,cAAA,EAAgB,CAAA,EAAE;AAAA,KAAA,EAC/G;AAAA,GAAA,EACF,CAAA,EAAM,CAAA;AAEV;ACnCA,SAAS,cAAA,GAAiB;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,CAAA,EAAG,SAAA,EAAW,KAAA,EAAO,WAAW,UAAA,EAAY,YAAA,EAAc,cAAA,EAAe,GAAI,OAAA,EAAQ;AACrG,EAAA,MAAM,IAAA,GAAOD,YAAY,MAAM,CAAA;AAC/B,EAAA,uBACEC,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAuC,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACnE,QAAA,EAAA;AAAA,oBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA;AAAA,sBAAAD,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,mCAAA,EAAoC,QAAA,EAAA,gBAAA,EAAc,CAAA;AAAA,sBAAKA,IAAC,cAAA,EAAA,EAAe,OAAA,EAASE,aAAa,OAAA,EAAS,MAAA,EAAQ,UAAU,SAAA,EAAW;AAAA,KAAA,EAAE,CAAA;AAAA,oBAC3MD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EACb,QAAA,EAAA;AAAA,sBAAAD,IAAC,QAAA,EAAA,EAAS,KAAA,EAAM,UAAS,KAAA,EAAO,MAAA,CAAO,aAAY,EAAG,CAAA;AAAA,sBACtDA,IAAC,QAAA,EAAA,EAAS,KAAA,EAAM,aAAY,KAAA,EAAO,SAAA,EAAW,WAAW,KAAA,EAAO,CAAA;AAAA,sBAChEA,IAAC,QAAA,EAAA,EAAS,KAAA,EAAM,UAAS,KAAA,EAAO,IAAA,EAAM,cAAc,GAAA,EAAK,CAAA;AAAA,sBACzDA,IAAC,QAAA,EAAA,EAAS,KAAA,EAAM,QAAO,KAAA,EAAO,IAAA,EAAM,QAAQ,GAAA,EAAK;AAAA,KAAA,EACnD,CAAA;AAAA,oBACAA,IAAC,UAAA,EAAA,EAAW,MAAA,EACV,0BAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,WAAA,EACb,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACb,QAAA,EAAA;AAAA,wBAAAD,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,qBAAA,EAAmB,CAAA;AAAA,wBAC5EC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EACb,QAAA,EAAA;AAAA,0BAAAD,GAAAA,CAAC,OAAI,KAAA,EAAM,MAAA,EAAO,OAAO,UAAA,iBAAW,IAAI,IAAA,EAAM,CAAA,EAAG,CAAA;AAAA,0BACjDA,GAAAA,CAAC,GAAA,EAAA,EAAI,KAAA,EAAM,eAAc,KAAA,EAAO,UAAA,iBAAW,IAAI,IAAA,EAAK,EAAG,EAAE,SAAA,EAAW,MAAA,EAAQ,CAAA,EAAG,CAAA;AAAA,0BAC/EA,IAAC,GAAA,EAAA,EAAI,KAAA,EAAM,UAAS,KAAA,EAAO,YAAA,CAAa,YAAU,CAAA,EAAG,CAAA;AAAA,0BACrDA,IAAC,GAAA,EAAA,EAAI,KAAA,EAAM,kBAAiB,KAAA,EAAO,cAAA,CAAe,OAAA,EAAS,KAAK,CAAA,EAAG,CAAA;AAAA,0BACnEA,IAAC,GAAA,EAAA,EAAI,KAAA,EAAM,kBAAiB,KAAA,EAAO,cAAA,CAAe,MAAA,EAAS,KAAK,CAAA,EAAG,CAAA;AAAA,0BACnEA,GAAAA,CAAC,GAAA,EAAA,EAAI,KAAA,EAAM,YAAA,EAAa,KAAA,EAAO,YAAA,CAAa,IAAA,EAAM,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA,EAAG;AAAA,SAAA,EAC3E;AAAA,OAAA,EACF,CAAA;AAAA,MACC,yBAASA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8FAA6F,QAAA,EAAA,wDAAA,EAA4C,CAAA;AAAA,sBAClKC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACb,QAAA,EAAA;AAAA,wBAAAD,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EAA2C,QAAA,EAAA,aAAA,EAAW,CAAA;AAAA,wBACpEA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yCAAwC,QAAA,EAAA,6HAAA,EAA2H;AAAA,OAAA,EAClL;AAAA,KAAA,EACF,CAAA,EACF;AAAA,GAAA,EACF,CAAA,EAAM,CAAA;AAEV;AAEA,SAAS,QAAA,CAAS,EAAE,KAAA,EAAO,KAAA,EAAO,WAAU,EAA0D;AACpG,EAAA,uBAAOC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EAAuD,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,0CAAA,EAA4C,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,oBAAIA,IAAC,GAAA,EAAA,EAAE,SAAA,EAAW,qBAAqB,SAAA,GAAY,gBAAA,GAAmB,eAAe,CAAA,CAAA,EAAK,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EAAI,CAAA;AAClP;AAEA,SAAS,GAAA,CAAI,EAAE,KAAA,EAAO,KAAA,EAAM,EAAqC;AAC/D,EAAA,uBAAOC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sBAAA,EAAuB,QAAA,EAAA;AAAA,oBAAAD,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,eAAA,EAAiB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,oBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAmC,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EAAO,CAAA;AAC7J;AAEO,SAAS,iBAAA,CAAkB,EAAE,MAAA,EAAQ,YAAA,EAAa,EAAoG;AAC3J,EAAA,MAAM,UAAA,GAAwD,EAAE,aAAA,EAAe,IAAA,EAAM,gBAAA,EAAkBE,WAAAA,EAAa,aAAA,EAAe,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,GAAG,MAAA,EAAO;AACxK,EAAA,uBAAOF,IAAC,YAAA,EAAA,EAAa,MAAA,EAAQ,YAAY,YAAA,EAA4B,QAAA,kBAAAA,GAAAA,CAAC,cAAA,EAAA,EAAe,CAAA,EAAE,CAAA;AACzF","file":"index.js","sourcesContent":["import React, { createContext, useContext, useState, useCallback, useEffect, useMemo } from 'react'\nimport type { Locale, Direction, TranslationDict, I18nConfig } from '@geenius/i18n-shared'\nimport { t as tFn, plural, formatDate as fmtDate, formatNumber as fmtNum, formatCurrency as fmtCur, getDirection, isRTL as checkRTL, detectLocale, LOCALE_INFO } from '@geenius/i18n-shared'\n\ninterface I18nContextValue {\n locale: Locale; direction: Direction; isRTL: boolean\n setLocale: (l: Locale) => void; t: (key: string, params?: Record<string, string | number>) => string\n formatDate: (date: Date | string, opts?: Intl.DateTimeFormatOptions) => string\n formatNumber: (n: number, opts?: Intl.NumberFormatOptions) => string\n formatCurrency: (amount: number, currency: string) => string\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nexport function I18nProvider({ children, config, translations }: { children: React.ReactNode; config: I18nConfig; translations?: TranslationDict }) {\n const [locale, setLocaleState] = useState<Locale>(() => {\n if (config.persistLocale && typeof localStorage !== 'undefined') {\n const saved = localStorage.getItem('geenius-locale')\n if (saved && config.supportedLocales.includes(saved as Locale)) return saved as Locale\n }\n if (config.detectBrowser) return detectLocale(config.supportedLocales)\n return config.defaultLocale\n })\n\n const setLocale = useCallback((l: Locale) => {\n setLocaleState(l)\n if (config.persistLocale && typeof localStorage !== 'undefined') localStorage.setItem('geenius-locale', l)\n if (typeof document !== 'undefined') { document.documentElement.dir = getDirection(l); document.documentElement.lang = l }\n }, [config.persistLocale])\n\n useEffect(() => {\n if (typeof document !== 'undefined') { document.documentElement.dir = getDirection(locale); document.documentElement.lang = locale }\n }, [locale])\n\n const value = useMemo<I18nContextValue>(() => ({\n locale, direction: getDirection(locale), isRTL: checkRTL(locale), setLocale,\n t: (key, params) => tFn(key, translations ?? {}, params),\n formatDate: (date, opts) => fmtDate(date, locale, opts),\n formatNumber: (n, opts) => fmtNum(n, locale, opts),\n formatCurrency: (amount, currency) => fmtCur(amount, currency, locale),\n }), [locale, setLocale, translations])\n\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useI18n() {\n const ctx = useContext(I18nContext)\n if (!ctx) throw new Error('useI18n must be used within I18nProvider')\n return ctx\n}\n","import { useState, useEffect } from 'react'\nimport type { Locale } from '@geenius/i18n-shared'\nimport { detectLocale } from '@geenius/i18n-shared'\n\nexport function useLocaleDetect(supportedLocales: Locale[]) {\n const [detectedLocale, setDetected] = useState<Locale>(supportedLocales[0])\n const [isDetecting, setDetecting] = useState(true)\n useEffect(() => { setDetected(detectLocale(supportedLocales)); setDetecting(false) }, [supportedLocales])\n return { detectedLocale, isDetecting }\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react'\nimport type { Locale, TranslationDict, I18nNamespace } from '@geenius/i18n-shared'\nimport { t as tFn, loadNamespace } from '@geenius/i18n-shared'\n\nexport function useTranslations(locale: Locale, namespace: I18nNamespace) {\n const [dict, setDict] = useState<TranslationDict>({})\n const [isLoading, setLoading] = useState(true)\n useEffect(() => { setLoading(true); loadNamespace(locale, namespace).then(d => { setDict(d); setLoading(false) }) }, [locale, namespace])\n const t = useCallback((key: string, params?: Record<string, string | number>) => tFn(key, dict, params), [dict])\n return { dict, isLoading, t }\n}\n","import { useState, useMemo } from 'react'\nimport type { TranslationEntry, MissingKey, LocaleStat } from '@geenius/i18n-shared'\n\nexport function useI18nAdmin(data: { translations?: TranslationEntry[]; missingKeys?: MissingKey[]; localeStats?: LocaleStat[] }, mutations: { upsert: (locale: string, ns: string, key: string, value: string) => Promise<void>; deleteKey: (locale: string, key: string) => Promise<void>; importDict: (locale: string, ns: string, dict: Record<string, string>) => Promise<void>; clearMissing: (id: string) => Promise<void> }) {\n const [search, setSearch] = useState('')\n const filteredTranslations = useMemo(() => {\n if (!search) return data.translations ?? []\n const q = search.toLowerCase()\n return (data.translations ?? []).filter(t => t.key.toLowerCase().includes(q) || t.value.toLowerCase().includes(q))\n }, [data.translations, search])\n return { translations: filteredTranslations, missingKeys: data.missingKeys ?? [], localeStats: data.localeStats ?? [], search, setSearch, isLoading: data.translations === undefined, ...mutations }\n}\n","import React, { useState } from 'react'\nimport type { Locale, Direction, TranslationEntry, MissingKey, LocaleStat } from '@geenius/i18n-shared'\nimport { LOCALE_INFO } from '@geenius/i18n-shared'\n\nexport function LocaleSwitcher({ locales, current, onChange }: { locales: Locale[]; current: Locale; onChange: (l: Locale) => void }) {\n const [open, setOpen] = useState(false)\n const info = LOCALE_INFO[current]\n return (\n <div className=\"relative\">\n <button type=\"button\" onClick={() => setOpen(!open)} className=\"flex items-center gap-2 rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white hover:bg-white/10 transition-all\">\n <span className=\"text-lg\">{info?.flag}</span><span>{info?.nativeName}</span><span className=\"text-white/30 text-xs ml-1\">▼</span>\n </button>\n {open && (\n <div className=\"absolute top-full mt-1 right-0 z-50 min-w-[200px] rounded-xl border border-white/10 bg-[#111118] py-1 shadow-xl\">\n {locales.map(l => { const li = LOCALE_INFO[l]; return (\n <button key={l} type=\"button\" onClick={() => { onChange(l); setOpen(false) }}\n className={`flex w-full items-center gap-3 px-4 py-2.5 text-sm transition-colors ${current === l ? 'bg-indigo-500/15 text-indigo-300' : 'text-white/70 hover:bg-white/5'}`}>\n <span className=\"text-lg\">{li?.flag}</span><span>{li?.nativeName}</span><span className=\"text-xs text-white/30 ml-auto\">{li?.name}</span>\n {li?.direction === 'rtl' && <span className=\"text-[10px] px-1 py-0.5 rounded bg-amber-500/15 text-amber-400\">RTL</span>}\n </button>\n )})}\n </div>\n )}\n </div>\n )\n}\n\nexport function RTLWrapper({ children, locale }: { children: React.ReactNode; locale?: Locale }) {\n const dir = locale ? LOCALE_INFO[locale]?.direction ?? 'ltr' : 'ltr'\n return <div dir={dir} style={{ textAlign: dir === 'rtl' ? 'right' : 'left' }}>{children}</div>\n}\n\nexport function TranslationEditor({ onSave, initialKey, initialLocale, namespaces }: { onSave: (locale: string, ns: string, key: string, value: string) => void; initialKey?: string; initialLocale?: Locale; namespaces?: string[] }) {\n const [locale, setLocale] = useState<string>(initialLocale ?? 'en')\n const [ns, setNs] = useState(namespaces?.[0] ?? 'common')\n const [key, setKey] = useState(initialKey ?? ''); const [value, setValue] = useState('')\n return (\n <div className=\"space-y-3 rounded-xl border border-white/8 bg-white/[0.02] p-5\">\n <div className=\"flex gap-2\">\n <select value={locale} onChange={e => setLocale(e.target.value)} className=\"rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-xs text-white outline-none\">{Object.entries(LOCALE_INFO).map(([code, info]) => <option key={code} value={code}>{info.flag} {info.name}</option>)}</select>\n <select value={ns} onChange={e => setNs(e.target.value)} className=\"rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-xs text-white outline-none\">{(namespaces ?? ['common', 'auth', 'dashboard', 'billing', 'errors']).map(n => <option key={n} value={n}>{n}</option>)}</select>\n </div>\n <input type=\"text\" placeholder=\"Translation key (e.g. auth.login_button)\" value={key} onChange={e => setKey(e.target.value)} className=\"w-full rounded-xl border border-white/10 bg-white/5 px-4 py-2.5 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/40\" />\n <textarea placeholder=\"Translation value…\" value={value} onChange={e => setValue(e.target.value)} rows={3} className=\"w-full rounded-xl border border-white/10 bg-white/5 px-4 py-2.5 text-sm text-white placeholder-white/30 outline-none focus:border-indigo-500/40 resize-none\" />\n <button type=\"button\" onClick={() => { onSave(locale, ns, key, value); setKey(''); setValue('') }} disabled={!key || !value} className=\"rounded-lg bg-indigo-600 px-4 py-2 text-xs font-medium text-white hover:bg-indigo-500 disabled:opacity-50\">Save Translation</button>\n </div>\n )\n}\n\nexport function TranslationTable({ translations, locale, onUpdate, onDelete }: { translations: TranslationEntry[]; locale: Locale; onUpdate?: (key: string, value: string) => void; onDelete?: (key: string) => void }) {\n if (translations.length === 0) return <div className=\"flex flex-col items-center py-12\"><div className=\"mb-3 text-4xl opacity-20\">🌐</div><p className=\"text-sm text-white/40\">No translations for this locale</p></div>\n return (\n <div className=\"overflow-x-auto rounded-xl border border-white/8\">\n <table className=\"w-full text-sm\"><thead><tr className=\"border-b border-white/8 bg-white/[0.02]\"><th className=\"px-4 py-3 text-left text-xs font-medium text-white/40 uppercase\">Key</th><th className=\"px-4 py-3 text-left text-xs font-medium text-white/40 uppercase\">Value</th><th className=\"px-4 py-3 text-left text-xs font-medium text-white/40 uppercase\">Namespace</th><th className=\"px-4 py-3 text-right text-xs font-medium text-white/40 uppercase\">Actions</th></tr></thead>\n <tbody className=\"divide-y divide-white/5\">{translations.map(t => (\n <tr key={t.id} className=\"group hover:bg-white/[0.02]\">\n <td className=\"px-4 py-3 font-mono text-xs text-indigo-300\">{t.key}</td>\n <td className=\"px-4 py-3 text-white/70 max-w-xs truncate\">{t.value}</td>\n <td className=\"px-4 py-3\"><span className=\"rounded bg-white/5 px-1.5 py-0.5 text-[10px] text-white/40\">{t.namespace}</span></td>\n <td className=\"px-4 py-3 text-right\">{onDelete && <button type=\"button\" onClick={() => onDelete(t.key)} className=\"rounded px-2 py-1 text-xs text-white/20 hover:text-red-400 opacity-0 group-hover:opacity-100\">Delete</button>}</td>\n </tr>\n ))}</tbody></table>\n </div>\n )\n}\n\nexport function MissingKeyAlert({ count, locale }: { count: number; locale: Locale }) {\n if (count === 0) return null\n return <div className=\"flex items-center gap-3 rounded-lg border border-red-500/20 bg-red-500/[0.05] px-4 py-2.5\"><span className=\"text-sm\">⚠️</span><span className=\"text-xs text-red-300\">{count} missing key{count > 1 ? 's' : ''} for <strong>{LOCALE_INFO[locale]?.name}</strong></span></div>\n}\n\nexport function LocaleStatsCard({ stats }: { stats: LocaleStat[] }) {\n return (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4\">{stats.map(s => {\n const info = LOCALE_INFO[s.locale]\n const color = s.coverage >= 90 ? 'bg-emerald-500' : s.coverage >= 70 ? 'bg-amber-500' : 'bg-red-500'\n return (\n <div key={s.locale} className=\"rounded-xl border border-white/8 bg-white/[0.02] p-4\">\n <div className=\"flex items-center gap-2 mb-2\"><span className=\"text-lg\">{info?.flag}</span><span className=\"text-xs font-medium text-white/80\">{info?.nativeName}</span></div>\n <div className=\"mb-1 flex justify-between text-[10px] text-white/40\"><span>{s.totalKeys} keys</span><span className=\"font-bold\">{s.coverage}%</span></div>\n <div className=\"h-1.5 rounded-full bg-white/5 overflow-hidden\"><div className={`h-full rounded-full ${color}`} style={{ width: `${s.coverage}%` }} /></div>\n {s.missingKeys > 0 && <p className=\"mt-1.5 text-[10px] text-red-400\">{s.missingKeys} missing</p>}\n </div>\n )\n })}</div>\n )\n}\n","import React, { useState } from 'react'\nimport type { Locale, TranslationEntry, MissingKey, LocaleStat } from '@geenius/i18n-shared'\nimport { LOCALE_INFO, ALL_LOCALES } from '@geenius/i18n-shared'\nimport { useI18nAdmin } from '../hooks/useI18nAdmin'\nimport { LocaleStatsCard, MissingKeyAlert, TranslationTable, TranslationEditor } from '../components'\n\ninterface I18nAdminPageProps { translations?: TranslationEntry[]; missingKeys?: MissingKey[]; localeStats?: LocaleStat[]; mutations: Parameters<typeof useI18nAdmin>[1] }\n\nexport function I18nAdminPage({ translations, missingKeys, localeStats, mutations }: I18nAdminPageProps) {\n const admin = useI18nAdmin({ translations, missingKeys, localeStats }, mutations)\n const [selectedLocale, setSelectedLocale] = useState<Locale>('en')\n const [selectedNs, setSelectedNs] = useState('common')\n\n const filteredTranslations = admin.translations.filter(t => t.locale === selectedLocale && t.namespace === selectedNs)\n\n if (admin.isLoading) return (\n <div className=\"min-h-screen bg-[#090a0f] px-6 py-12\"><div className=\"mx-auto max-w-6xl\">\n <div className=\"mb-8 h-10 w-48 animate-pulse rounded-lg bg-white/5\" />\n <div className=\"mb-6 grid grid-cols-4 gap-3\">{Array.from({ length: 8 }).map((_, i) => <div key={i} className=\"h-20 animate-pulse rounded-xl bg-white/5\" />)}</div>\n <div className=\"h-96 animate-pulse rounded-xl bg-white/5\" />\n </div></div>\n )\n\n return (\n <div className=\"min-h-screen bg-[#090a0f] text-white\"><div className=\"mx-auto max-w-6xl px-6 py-12\">\n <h1 className=\"text-2xl font-bold tracking-tight mb-8\">Translation Admin</h1>\n {admin.localeStats.length > 0 && <div className=\"mb-8\"><h2 className=\"text-sm font-semibold text-white/60 mb-4\">Locale Coverage</h2><LocaleStatsCard stats={admin.localeStats} /></div>}\n {admin.missingKeys.length > 0 && <div className=\"mb-6\"><MissingKeyAlert count={admin.missingKeys.filter(m => m.locale === selectedLocale).length} locale={selectedLocale} /></div>}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <select value={selectedLocale} onChange={e => setSelectedLocale(e.target.value as Locale)} className=\"rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-sm text-white outline-none\">{ALL_LOCALES.map(l => <option key={l} value={l}>{LOCALE_INFO[l].flag} {LOCALE_INFO[l].name}</option>)}</select>\n <select value={selectedNs} onChange={e => setSelectedNs(e.target.value)} className=\"rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-sm text-white outline-none\">{['common', 'auth', 'dashboard', 'billing', 'errors'].map(n => <option key={n} value={n}>{n}</option>)}</select>\n <input type=\"text\" placeholder=\"Search…\" value={admin.search} onChange={e => admin.setSearch(e.target.value)} className=\"ml-auto w-48 rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white placeholder-white/30 outline-none\" />\n </div>\n <TranslationTable translations={filteredTranslations} locale={selectedLocale} onDelete={(key) => admin.deleteKey(selectedLocale, key)} />\n </div>\n <div><TranslationEditor onSave={(l, ns, k, v) => admin.upsert(l, ns, k, v)} initialLocale={selectedLocale} /></div>\n </div>\n </div></div>\n )\n}\n","import React from 'react'\nimport type { I18nConfig, TranslationDict } from '@geenius/i18n-shared'\nimport { LOCALE_INFO, ALL_LOCALES } from '@geenius/i18n-shared'\nimport { useI18n, I18nProvider } from '../hooks/useI18n'\nimport { LocaleSwitcher, RTLWrapper } from '../components'\n\nfunction PreviewContent() {\n const { locale, t, direction, isRTL, setLocale, formatDate, formatNumber, formatCurrency } = useI18n()\n const info = LOCALE_INFO[locale]\n return (\n <div className=\"min-h-screen bg-[#090a0f] text-white\"><div className=\"mx-auto max-w-3xl px-6 py-12\">\n <div className=\"mb-8 flex items-center justify-between\"><h1 className=\"text-2xl font-bold tracking-tight\">Locale Preview</h1><LocaleSwitcher locales={ALL_LOCALES} current={locale} onChange={setLocale} /></div>\n <div className=\"mb-6 grid grid-cols-2 gap-4 md:grid-cols-4\">\n <InfoCard label=\"Locale\" value={locale.toUpperCase()} />\n <InfoCard label=\"Direction\" value={direction} highlight={isRTL} />\n <InfoCard label=\"Native\" value={info?.nativeName ?? '?'} />\n <InfoCard label=\"Flag\" value={info?.flag ?? '?'} />\n </div>\n <RTLWrapper locale={locale}>\n <div className=\"space-y-6\">\n <div className=\"rounded-xl border border-white/8 bg-white/[0.02] p-5\">\n <h3 className=\"text-sm font-semibold text-white/80 mb-4\">Formatting Examples</h3>\n <div className=\"space-y-3 text-sm\">\n <Row label=\"Date\" value={formatDate(new Date())} />\n <Row label=\"Date (full)\" value={formatDate(new Date(), { dateStyle: 'full' })} />\n <Row label=\"Number\" value={formatNumber(1234567.89)} />\n <Row label=\"Currency (USD)\" value={formatCurrency(9999.99, 'USD')} />\n <Row label=\"Currency (EUR)\" value={formatCurrency(4250.50, 'EUR')} />\n <Row label=\"Percentage\" value={formatNumber(0.85, { style: 'percent' })} />\n </div>\n </div>\n {isRTL && <div className=\"rounded-lg border border-amber-500/20 bg-amber-500/[0.05] px-4 py-3 text-sm text-amber-300\">⚡ RTL mode active — text flows right-to-left</div>}\n <div className=\"rounded-xl border border-white/8 bg-white/[0.02] p-5\">\n <h3 className=\"text-sm font-semibold text-white/80 mb-3\">Sample Text</h3>\n <p className=\"text-sm text-white/60 leading-relaxed\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>\n </div>\n </div>\n </RTLWrapper>\n </div></div>\n )\n}\n\nfunction InfoCard({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) {\n return <div className=\"rounded-xl border border-white/8 bg-white/[0.02] p-4\"><p className=\"text-[10px] text-white/40 mb-1 uppercase\">{label}</p><p className={`text-lg font-bold ${highlight ? 'text-amber-400' : 'text-white/90'}`}>{value}</p></div>\n}\n\nfunction Row({ label, value }: { label: string; value: string }) {\n return <div className=\"flex justify-between\"><span className=\"text-white/40\">{label}</span><span className=\"text-white/80 font-mono text-xs\">{value}</span></div>\n}\n\nexport function LocalePreviewPage({ config, translations }: { config?: Partial<import('@geenius/i18n-shared').I18nConfig>; translations?: TranslationDict }) {\n const fullConfig: import('@geenius/i18n-shared').I18nConfig = { defaultLocale: 'en', supportedLocales: ALL_LOCALES, detectBrowser: true, persistLocale: true, ...config }\n return <I18nProvider config={fullConfig} translations={translations}><PreviewContent /></I18nProvider>\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# ✦ @geenius-
|
|
1
|
+
# ✦ @geenius/i18n-react-css\n\n> Geenius i18n — React components & hooks (vanilla CSS variant)\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius/i18n-react-css\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius/i18n-react-css';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export { I18nProvider, useI18n, useI18nAdmin, useLocaleDetect, useTranslations } from '@geenius/i18n-react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { LocaleStat, Locale, TranslationEntry } from '@geenius/i18n-shared';
|
|
5
|
+
export { Direction, I18nConfig, I18nNamespace, Locale, LocaleInfo, LocaleStat, MissingKey, TranslationDict, TranslationEntry } from '@geenius/i18n-shared';
|
|
6
|
+
|
|
7
|
+
declare function LocaleSwitcher({ locales, current, onChange }: {
|
|
8
|
+
locales: Locale[];
|
|
9
|
+
current: Locale;
|
|
10
|
+
onChange: (l: Locale) => void;
|
|
11
|
+
}): react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare function RTLWrapper({ children, locale }: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
locale?: Locale;
|
|
15
|
+
}): react_jsx_runtime.JSX.Element;
|
|
16
|
+
declare function TranslationEditor({ onSave, initialLocale, namespaces }: {
|
|
17
|
+
onSave: (l: string, ns: string, k: string, v: string) => void;
|
|
18
|
+
initialLocale?: Locale;
|
|
19
|
+
namespaces?: string[];
|
|
20
|
+
}): react_jsx_runtime.JSX.Element;
|
|
21
|
+
declare function TranslationTable({ translations, locale, onDelete }: {
|
|
22
|
+
translations: TranslationEntry[];
|
|
23
|
+
locale: Locale;
|
|
24
|
+
onDelete?: (key: string) => void;
|
|
25
|
+
}): react_jsx_runtime.JSX.Element;
|
|
26
|
+
declare function MissingKeyAlert({ count, locale }: {
|
|
27
|
+
count: number;
|
|
28
|
+
locale: Locale;
|
|
29
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
30
|
+
declare function LocaleStatsCard({ stats }: {
|
|
31
|
+
stats: LocaleStat[];
|
|
32
|
+
}): react_jsx_runtime.JSX.Element;
|
|
33
|
+
|
|
34
|
+
export { LocaleStatsCard, LocaleSwitcher, MissingKeyAlert, RTLWrapper, TranslationEditor, TranslationTable };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/hooks/index.ts
|
|
2
|
+
import { I18nProvider, useI18n } from "@geenius/i18n-react";
|
|
3
|
+
import { useLocaleDetect } from "@geenius/i18n-react";
|
|
4
|
+
import { useTranslations } from "@geenius/i18n-react";
|
|
5
|
+
import { useI18nAdmin } from "@geenius/i18n-react";
|
|
6
|
+
|
|
7
|
+
// src/components/index.tsx
|
|
8
|
+
import { useState } from "react";
|
|
9
|
+
import { LOCALE_INFO } from "@geenius/i18n-shared";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
function LocaleSwitcher({ locales, current, onChange }) {
|
|
12
|
+
const [open, setOpen] = useState(false);
|
|
13
|
+
const info = LOCALE_INFO[current];
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", { className: "i18n__locale-switcher", children: [
|
|
15
|
+
/* @__PURE__ */ jsxs("button", { type: "button", className: "i18n__locale-switcher-btn", onClick: () => setOpen(!open), children: [
|
|
16
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__locale-switcher-flag", children: info?.flag }),
|
|
17
|
+
/* @__PURE__ */ jsx("span", { children: info?.nativeName }),
|
|
18
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__locale-switcher-arrow", children: "\u25BC" })
|
|
19
|
+
] }),
|
|
20
|
+
open && /* @__PURE__ */ jsx("div", { className: "i18n__locale-dropdown", children: locales.map((l) => {
|
|
21
|
+
const li = LOCALE_INFO[l];
|
|
22
|
+
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => {
|
|
23
|
+
onChange(l);
|
|
24
|
+
setOpen(false);
|
|
25
|
+
}, className: `i18n__locale-option ${current === l ? "i18n__locale-option--active" : ""}`, children: [
|
|
26
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__locale-option-flag", children: li?.flag }),
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__locale-option-name", children: li?.nativeName }),
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__locale-option-eng", children: li?.name }),
|
|
29
|
+
li?.direction === "rtl" && /* @__PURE__ */ jsx("span", { className: "i18n__locale-option-rtl", children: "RTL" })
|
|
30
|
+
] }, l);
|
|
31
|
+
}) })
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
function RTLWrapper({ children, locale }) {
|
|
35
|
+
const dir = locale ? LOCALE_INFO[locale]?.direction ?? "ltr" : "ltr";
|
|
36
|
+
return /* @__PURE__ */ jsx("div", { className: "i18n__rtl-wrapper", dir, children });
|
|
37
|
+
}
|
|
38
|
+
function TranslationEditor({ onSave, initialLocale, namespaces }) {
|
|
39
|
+
const [locale, setLocale] = useState(initialLocale ?? "en");
|
|
40
|
+
const [ns, setNs] = useState(namespaces?.[0] ?? "common");
|
|
41
|
+
const [key, setKey] = useState("");
|
|
42
|
+
const [value, setValue] = useState("");
|
|
43
|
+
return /* @__PURE__ */ jsxs("div", { className: "i18n__editor", children: [
|
|
44
|
+
/* @__PURE__ */ jsxs("div", { className: "i18n__editor-selectors", children: [
|
|
45
|
+
/* @__PURE__ */ jsx("select", { value: locale, onChange: (e) => setLocale(e.target.value), className: "i18n__editor-select", children: Object.entries(LOCALE_INFO).map(([c, i]) => /* @__PURE__ */ jsxs("option", { value: c, children: [
|
|
46
|
+
i.flag,
|
|
47
|
+
" ",
|
|
48
|
+
i.name
|
|
49
|
+
] }, c)) }),
|
|
50
|
+
/* @__PURE__ */ jsx("select", { value: ns, onChange: (e) => setNs(e.target.value), className: "i18n__editor-select", children: (namespaces ?? ["common", "auth", "dashboard", "billing", "errors"]).map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n)) })
|
|
51
|
+
] }),
|
|
52
|
+
/* @__PURE__ */ jsx("input", { type: "text", className: "i18n__editor-input", placeholder: "Translation key\u2026", value: key, onChange: (e) => setKey(e.target.value) }),
|
|
53
|
+
/* @__PURE__ */ jsx("textarea", { className: "i18n__editor-input i18n__editor-textarea", placeholder: "Translation value\u2026", value, onChange: (e) => setValue(e.target.value) }),
|
|
54
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "i18n__btn i18n__btn--primary", disabled: !key || !value, onClick: () => {
|
|
55
|
+
onSave(locale, ns, key, value);
|
|
56
|
+
setKey("");
|
|
57
|
+
setValue("");
|
|
58
|
+
}, children: "Save Translation" })
|
|
59
|
+
] });
|
|
60
|
+
}
|
|
61
|
+
function TranslationTable({ translations, locale, onDelete }) {
|
|
62
|
+
if (translations.length === 0) return /* @__PURE__ */ jsxs("div", { className: "i18n__empty", children: [
|
|
63
|
+
/* @__PURE__ */ jsx("div", { className: "i18n__empty-icon", children: "\u{1F310}" }),
|
|
64
|
+
/* @__PURE__ */ jsx("div", { className: "i18n__empty-text", children: "No translations for this locale" })
|
|
65
|
+
] });
|
|
66
|
+
return /* @__PURE__ */ jsx("div", { style: { overflowX: "auto", borderRadius: "var(--i18n-radius)", border: "1px solid var(--i18n-border)" }, children: /* @__PURE__ */ jsxs("table", { className: "i18n__translation-table", children: [
|
|
67
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
68
|
+
/* @__PURE__ */ jsx("th", { children: "Key" }),
|
|
69
|
+
/* @__PURE__ */ jsx("th", { children: "Value" }),
|
|
70
|
+
/* @__PURE__ */ jsx("th", { children: "NS" }),
|
|
71
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right" }, children: "Actions" })
|
|
72
|
+
] }) }),
|
|
73
|
+
/* @__PURE__ */ jsx("tbody", { children: translations.map((t) => /* @__PURE__ */ jsxs("tr", { className: "i18n__translation-row", children: [
|
|
74
|
+
/* @__PURE__ */ jsx("td", { className: "i18n__translation-key", children: t.key }),
|
|
75
|
+
/* @__PURE__ */ jsx("td", { className: "i18n__translation-value", children: t.value }),
|
|
76
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("span", { className: "i18n__translation-ns", children: t.namespace }) }),
|
|
77
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right" }, children: onDelete && /* @__PURE__ */ jsx("button", { type: "button", className: "i18n__delete-btn", onClick: () => onDelete(t.key), children: "Delete" }) })
|
|
78
|
+
] }, t.id)) })
|
|
79
|
+
] }) });
|
|
80
|
+
}
|
|
81
|
+
function MissingKeyAlert({ count, locale }) {
|
|
82
|
+
if (count === 0) return null;
|
|
83
|
+
return /* @__PURE__ */ jsxs("div", { className: "i18n__missing-badge", children: [
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__missing-badge-icon", children: "\u26A0\uFE0F" }),
|
|
85
|
+
/* @__PURE__ */ jsxs("span", { className: "i18n__missing-badge-text", children: [
|
|
86
|
+
count,
|
|
87
|
+
" missing key",
|
|
88
|
+
count > 1 ? "s" : "",
|
|
89
|
+
" for ",
|
|
90
|
+
/* @__PURE__ */ jsx("strong", { children: LOCALE_INFO[locale]?.name })
|
|
91
|
+
] })
|
|
92
|
+
] });
|
|
93
|
+
}
|
|
94
|
+
function LocaleStatsCard({ stats }) {
|
|
95
|
+
return /* @__PURE__ */ jsx("div", { className: "i18n__stats-grid", children: stats.map((s) => {
|
|
96
|
+
const info = LOCALE_INFO[s.locale];
|
|
97
|
+
const barClass = s.coverage >= 90 ? "i18n__stats-bar-fill--complete" : s.coverage >= 70 ? "i18n__stats-bar-fill--partial" : "i18n__stats-bar-fill--low";
|
|
98
|
+
return /* @__PURE__ */ jsxs("div", { className: "i18n__stats-card", children: [
|
|
99
|
+
/* @__PURE__ */ jsxs("div", { className: "i18n__stats-card-header", children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__stats-card-flag", children: info?.flag }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: "i18n__stats-card-name", children: info?.nativeName })
|
|
102
|
+
] }),
|
|
103
|
+
/* @__PURE__ */ jsxs("div", { className: "i18n__stats-card-meta", children: [
|
|
104
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
105
|
+
s.totalKeys,
|
|
106
|
+
" keys"
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 700 }, children: [
|
|
109
|
+
s.coverage,
|
|
110
|
+
"%"
|
|
111
|
+
] })
|
|
112
|
+
] }),
|
|
113
|
+
/* @__PURE__ */ jsx("div", { className: "i18n__stats-bar", children: /* @__PURE__ */ jsx("div", { className: `i18n__stats-bar-fill ${barClass}`, style: { width: `${s.coverage}%` } }) }),
|
|
114
|
+
s.missingKeys > 0 && /* @__PURE__ */ jsxs("div", { className: "i18n__stats-card-missing", children: [
|
|
115
|
+
s.missingKeys,
|
|
116
|
+
" missing"
|
|
117
|
+
] })
|
|
118
|
+
] }, s.locale);
|
|
119
|
+
}) });
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
I18nProvider,
|
|
123
|
+
LocaleStatsCard,
|
|
124
|
+
LocaleSwitcher,
|
|
125
|
+
MissingKeyAlert,
|
|
126
|
+
RTLWrapper,
|
|
127
|
+
TranslationEditor,
|
|
128
|
+
TranslationTable,
|
|
129
|
+
useI18n,
|
|
130
|
+
useI18nAdmin,
|
|
131
|
+
useLocaleDetect,
|
|
132
|
+
useTranslations
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/index.ts","../src/components/index.tsx"],"sourcesContent":["export { I18nProvider, useI18n } from '@geenius/i18n-react'\nexport { useLocaleDetect } from '@geenius/i18n-react'\nexport { useTranslations } from '@geenius/i18n-react'\nexport { useI18nAdmin } from '@geenius/i18n-react'\n","import React, { useState } from 'react'\nimport type { Locale, TranslationEntry, LocaleStat, MissingKey } from '@geenius/i18n-shared'\nimport { LOCALE_INFO, ALL_LOCALES } from '@geenius/i18n-shared'\n\nexport function LocaleSwitcher({ locales, current, onChange }: { locales: Locale[]; current: Locale; onChange: (l: Locale) => void }) {\n const [open, setOpen] = useState(false)\n const info = LOCALE_INFO[current]\n return (\n <div className=\"i18n__locale-switcher\">\n <button type=\"button\" className=\"i18n__locale-switcher-btn\" onClick={() => setOpen(!open)}>\n <span className=\"i18n__locale-switcher-flag\">{info?.flag}</span><span>{info?.nativeName}</span><span className=\"i18n__locale-switcher-arrow\">▼</span>\n </button>\n {open && <div className=\"i18n__locale-dropdown\">{locales.map(l => { const li = LOCALE_INFO[l]; return (\n <button key={l} type=\"button\" onClick={() => { onChange(l); setOpen(false) }} className={`i18n__locale-option ${current === l ? 'i18n__locale-option--active' : ''}`}>\n <span className=\"i18n__locale-option-flag\">{li?.flag}</span><span className=\"i18n__locale-option-name\">{li?.nativeName}</span><span className=\"i18n__locale-option-eng\">{li?.name}</span>\n {li?.direction === 'rtl' && <span className=\"i18n__locale-option-rtl\">RTL</span>}\n </button>\n )})}</div>}\n </div>\n )\n}\n\nexport function RTLWrapper({ children, locale }: { children: React.ReactNode; locale?: Locale }) {\n const dir = locale ? LOCALE_INFO[locale]?.direction ?? 'ltr' : 'ltr'\n return <div className=\"i18n__rtl-wrapper\" dir={dir}>{children}</div>\n}\n\nexport function TranslationEditor({ onSave, initialLocale, namespaces }: { onSave: (l: string, ns: string, k: string, v: string) => void; initialLocale?: Locale; namespaces?: string[] }) {\n const [locale, setLocale] = useState<string>(initialLocale ?? 'en'); const [ns, setNs] = useState(namespaces?.[0] ?? 'common')\n const [key, setKey] = useState(''); const [value, setValue] = useState('')\n return (\n <div className=\"i18n__editor\">\n <div className=\"i18n__editor-selectors\">\n <select value={locale} onChange={e => setLocale(e.target.value)} className=\"i18n__editor-select\">{Object.entries(LOCALE_INFO).map(([c, i]) => <option key={c} value={c}>{i.flag} {i.name}</option>)}</select>\n <select value={ns} onChange={e => setNs(e.target.value)} className=\"i18n__editor-select\">{(namespaces ?? ['common','auth','dashboard','billing','errors']).map(n => <option key={n} value={n}>{n}</option>)}</select>\n </div>\n <input type=\"text\" className=\"i18n__editor-input\" placeholder=\"Translation key…\" value={key} onChange={e => setKey(e.target.value)} />\n <textarea className=\"i18n__editor-input i18n__editor-textarea\" placeholder=\"Translation value…\" value={value} onChange={e => setValue(e.target.value)} />\n <button type=\"button\" className=\"i18n__btn i18n__btn--primary\" disabled={!key || !value} onClick={() => { onSave(locale, ns, key, value); setKey(''); setValue('') }}>Save Translation</button>\n </div>\n )\n}\n\nexport function TranslationTable({ translations, locale, onDelete }: { translations: TranslationEntry[]; locale: Locale; onDelete?: (key: string) => void }) {\n if (translations.length === 0) return <div className=\"i18n__empty\"><div className=\"i18n__empty-icon\">🌐</div><div className=\"i18n__empty-text\">No translations for this locale</div></div>\n return (\n <div style={{ overflowX: 'auto', borderRadius: 'var(--i18n-radius)', border: '1px solid var(--i18n-border)' }}>\n <table className=\"i18n__translation-table\"><thead><tr><th>Key</th><th>Value</th><th>NS</th><th style={{ textAlign: 'right' }}>Actions</th></tr></thead>\n <tbody>{translations.map(t => <tr key={t.id} className=\"i18n__translation-row\"><td className=\"i18n__translation-key\">{t.key}</td><td className=\"i18n__translation-value\">{t.value}</td><td><span className=\"i18n__translation-ns\">{t.namespace}</span></td><td style={{ textAlign: 'right' }}>{onDelete && <button type=\"button\" className=\"i18n__delete-btn\" onClick={() => onDelete(t.key)}>Delete</button>}</td></tr>)}</tbody></table>\n </div>\n )\n}\n\nexport function MissingKeyAlert({ count, locale }: { count: number; locale: Locale }) {\n if (count === 0) return null\n return <div className=\"i18n__missing-badge\"><span className=\"i18n__missing-badge-icon\">⚠️</span><span className=\"i18n__missing-badge-text\">{count} missing key{count > 1 ? 's' : ''} for <strong>{LOCALE_INFO[locale]?.name}</strong></span></div>\n}\n\nexport function LocaleStatsCard({ stats }: { stats: LocaleStat[] }) {\n return (\n <div className=\"i18n__stats-grid\">{stats.map(s => {\n const info = LOCALE_INFO[s.locale]; const barClass = s.coverage >= 90 ? 'i18n__stats-bar-fill--complete' : s.coverage >= 70 ? 'i18n__stats-bar-fill--partial' : 'i18n__stats-bar-fill--low'\n return <div key={s.locale} className=\"i18n__stats-card\"><div className=\"i18n__stats-card-header\"><span className=\"i18n__stats-card-flag\">{info?.flag}</span><span className=\"i18n__stats-card-name\">{info?.nativeName}</span></div><div className=\"i18n__stats-card-meta\"><span>{s.totalKeys} keys</span><span style={{ fontWeight: 700 }}>{s.coverage}%</span></div><div className=\"i18n__stats-bar\"><div className={`i18n__stats-bar-fill ${barClass}`} style={{ width: `${s.coverage}%` }} /></div>{s.missingKeys > 0 && <div className=\"i18n__stats-card-missing\">{s.missingKeys} missing</div>}</div>\n })}</div>\n )\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# ✦ @geenius-
|
|
1
|
+
# ✦ @geenius/i18n-shared\n\n> Geenius i18n — Shared types & Convex schema\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius/i18n-shared\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius/i18n-shared';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|