@emdash-cms/admin 0.20.0 → 0.21.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/dist/{LocaleDirectionProvider-D701o676.js → LocaleDirectionProvider-2r3ddASD.js} +20 -20
- package/dist/{LocaleDirectionProvider-D701o676.js.map → LocaleDirectionProvider-2r3ddASD.js.map} +1 -1
- package/dist/index.js +46 -11
- package/dist/index.js.map +1 -1
- package/dist/locales/ar/messages.mjs +1 -1
- package/dist/locales/de/messages.mjs +1 -1
- package/dist/locales/en/messages.mjs +1 -1
- package/dist/locales/en-GB/messages.mjs +1 -1
- package/dist/locales/es-419/messages.mjs +1 -1
- package/dist/locales/es-ES/messages.mjs +1 -1
- package/dist/locales/eu/messages.mjs +1 -1
- package/dist/locales/fa/messages.mjs +1 -1
- package/dist/locales/fr/messages.mjs +1 -1
- package/dist/locales/id/messages.mjs +1 -1
- package/dist/locales/index.js +1 -1
- package/dist/locales/ja/messages.mjs +1 -1
- package/dist/locales/ko/messages.mjs +1 -1
- package/dist/locales/nb/messages.mjs +1 -1
- package/dist/locales/pl/messages.mjs +1 -1
- package/dist/locales/pseudo/messages.mjs +1 -1
- package/dist/locales/pt-BR/messages.mjs +1 -1
- package/dist/locales/th/messages.mjs +1 -1
- package/dist/locales/zh-CN/messages.mjs +1 -1
- package/dist/locales/zh-TW/messages.mjs +1 -1
- package/dist/messages-4RfOgpRe.js +6 -0
- package/dist/messages-4RfOgpRe.js.map +1 -0
- package/dist/messages-B2dislAg.js +6 -0
- package/dist/messages-B2dislAg.js.map +1 -0
- package/dist/messages-BCwJZnj9.js +6 -0
- package/dist/messages-BCwJZnj9.js.map +1 -0
- package/dist/messages-BKIhPAtr.js +6 -0
- package/dist/messages-BKIhPAtr.js.map +1 -0
- package/dist/messages-BQK7rTdD.js +6 -0
- package/dist/messages-BQK7rTdD.js.map +1 -0
- package/dist/messages-Bi-nkgXF.js +6 -0
- package/dist/messages-Bi-nkgXF.js.map +1 -0
- package/dist/messages-BijE6qyL.js +6 -0
- package/dist/messages-BijE6qyL.js.map +1 -0
- package/dist/messages-CUr8te5R.js +6 -0
- package/dist/messages-CUr8te5R.js.map +1 -0
- package/dist/messages-CsCXsIkt.js +6 -0
- package/dist/messages-CsCXsIkt.js.map +1 -0
- package/dist/messages-CvdFDy7W.js +6 -0
- package/dist/messages-CvdFDy7W.js.map +1 -0
- package/dist/messages-D3Za28AJ.js +6 -0
- package/dist/messages-D3Za28AJ.js.map +1 -0
- package/dist/messages-D4fTrIpF.js +6 -0
- package/dist/messages-D4fTrIpF.js.map +1 -0
- package/dist/messages-DPKhsdix.js +6 -0
- package/dist/messages-DPKhsdix.js.map +1 -0
- package/dist/messages-DU6VHdml.js +6 -0
- package/dist/messages-DU6VHdml.js.map +1 -0
- package/dist/messages-DVps7CyU.js +6 -0
- package/dist/messages-DVps7CyU.js.map +1 -0
- package/dist/messages-DcYO8AdT.js +6 -0
- package/dist/messages-DcYO8AdT.js.map +1 -0
- package/dist/messages-HYNWLJvO.js +6 -0
- package/dist/messages-HYNWLJvO.js.map +1 -0
- package/dist/messages-HwYE7sN5.js +6 -0
- package/dist/messages-HwYE7sN5.js.map +1 -0
- package/dist/messages-n9rSmjwa.js +6 -0
- package/dist/messages-n9rSmjwa.js.map +1 -0
- package/dist/styles.css +2 -2
- package/package.json +3 -3
- package/dist/messages-BCdr0vs6.js +0 -6
- package/dist/messages-BCdr0vs6.js.map +0 -1
- package/dist/messages-BEba-i5h.js +0 -6
- package/dist/messages-BEba-i5h.js.map +0 -1
- package/dist/messages-BOJU79wz.js +0 -6
- package/dist/messages-BOJU79wz.js.map +0 -1
- package/dist/messages-B_776u_s.js +0 -6
- package/dist/messages-B_776u_s.js.map +0 -1
- package/dist/messages-BuTB8H87.js +0 -6
- package/dist/messages-BuTB8H87.js.map +0 -1
- package/dist/messages-BxxGIhf4.js +0 -6
- package/dist/messages-BxxGIhf4.js.map +0 -1
- package/dist/messages-CBkzQcd-.js +0 -6
- package/dist/messages-CBkzQcd-.js.map +0 -1
- package/dist/messages-CNCPtLaI.js +0 -6
- package/dist/messages-CNCPtLaI.js.map +0 -1
- package/dist/messages-CY65b3kz.js +0 -6
- package/dist/messages-CY65b3kz.js.map +0 -1
- package/dist/messages-CvaPem7G.js +0 -6
- package/dist/messages-CvaPem7G.js.map +0 -1
- package/dist/messages-DHo2mVqL.js +0 -6
- package/dist/messages-DHo2mVqL.js.map +0 -1
- package/dist/messages-DHqYoT8m.js +0 -6
- package/dist/messages-DHqYoT8m.js.map +0 -1
- package/dist/messages-DUYqNIID.js +0 -6
- package/dist/messages-DUYqNIID.js.map +0 -1
- package/dist/messages-DflNUNOT.js +0 -6
- package/dist/messages-DflNUNOT.js.map +0 -1
- package/dist/messages-DfrYsR2M.js +0 -6
- package/dist/messages-DfrYsR2M.js.map +0 -1
- package/dist/messages-DiOQ8Er0.js +0 -6
- package/dist/messages-DiOQ8Er0.js.map +0 -1
- package/dist/messages-MtFRSNif.js +0 -6
- package/dist/messages-MtFRSNif.js.map +0 -1
- package/dist/messages-TCMOQPXZ.js +0 -6
- package/dist/messages-TCMOQPXZ.js.map +0 -1
- package/dist/messages-Z5LBofRQ.js +0 -6
- package/dist/messages-Z5LBofRQ.js.map +0 -1
|
@@ -208,25 +208,25 @@ function resolveLocale(request) {
|
|
|
208
208
|
//#endregion
|
|
209
209
|
//#region src/locales/loadMessages.ts
|
|
210
210
|
const LOCALE_LOADERS = /* @__PURE__ */ Object.assign({
|
|
211
|
-
"./ar/messages.mjs": () => import("./messages-
|
|
212
|
-
"./de/messages.mjs": () => import("./messages-
|
|
213
|
-
"./en/messages.mjs": () => import("./messages-
|
|
214
|
-
"./en-GB/messages.mjs": () => import("./messages-
|
|
215
|
-
"./es-419/messages.mjs": () => import("./messages-
|
|
216
|
-
"./es-ES/messages.mjs": () => import("./messages-
|
|
217
|
-
"./eu/messages.mjs": () => import("./messages-
|
|
218
|
-
"./fa/messages.mjs": () => import("./messages-
|
|
219
|
-
"./fr/messages.mjs": () => import("./messages-
|
|
220
|
-
"./id/messages.mjs": () => import("./messages-
|
|
221
|
-
"./ja/messages.mjs": () => import("./messages-
|
|
222
|
-
"./ko/messages.mjs": () => import("./messages-
|
|
223
|
-
"./nb/messages.mjs": () => import("./messages-
|
|
224
|
-
"./pl/messages.mjs": () => import("./messages-
|
|
225
|
-
"./pseudo/messages.mjs": () => import("./messages-
|
|
226
|
-
"./pt-BR/messages.mjs": () => import("./messages-
|
|
227
|
-
"./th/messages.mjs": () => import("./messages-
|
|
228
|
-
"./zh-CN/messages.mjs": () => import("./messages-
|
|
229
|
-
"./zh-TW/messages.mjs": () => import("./messages-
|
|
211
|
+
"./ar/messages.mjs": () => import("./messages-BCwJZnj9.js"),
|
|
212
|
+
"./de/messages.mjs": () => import("./messages-Bi-nkgXF.js"),
|
|
213
|
+
"./en/messages.mjs": () => import("./messages-D4fTrIpF.js"),
|
|
214
|
+
"./en-GB/messages.mjs": () => import("./messages-DVps7CyU.js"),
|
|
215
|
+
"./es-419/messages.mjs": () => import("./messages-BijE6qyL.js"),
|
|
216
|
+
"./es-ES/messages.mjs": () => import("./messages-n9rSmjwa.js"),
|
|
217
|
+
"./eu/messages.mjs": () => import("./messages-BKIhPAtr.js"),
|
|
218
|
+
"./fa/messages.mjs": () => import("./messages-CUr8te5R.js"),
|
|
219
|
+
"./fr/messages.mjs": () => import("./messages-CvdFDy7W.js"),
|
|
220
|
+
"./id/messages.mjs": () => import("./messages-DcYO8AdT.js"),
|
|
221
|
+
"./ja/messages.mjs": () => import("./messages-HYNWLJvO.js"),
|
|
222
|
+
"./ko/messages.mjs": () => import("./messages-DPKhsdix.js"),
|
|
223
|
+
"./nb/messages.mjs": () => import("./messages-D3Za28AJ.js"),
|
|
224
|
+
"./pl/messages.mjs": () => import("./messages-HwYE7sN5.js"),
|
|
225
|
+
"./pseudo/messages.mjs": () => import("./messages-B2dislAg.js"),
|
|
226
|
+
"./pt-BR/messages.mjs": () => import("./messages-4RfOgpRe.js"),
|
|
227
|
+
"./th/messages.mjs": () => import("./messages-DU6VHdml.js"),
|
|
228
|
+
"./zh-CN/messages.mjs": () => import("./messages-BQK7rTdD.js"),
|
|
229
|
+
"./zh-TW/messages.mjs": () => import("./messages-CsCXsIkt.js")
|
|
230
230
|
});
|
|
231
231
|
async function loadMessages(locale) {
|
|
232
232
|
const key = `./${locale}/messages.mjs`;
|
|
@@ -293,4 +293,4 @@ function LocaleDirectionProvider({ children }) {
|
|
|
293
293
|
|
|
294
294
|
//#endregion
|
|
295
295
|
export { SUPPORTED_LOCALES as a, getLocaleLabel as c, DEFAULT_LOCALE as i, resolveLocale as l, useLocale as n, SUPPORTED_LOCALE_CODES as o, loadMessages as r, getLocaleDir as s, LocaleDirectionProvider as t };
|
|
296
|
-
//# sourceMappingURL=LocaleDirectionProvider-
|
|
296
|
+
//# sourceMappingURL=LocaleDirectionProvider-2r3ddASD.js.map
|
package/dist/{LocaleDirectionProvider-D701o676.js.map → LocaleDirectionProvider-2r3ddASD.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocaleDirectionProvider-D701o676.js","names":["React"],"sources":["../src/locales/locales.ts","../src/locales/config.ts","../src/locales/loadMessages.ts","../src/locales/useLocale.ts","../src/locales/LocaleDirectionProvider.tsx"],"sourcesContent":["/**\n * Canonical locale definitions -- the single source of truth.\n *\n * This file is intentionally free of Vite/Astro APIs (`import.meta.env` etc.)\n * so it can be imported from CLI tools (Lingui, Lunaria) running in plain Node.\n *\n * To add a new locale:\n * 1. Add an entry here (with `enabled: false`).\n * 2. Run `pnpm locale:extract` to generate the PO file.\n * 3. Translate the strings in the PO file.\n * 4. Set `enabled: true` once coverage is sufficient.\n *\n * Lingui and Lunaria use all locales (for extraction and tracking).\n * The admin runtime only exposes locales with `enabled: true`.\n */\n\nexport interface LocaleDefinition {\n\t/** BCP 47 locale code (e.g. \"en\", \"pt-BR\"). */\n\tcode: string;\n\t/** Human-readable label in the locale's own language. */\n\tlabel: string;\n\t/** Whether this locale is selectable in the admin UI. */\n\tenabled: boolean;\n\t/** Text direction for this locale. Defaults to \"ltr\" if not specified. */\n\tdir?: \"rtl\" | \"ltr\";\n}\n\n/**\n * All locales that have (or should have) a PO catalog.\n * First entry is the source/default locale.\n */\nexport const LOCALES: LocaleDefinition[] = [\n\t// Source locale first, then alphabetical by English name.\n\t{ code: \"en\", label: \"English\", enabled: true },\n\t{ code: \"ar\", label: \"العربية\", enabled: true, dir: \"rtl\" }, // Arabic\n\t{ code: \"eu\", label: \"Euskara\", enabled: true }, // Basque\n\t{ code: \"zh-CN\", label: \"简体中文\", enabled: true }, // Chinese (Simplified)\n\t{ code: \"zh-TW\", label: \"繁體中文\", enabled: true }, // Chinese (Traditional)\n\t{ code: \"en-GB\", label: \"English (UK)\", enabled: true }, // English (United Kingdom)\n\t{ code: \"fa\", label: \"فارسی\", enabled: true, dir: \"rtl\" }, // Farsi (also known as Persian)\n\t{ code: \"fr\", label: \"Français\", enabled: true }, // French\n\t{ code: \"de\", label: \"Deutsch\", enabled: true }, // German\n\t{ code: \"id\", label: \"Bahasa Indonesia\", enabled: true }, // Indonesian\n\t{ code: \"ja\", label: \"日本語\", enabled: true }, // Japanese\n\t{ code: \"ko\", label: \"한국어\", enabled: false }, // Korean\n\t{ code: \"nb\", label: \"Norsk bokmål\", enabled: true }, // Norwegian Bokmål\n\t{ code: \"pl\", label: \"Polski\", enabled: true }, // Polish\n\t{ code: \"pt-BR\", label: \"Português (Brasil)\", enabled: true }, // Portuguese (Brazil)\n\t{ code: \"es-419\", label: \"Español (Latinoamérica)\", enabled: true }, // Spanish (Latin America)\n\t{ code: \"es-ES\", label: \"Español (España)\", enabled: true }, // Spanish (Spain) - BCP 47\n\t{ code: \"th\", label: \"ไทย\", enabled: true }, // Thai\n\t// Pseudo-locale for i18n testing - never enabled in the admin UI by default.\n\t// Set EMDASH_PSEUDO_LOCALE=1 in .env to expose it in the locale switcher (dev only).\n\t{ code: \"pseudo\", label: \"Pseudo\", enabled: false },\n];\n\n/** The source locale (first entry). */\nexport const SOURCE_LOCALE = LOCALES[0]!;\n\n/** All locale codes (for Lingui extraction / Lunaria tracking). */\nexport const LOCALE_CODES = LOCALES.map((l) => l.code);\n\n/** Target locales -- everything except the source (for Lunaria). */\nexport const TARGET_LOCALES = LOCALES.slice(1);\n\n/** Locales enabled in the admin UI. */\nexport const ENABLED_LOCALES = LOCALES.filter((l) => l.enabled);\n","/**\n * Locale configuration for the admin UI runtime.\n *\n * Locale definitions are in `./locales.ts` -- the single source of truth\n * shared by this file, lingui.config.ts and lunaria.config.ts.\n */\n\nimport { ENABLED_LOCALES, LOCALES, SOURCE_LOCALE } from \"./locales.js\";\n\nexport type { LocaleDefinition as SupportedLocale } from \"./locales.js\";\n\nfunction isValidLocale(code: string): boolean {\n\ttry {\n\t\tconst locale = new Intl.Locale(code);\n\t\treturn locale.baseName !== \"\";\n\t} catch {\n\t\tif (import.meta.env.DEV) {\n\t\t\tthrow new Error(`Invalid locale code: \"${code}\"`);\n\t\t}\n\t\treturn false;\n\t}\n}\n\n// Injected by the EmDash Vite integration from process.env.EMDASH_PSEUDO_LOCALE.\n// Only true in dev when EMDASH_PSEUDO_LOCALE=1 is set.\ndeclare const __EMDASH_PSEUDO_LOCALE__: boolean;\n\n/**\n * The pseudo locale, injected into the supported list only when\n * EMDASH_PSEUDO_LOCALE=1 is set. Never available in production.\n */\nconst PSEUDO_LOCALE =\n\ttypeof __EMDASH_PSEUDO_LOCALE__ !== \"undefined\" && __EMDASH_PSEUDO_LOCALE__\n\t\t? LOCALES.find((l) => l.code === \"pseudo\")\n\t\t: undefined;\n\n/** Available locales at runtime, validated against BCP 47. */\nexport const SUPPORTED_LOCALES = [\n\t...ENABLED_LOCALES.filter((l) => isValidLocale(l.code)),\n\t...(PSEUDO_LOCALE ? [PSEUDO_LOCALE] : []),\n];\n\nexport const SUPPORTED_LOCALE_CODES = new Set(SUPPORTED_LOCALES.map((l) => l.code));\n\nexport const DEFAULT_LOCALE = SOURCE_LOCALE.code;\n\n/** Maps base language codes to supported locales (e.g. \"pt\" -> \"pt-BR\"). */\nconst BASE_LANGUAGE_MAP = new Map<string, string>();\n/** Maps script codes to supported locales (e.g. \"zh-Hant\" -> \"zh-TW\", \"zh-Hans\" -> \"zh-CN\"). */\nconst SCRIPT_LANGUAGE_MAP = new Map<string, string>();\n\nfor (const l of SUPPORTED_LOCALES) {\n\tconst base = l.code.split(\"-\")[0]!.toLowerCase();\n\t// First match wins -- if we have both \"pt\" and \"pt-BR\", exact wins via direct lookup.\n\tif (!BASE_LANGUAGE_MAP.has(base)) {\n\t\tBASE_LANGUAGE_MAP.set(base, l.code);\n\t}\n\n\tconst maximized = new Intl.Locale(l.code).maximize();\n\tif (maximized.script) {\n\t\tconst scriptKey = `${maximized.language}-${maximized.script}`.toLowerCase();\n\t\tif (!SCRIPT_LANGUAGE_MAP.has(scriptKey)) {\n\t\t\tSCRIPT_LANGUAGE_MAP.set(scriptKey, l.code);\n\t\t}\n\t}\n}\n\n/**\n * Find the best matching supported locale for a BCP 47 tag.\n * Canonicalizes via Intl.Locale so case differences (e.g. \"pt-br\" vs \"pt-BR\")\n * don't prevent matching. Supports script codes (zh-Hant -> zh-TW, zh-Hans -> zh-CN)\n * and falls back to base language (pt-PT -> pt-BR).\n */\nfunction matchLocale(tag: string): string | undefined {\n\tconst trimmed = tag.trim();\n\tif (!trimmed) return undefined;\n\tlet canonical: string;\n\ttry {\n\t\tcanonical = new Intl.Locale(trimmed).baseName;\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\t// Exact match (case-insensitive via Intl.Locale)\n\tif (SUPPORTED_LOCALE_CODES.has(canonical)) return canonical;\n\n\t// Try script-based matching (zh-Hant -> zh-TW, zh-Hans -> zh-CN)\n\tconst locale = new Intl.Locale(trimmed);\n\tif (locale.script) {\n\t\tconst scriptKey = `${locale.language}-${locale.script}`.toLowerCase();\n\t\tconst scriptMatch = SCRIPT_LANGUAGE_MAP.get(scriptKey);\n\t\tif (scriptMatch) return scriptMatch;\n\t}\n\n\t// Fallback to base language (pt-PT -> pt-BR)\n\tconst base = canonical.split(\"-\")[0]!.toLowerCase();\n\treturn BASE_LANGUAGE_MAP.get(base);\n}\n\nconst LOCALE_LABELS = new Map(SUPPORTED_LOCALES.map((l) => [l.code, l.label]));\n\n/** Get a display label for a locale code, falling back to uppercase code. */\nexport function getLocaleLabel(code: string): string {\n\treturn LOCALE_LABELS.get(code) ?? code.toUpperCase();\n}\n\nconst LOCALE_DIRS = new Map(SUPPORTED_LOCALES.map((l) => [l.code, l.dir]));\n\n/** Get the text direction for a locale code. Defaults to \"ltr\" if not specified. */\nexport function getLocaleDir(code: string): \"ltr\" | \"rtl\" {\n\treturn LOCALE_DIRS.get(code) ?? \"ltr\";\n}\n\nconst LOCALE_COOKIE_RE = /(?:^|;\\s*)emdash-locale=([^;]+)/;\n\n/**\n * Resolve the admin locale from a Request.\n * Priority: emdash-locale cookie -> Accept-Language -> DEFAULT_LOCALE.\n */\nexport function resolveLocale(request: Request): string {\n\tconst cookieHeader = request.headers.get(\"cookie\") ?? \"\";\n\tconst cookieMatch = cookieHeader.match(LOCALE_COOKIE_RE);\n\tconst cookieLocale = cookieMatch?.[1]?.trim() ?? \"\";\n\n\tif (SUPPORTED_LOCALE_CODES.has(cookieLocale)) return cookieLocale;\n\n\tconst acceptLang = request.headers.get(\"accept-language\") ?? \"\";\n\tfor (const entry of acceptLang.split(\",\")) {\n\t\tconst tag = entry.split(\";\")[0]!.trim();\n\t\tconst matched = matchLocale(tag);\n\t\tif (matched) return matched;\n\t}\n\n\treturn DEFAULT_LOCALE;\n}\n","import type { Messages } from \"@lingui/core\";\n\nimport { DEFAULT_LOCALE } from \"./config.js\";\n\nconst LOCALE_LOADERS = import.meta.glob<{ messages: Messages }>(\"./**/messages.mjs\");\n\nexport async function loadMessages(locale: string): Promise<Messages> {\n\tconst key = `./${locale}/messages.mjs`;\n\tconst fallbackKey = `./${DEFAULT_LOCALE}/messages.mjs`;\n\tconst loader = LOCALE_LOADERS[key] ?? LOCALE_LOADERS[fallbackKey];\n\tif (!loader) {\n\t\tthrow new Error(\n\t\t\t`No locale catalog found for \"${locale}\" or \"${DEFAULT_LOCALE}\". Run \\`pnpm locale:compile\\` to generate catalogs.`,\n\t\t);\n\t}\n\tconst { messages } = await loader();\n\treturn messages;\n}\n","import { useLingui } from \"@lingui/react\";\nimport * as React from \"react\";\n\nimport { SUPPORTED_LOCALE_CODES } from \"./config.js\";\nimport { loadMessages } from \"./loadMessages.js\";\n\nfunction setCookie(code: string) {\n\tconst secure = window.location.protocol === \"https:\" ? \"; Secure\" : \"\";\n\tdocument.cookie = `emdash-locale=${code}; Path=/_emdash; SameSite=Lax; Max-Age=31536000${secure}`;\n}\n\n/**\n * Get the current locale and a function to switch locales.\n * Loads the new catalog dynamically and sets a cookie for server-side persistence.\n */\nexport function useLocale() {\n\tconst { i18n } = useLingui();\n\tconst [locale, setLocaleState] = React.useState(i18n.locale);\n\n\tconst setLocale = React.useCallback(\n\t\t(code: string) => {\n\t\t\tif (code === i18n.locale || !SUPPORTED_LOCALE_CODES.has(code)) return;\n\t\t\tsetCookie(code);\n\t\t\tvoid loadMessages(code)\n\t\t\t\t.then((messages) => i18n.loadAndActivate({ locale: code, messages }))\n\t\t\t\t.catch(() => {\n\t\t\t\t\tsetCookie(i18n.locale);\n\t\t\t\t});\n\t\t},\n\t\t[i18n],\n\t);\n\n\t// Subscribe to i18n change events to trigger re-renders\n\tReact.useEffect(() => {\n\t\tconst unsubscribe = i18n.on(\"change\", () => {\n\t\t\tsetLocaleState(i18n.locale);\n\t\t});\n\t\treturn unsubscribe;\n\t}, [i18n]);\n\n\treturn { locale, setLocale };\n}\n","import { DirectionProvider } from \"@cloudflare/kumo/primitives\";\nimport * as React from \"react\";\n\nimport { getLocaleDir } from \"./config.js\";\nimport { useLocale } from \"./useLocale.js\";\n\ninterface LocaleDirectionProviderProps {\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps the app with DirectionProvider and keeps it in sync with the current locale.\n * Automatically updates direction when locale changes via useLocale.\n */\nexport function LocaleDirectionProvider({ children }: LocaleDirectionProviderProps) {\n\tconst { locale } = useLocale();\n\tconst dir = React.useMemo(() => getLocaleDir(locale), [locale]);\n\n\t/** Sync the direction and lang attributes with the current locale. */\n\tReact.useEffect(() => {\n\t\tdocument.documentElement.setAttribute(\"lang\", locale);\n\t\tdocument.documentElement.setAttribute(\"dir\", dir);\n\t}, [dir, locale]);\n\n\treturn <DirectionProvider direction={dir}>{children}</DirectionProvider>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LocaleDirectionProvider-2r3ddASD.js","names":["React"],"sources":["../src/locales/locales.ts","../src/locales/config.ts","../src/locales/loadMessages.ts","../src/locales/useLocale.ts","../src/locales/LocaleDirectionProvider.tsx"],"sourcesContent":["/**\n * Canonical locale definitions -- the single source of truth.\n *\n * This file is intentionally free of Vite/Astro APIs (`import.meta.env` etc.)\n * so it can be imported from CLI tools (Lingui, Lunaria) running in plain Node.\n *\n * To add a new locale:\n * 1. Add an entry here (with `enabled: false`).\n * 2. Run `pnpm locale:extract` to generate the PO file.\n * 3. Translate the strings in the PO file.\n * 4. Set `enabled: true` once coverage is sufficient.\n *\n * Lingui and Lunaria use all locales (for extraction and tracking).\n * The admin runtime only exposes locales with `enabled: true`.\n */\n\nexport interface LocaleDefinition {\n\t/** BCP 47 locale code (e.g. \"en\", \"pt-BR\"). */\n\tcode: string;\n\t/** Human-readable label in the locale's own language. */\n\tlabel: string;\n\t/** Whether this locale is selectable in the admin UI. */\n\tenabled: boolean;\n\t/** Text direction for this locale. Defaults to \"ltr\" if not specified. */\n\tdir?: \"rtl\" | \"ltr\";\n}\n\n/**\n * All locales that have (or should have) a PO catalog.\n * First entry is the source/default locale.\n */\nexport const LOCALES: LocaleDefinition[] = [\n\t// Source locale first, then alphabetical by English name.\n\t{ code: \"en\", label: \"English\", enabled: true },\n\t{ code: \"ar\", label: \"العربية\", enabled: true, dir: \"rtl\" }, // Arabic\n\t{ code: \"eu\", label: \"Euskara\", enabled: true }, // Basque\n\t{ code: \"zh-CN\", label: \"简体中文\", enabled: true }, // Chinese (Simplified)\n\t{ code: \"zh-TW\", label: \"繁體中文\", enabled: true }, // Chinese (Traditional)\n\t{ code: \"en-GB\", label: \"English (UK)\", enabled: true }, // English (United Kingdom)\n\t{ code: \"fa\", label: \"فارسی\", enabled: true, dir: \"rtl\" }, // Farsi (also known as Persian)\n\t{ code: \"fr\", label: \"Français\", enabled: true }, // French\n\t{ code: \"de\", label: \"Deutsch\", enabled: true }, // German\n\t{ code: \"id\", label: \"Bahasa Indonesia\", enabled: true }, // Indonesian\n\t{ code: \"ja\", label: \"日本語\", enabled: true }, // Japanese\n\t{ code: \"ko\", label: \"한국어\", enabled: false }, // Korean\n\t{ code: \"nb\", label: \"Norsk bokmål\", enabled: true }, // Norwegian Bokmål\n\t{ code: \"pl\", label: \"Polski\", enabled: true }, // Polish\n\t{ code: \"pt-BR\", label: \"Português (Brasil)\", enabled: true }, // Portuguese (Brazil)\n\t{ code: \"es-419\", label: \"Español (Latinoamérica)\", enabled: true }, // Spanish (Latin America)\n\t{ code: \"es-ES\", label: \"Español (España)\", enabled: true }, // Spanish (Spain) - BCP 47\n\t{ code: \"th\", label: \"ไทย\", enabled: true }, // Thai\n\t// Pseudo-locale for i18n testing - never enabled in the admin UI by default.\n\t// Set EMDASH_PSEUDO_LOCALE=1 in .env to expose it in the locale switcher (dev only).\n\t{ code: \"pseudo\", label: \"Pseudo\", enabled: false },\n];\n\n/** The source locale (first entry). */\nexport const SOURCE_LOCALE = LOCALES[0]!;\n\n/** All locale codes (for Lingui extraction / Lunaria tracking). */\nexport const LOCALE_CODES = LOCALES.map((l) => l.code);\n\n/** Target locales -- everything except the source (for Lunaria). */\nexport const TARGET_LOCALES = LOCALES.slice(1);\n\n/** Locales enabled in the admin UI. */\nexport const ENABLED_LOCALES = LOCALES.filter((l) => l.enabled);\n","/**\n * Locale configuration for the admin UI runtime.\n *\n * Locale definitions are in `./locales.ts` -- the single source of truth\n * shared by this file, lingui.config.ts and lunaria.config.ts.\n */\n\nimport { ENABLED_LOCALES, LOCALES, SOURCE_LOCALE } from \"./locales.js\";\n\nexport type { LocaleDefinition as SupportedLocale } from \"./locales.js\";\n\nfunction isValidLocale(code: string): boolean {\n\ttry {\n\t\tconst locale = new Intl.Locale(code);\n\t\treturn locale.baseName !== \"\";\n\t} catch {\n\t\tif (import.meta.env.DEV) {\n\t\t\tthrow new Error(`Invalid locale code: \"${code}\"`);\n\t\t}\n\t\treturn false;\n\t}\n}\n\n// Injected by the EmDash Vite integration from process.env.EMDASH_PSEUDO_LOCALE.\n// Only true in dev when EMDASH_PSEUDO_LOCALE=1 is set.\ndeclare const __EMDASH_PSEUDO_LOCALE__: boolean;\n\n/**\n * The pseudo locale, injected into the supported list only when\n * EMDASH_PSEUDO_LOCALE=1 is set. Never available in production.\n */\nconst PSEUDO_LOCALE =\n\ttypeof __EMDASH_PSEUDO_LOCALE__ !== \"undefined\" && __EMDASH_PSEUDO_LOCALE__\n\t\t? LOCALES.find((l) => l.code === \"pseudo\")\n\t\t: undefined;\n\n/** Available locales at runtime, validated against BCP 47. */\nexport const SUPPORTED_LOCALES = [\n\t...ENABLED_LOCALES.filter((l) => isValidLocale(l.code)),\n\t...(PSEUDO_LOCALE ? [PSEUDO_LOCALE] : []),\n];\n\nexport const SUPPORTED_LOCALE_CODES = new Set(SUPPORTED_LOCALES.map((l) => l.code));\n\nexport const DEFAULT_LOCALE = SOURCE_LOCALE.code;\n\n/** Maps base language codes to supported locales (e.g. \"pt\" -> \"pt-BR\"). */\nconst BASE_LANGUAGE_MAP = new Map<string, string>();\n/** Maps script codes to supported locales (e.g. \"zh-Hant\" -> \"zh-TW\", \"zh-Hans\" -> \"zh-CN\"). */\nconst SCRIPT_LANGUAGE_MAP = new Map<string, string>();\n\nfor (const l of SUPPORTED_LOCALES) {\n\tconst base = l.code.split(\"-\")[0]!.toLowerCase();\n\t// First match wins -- if we have both \"pt\" and \"pt-BR\", exact wins via direct lookup.\n\tif (!BASE_LANGUAGE_MAP.has(base)) {\n\t\tBASE_LANGUAGE_MAP.set(base, l.code);\n\t}\n\n\tconst maximized = new Intl.Locale(l.code).maximize();\n\tif (maximized.script) {\n\t\tconst scriptKey = `${maximized.language}-${maximized.script}`.toLowerCase();\n\t\tif (!SCRIPT_LANGUAGE_MAP.has(scriptKey)) {\n\t\t\tSCRIPT_LANGUAGE_MAP.set(scriptKey, l.code);\n\t\t}\n\t}\n}\n\n/**\n * Find the best matching supported locale for a BCP 47 tag.\n * Canonicalizes via Intl.Locale so case differences (e.g. \"pt-br\" vs \"pt-BR\")\n * don't prevent matching. Supports script codes (zh-Hant -> zh-TW, zh-Hans -> zh-CN)\n * and falls back to base language (pt-PT -> pt-BR).\n */\nfunction matchLocale(tag: string): string | undefined {\n\tconst trimmed = tag.trim();\n\tif (!trimmed) return undefined;\n\tlet canonical: string;\n\ttry {\n\t\tcanonical = new Intl.Locale(trimmed).baseName;\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\t// Exact match (case-insensitive via Intl.Locale)\n\tif (SUPPORTED_LOCALE_CODES.has(canonical)) return canonical;\n\n\t// Try script-based matching (zh-Hant -> zh-TW, zh-Hans -> zh-CN)\n\tconst locale = new Intl.Locale(trimmed);\n\tif (locale.script) {\n\t\tconst scriptKey = `${locale.language}-${locale.script}`.toLowerCase();\n\t\tconst scriptMatch = SCRIPT_LANGUAGE_MAP.get(scriptKey);\n\t\tif (scriptMatch) return scriptMatch;\n\t}\n\n\t// Fallback to base language (pt-PT -> pt-BR)\n\tconst base = canonical.split(\"-\")[0]!.toLowerCase();\n\treturn BASE_LANGUAGE_MAP.get(base);\n}\n\nconst LOCALE_LABELS = new Map(SUPPORTED_LOCALES.map((l) => [l.code, l.label]));\n\n/** Get a display label for a locale code, falling back to uppercase code. */\nexport function getLocaleLabel(code: string): string {\n\treturn LOCALE_LABELS.get(code) ?? code.toUpperCase();\n}\n\nconst LOCALE_DIRS = new Map(SUPPORTED_LOCALES.map((l) => [l.code, l.dir]));\n\n/** Get the text direction for a locale code. Defaults to \"ltr\" if not specified. */\nexport function getLocaleDir(code: string): \"ltr\" | \"rtl\" {\n\treturn LOCALE_DIRS.get(code) ?? \"ltr\";\n}\n\nconst LOCALE_COOKIE_RE = /(?:^|;\\s*)emdash-locale=([^;]+)/;\n\n/**\n * Resolve the admin locale from a Request.\n * Priority: emdash-locale cookie -> Accept-Language -> DEFAULT_LOCALE.\n */\nexport function resolveLocale(request: Request): string {\n\tconst cookieHeader = request.headers.get(\"cookie\") ?? \"\";\n\tconst cookieMatch = cookieHeader.match(LOCALE_COOKIE_RE);\n\tconst cookieLocale = cookieMatch?.[1]?.trim() ?? \"\";\n\n\tif (SUPPORTED_LOCALE_CODES.has(cookieLocale)) return cookieLocale;\n\n\tconst acceptLang = request.headers.get(\"accept-language\") ?? \"\";\n\tfor (const entry of acceptLang.split(\",\")) {\n\t\tconst tag = entry.split(\";\")[0]!.trim();\n\t\tconst matched = matchLocale(tag);\n\t\tif (matched) return matched;\n\t}\n\n\treturn DEFAULT_LOCALE;\n}\n","import type { Messages } from \"@lingui/core\";\n\nimport { DEFAULT_LOCALE } from \"./config.js\";\n\nconst LOCALE_LOADERS = import.meta.glob<{ messages: Messages }>(\"./**/messages.mjs\");\n\nexport async function loadMessages(locale: string): Promise<Messages> {\n\tconst key = `./${locale}/messages.mjs`;\n\tconst fallbackKey = `./${DEFAULT_LOCALE}/messages.mjs`;\n\tconst loader = LOCALE_LOADERS[key] ?? LOCALE_LOADERS[fallbackKey];\n\tif (!loader) {\n\t\tthrow new Error(\n\t\t\t`No locale catalog found for \"${locale}\" or \"${DEFAULT_LOCALE}\". Run \\`pnpm locale:compile\\` to generate catalogs.`,\n\t\t);\n\t}\n\tconst { messages } = await loader();\n\treturn messages;\n}\n","import { useLingui } from \"@lingui/react\";\nimport * as React from \"react\";\n\nimport { SUPPORTED_LOCALE_CODES } from \"./config.js\";\nimport { loadMessages } from \"./loadMessages.js\";\n\nfunction setCookie(code: string) {\n\tconst secure = window.location.protocol === \"https:\" ? \"; Secure\" : \"\";\n\tdocument.cookie = `emdash-locale=${code}; Path=/_emdash; SameSite=Lax; Max-Age=31536000${secure}`;\n}\n\n/**\n * Get the current locale and a function to switch locales.\n * Loads the new catalog dynamically and sets a cookie for server-side persistence.\n */\nexport function useLocale() {\n\tconst { i18n } = useLingui();\n\tconst [locale, setLocaleState] = React.useState(i18n.locale);\n\n\tconst setLocale = React.useCallback(\n\t\t(code: string) => {\n\t\t\tif (code === i18n.locale || !SUPPORTED_LOCALE_CODES.has(code)) return;\n\t\t\tsetCookie(code);\n\t\t\tvoid loadMessages(code)\n\t\t\t\t.then((messages) => i18n.loadAndActivate({ locale: code, messages }))\n\t\t\t\t.catch(() => {\n\t\t\t\t\tsetCookie(i18n.locale);\n\t\t\t\t});\n\t\t},\n\t\t[i18n],\n\t);\n\n\t// Subscribe to i18n change events to trigger re-renders\n\tReact.useEffect(() => {\n\t\tconst unsubscribe = i18n.on(\"change\", () => {\n\t\t\tsetLocaleState(i18n.locale);\n\t\t});\n\t\treturn unsubscribe;\n\t}, [i18n]);\n\n\treturn { locale, setLocale };\n}\n","import { DirectionProvider } from \"@cloudflare/kumo/primitives\";\nimport * as React from \"react\";\n\nimport { getLocaleDir } from \"./config.js\";\nimport { useLocale } from \"./useLocale.js\";\n\ninterface LocaleDirectionProviderProps {\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps the app with DirectionProvider and keeps it in sync with the current locale.\n * Automatically updates direction when locale changes via useLocale.\n */\nexport function LocaleDirectionProvider({ children }: LocaleDirectionProviderProps) {\n\tconst { locale } = useLocale();\n\tconst dir = React.useMemo(() => getLocaleDir(locale), [locale]);\n\n\t/** Sync the direction and lang attributes with the current locale. */\n\tReact.useEffect(() => {\n\t\tdocument.documentElement.setAttribute(\"lang\", locale);\n\t\tdocument.documentElement.setAttribute(\"dir\", dir);\n\t}, [dir, locale]);\n\n\treturn <DirectionProvider direction={dir}>{children}</DirectionProvider>;\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as fetchAuthMode, d as throwResponseError, i as fetchPlugins, l as fetchManifest, n as enablePlugin, o as API_BASE, r as fetchPlugin, s as apiFetch, t as disablePlugin, u as parseApiResponse } from "./plugins-G9Z9NQ7n.js";
|
|
2
|
-
import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-
|
|
2
|
+
import { a as SUPPORTED_LOCALES, i as DEFAULT_LOCALE, l as resolveLocale, n as useLocale, o as SUPPORTED_LOCALE_CODES, t as LocaleDirectionProvider } from "./LocaleDirectionProvider-2r3ddASD.js";
|
|
3
3
|
import "./locales/index.js";
|
|
4
4
|
import { Autocomplete, Badge, Button, Checkbox, ClipboardText, CommandPalette, Dialog, Input, InputArea, Label, LinkButton, Loader, Popover, Select, Sidebar as KumoSidebar, Switch, Tabs, Toast, Toasty, Tooltip, buttonVariants, useSidebar } from "@cloudflare/kumo";
|
|
5
5
|
import { i18n } from "@lingui/core";
|
|
@@ -23313,6 +23313,7 @@ function RedirectFormDialog({ open, onClose, redirect, defaultSource }) {
|
|
|
23313
23313
|
const [type, setType] = useState(String(redirect?.type ?? 301));
|
|
23314
23314
|
const [enabled, setEnabled] = useState(redirect?.enabled ?? true);
|
|
23315
23315
|
const [groupName, setGroupName] = useState(redirect?.groupName ?? "");
|
|
23316
|
+
const isTerminal = type === "410" || type === "451";
|
|
23316
23317
|
const createMutation = useMutation({
|
|
23317
23318
|
mutationFn: (input) => createRedirect(input),
|
|
23318
23319
|
onSuccess: () => {
|
|
@@ -23332,7 +23333,7 @@ function RedirectFormDialog({ open, onClose, redirect, defaultSource }) {
|
|
|
23332
23333
|
e.preventDefault();
|
|
23333
23334
|
const input = {
|
|
23334
23335
|
source: source.trim(),
|
|
23335
|
-
destination: destination.trim(),
|
|
23336
|
+
destination: isTerminal ? "" : destination.trim(),
|
|
23336
23337
|
type: Number(type),
|
|
23337
23338
|
enabled,
|
|
23338
23339
|
groupName: groupName.trim() || null
|
|
@@ -23400,7 +23401,7 @@ function RedirectFormDialog({ open, onClose, redirect, defaultSource }) {
|
|
|
23400
23401
|
onChange: (e) => setSource(e.target.value),
|
|
23401
23402
|
required: true
|
|
23402
23403
|
}),
|
|
23403
|
-
/* @__PURE__ */ jsx(Input, {
|
|
23404
|
+
!isTerminal && /* @__PURE__ */ jsx(Input, {
|
|
23404
23405
|
label: _t({
|
|
23405
23406
|
id: "+DnHGY",
|
|
23406
23407
|
message: "Destination path"
|
|
@@ -23438,6 +23439,14 @@ function RedirectFormDialog({ open, onClose, redirect, defaultSource }) {
|
|
|
23438
23439
|
"308": _t({
|
|
23439
23440
|
id: "eFDKB6",
|
|
23440
23441
|
message: "308 Permanent (Strict)"
|
|
23442
|
+
}),
|
|
23443
|
+
"410": _t({
|
|
23444
|
+
id: "MvGDaL",
|
|
23445
|
+
message: "410 Content Deleted (Gone)"
|
|
23446
|
+
}),
|
|
23447
|
+
"451": _t({
|
|
23448
|
+
id: "k3JXF8",
|
|
23449
|
+
message: "451 Unavailable for legal reasons"
|
|
23441
23450
|
})
|
|
23442
23451
|
}
|
|
23443
23452
|
}) }), /* @__PURE__ */ jsx(Input, {
|
|
@@ -23501,7 +23510,7 @@ function RedirectFormDialog({ open, onClose, redirect, defaultSource }) {
|
|
|
23501
23510
|
})
|
|
23502
23511
|
});
|
|
23503
23512
|
}
|
|
23504
|
-
function NotFoundPanel({ items, onCreateRedirect }) {
|
|
23513
|
+
function NotFoundPanel({ items, onCreateRedirect, onMarkGone }) {
|
|
23505
23514
|
const { _: _t2 } = useLingui();
|
|
23506
23515
|
if (items.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
23507
23516
|
className: "text-sm text-kumo-subtle py-4 text-center",
|
|
@@ -23536,7 +23545,7 @@ function NotFoundPanel({ items, onCreateRedirect }) {
|
|
|
23536
23545
|
message: "Last seen"
|
|
23537
23546
|
})
|
|
23538
23547
|
}),
|
|
23539
|
-
/* @__PURE__ */ jsx("div", { className: "w-
|
|
23548
|
+
/* @__PURE__ */ jsx("div", { className: "w-20" })
|
|
23540
23549
|
]
|
|
23541
23550
|
}), items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
23542
23551
|
className: "flex items-center gap-4 py-2 px-4 border-b last:border-0 text-sm",
|
|
@@ -23556,9 +23565,9 @@ function NotFoundPanel({ items, onCreateRedirect }) {
|
|
|
23556
23565
|
return Number.isNaN(d.getTime()) ? item.lastSeen : d.toLocaleDateString();
|
|
23557
23566
|
})()
|
|
23558
23567
|
}),
|
|
23559
|
-
/* @__PURE__ */
|
|
23560
|
-
className: "w-
|
|
23561
|
-
children: /* @__PURE__ */ jsx("button", {
|
|
23568
|
+
/* @__PURE__ */ jsxs("div", {
|
|
23569
|
+
className: "w-20 flex items-center justify-end gap-3",
|
|
23570
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
23562
23571
|
onClick: () => onCreateRedirect(item.path),
|
|
23563
23572
|
className: "text-kumo-subtle hover:text-kumo-default",
|
|
23564
23573
|
title: _t2({
|
|
@@ -23571,7 +23580,20 @@ function NotFoundPanel({ items, onCreateRedirect }) {
|
|
|
23571
23580
|
values: { 0: item.path }
|
|
23572
23581
|
}),
|
|
23573
23582
|
children: /* @__PURE__ */ jsx(ArrowsLeftRight, { size: 14 })
|
|
23574
|
-
})
|
|
23583
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
23584
|
+
onClick: () => onMarkGone(item.path),
|
|
23585
|
+
className: "text-kumo-subtle hover:text-kumo-danger text-xs font-semibold tabular-nums",
|
|
23586
|
+
title: _t2({
|
|
23587
|
+
id: "P/mvvM",
|
|
23588
|
+
message: "Mark as Gone (410) — tells search engines it was permanently deleted"
|
|
23589
|
+
}),
|
|
23590
|
+
"aria-label": _t2({
|
|
23591
|
+
id: "XhXaJ+",
|
|
23592
|
+
message: "Mark {0} as Gone (410)",
|
|
23593
|
+
values: { 0: item.path }
|
|
23594
|
+
}),
|
|
23595
|
+
children: "410"
|
|
23596
|
+
})]
|
|
23575
23597
|
})
|
|
23576
23598
|
]
|
|
23577
23599
|
}, item.path))]
|
|
@@ -23630,6 +23652,17 @@ function Redirects() {
|
|
|
23630
23652
|
queryClient.invalidateQueries({ queryKey: ["redirects"] });
|
|
23631
23653
|
}
|
|
23632
23654
|
});
|
|
23655
|
+
const markGoneMutation = useMutation({
|
|
23656
|
+
mutationFn: (path) => createRedirect({
|
|
23657
|
+
source: path,
|
|
23658
|
+
destination: "",
|
|
23659
|
+
type: 410,
|
|
23660
|
+
enabled: true
|
|
23661
|
+
}),
|
|
23662
|
+
onSuccess: () => {
|
|
23663
|
+
queryClient.invalidateQueries({ queryKey: ["redirects"] });
|
|
23664
|
+
}
|
|
23665
|
+
});
|
|
23633
23666
|
function handleCreateFrom404(path) {
|
|
23634
23667
|
setPrefillSource(path);
|
|
23635
23668
|
setShowCreate(true);
|
|
@@ -23960,7 +23993,8 @@ function Redirects() {
|
|
|
23960
23993
|
] }),
|
|
23961
23994
|
tab === "404s" && /* @__PURE__ */ jsx(NotFoundPanel, {
|
|
23962
23995
|
items: notFoundQuery.data ?? [],
|
|
23963
|
-
onCreateRedirect: handleCreateFrom404
|
|
23996
|
+
onCreateRedirect: handleCreateFrom404,
|
|
23997
|
+
onMarkGone: (path) => markGoneMutation.mutate(path)
|
|
23964
23998
|
}),
|
|
23965
23999
|
showCreate && /* @__PURE__ */ jsx(RedirectFormDialog, {
|
|
23966
24000
|
open: true,
|
|
@@ -37438,7 +37472,8 @@ function BylinesPage() {
|
|
|
37438
37472
|
isGuest: guestFilter === "all" ? void 0 : guestFilter === "guest",
|
|
37439
37473
|
locale: activeLocale,
|
|
37440
37474
|
limit: 50
|
|
37441
|
-
})
|
|
37475
|
+
}),
|
|
37476
|
+
placeholderData: keepPreviousData
|
|
37442
37477
|
});
|
|
37443
37478
|
React$1.useEffect(() => {
|
|
37444
37479
|
if (data) {
|