@comvi/next 0.1.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/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/client/I18nProvider.cjs +101 -0
- package/dist/client/I18nProvider.d.ts +84 -0
- package/dist/client/I18nProvider.d.ts.map +1 -0
- package/dist/client/I18nProvider.js +99 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client.cjs +31 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +5 -0
- package/dist/createNextI18n.cjs +153 -0
- package/dist/createNextI18n.d.ts +183 -0
- package/dist/createNextI18n.d.ts.map +1 -0
- package/dist/createNextI18n.js +152 -0
- package/dist/index.cjs +17 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/middleware/createMiddleware.cjs +185 -0
- package/dist/middleware/createMiddleware.d.ts +38 -0
- package/dist/middleware/createMiddleware.d.ts.map +1 -0
- package/dist/middleware/createMiddleware.js +184 -0
- package/dist/middleware/types.d.ts +87 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware.cjs +3 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +2 -0
- package/dist/navigation.cjs +8 -0
- package/dist/navigation.d.ts +5 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +5 -0
- package/dist/routing/Link.cjs +42 -0
- package/dist/routing/Link.d.ts +25 -0
- package/dist/routing/Link.d.ts.map +1 -0
- package/dist/routing/Link.js +39 -0
- package/dist/routing/context.cjs +21 -0
- package/dist/routing/context.d.ts +9 -0
- package/dist/routing/context.d.ts.map +1 -0
- package/dist/routing/context.js +18 -0
- package/dist/routing/defineRouting.cjs +141 -0
- package/dist/routing/defineRouting.d.ts +123 -0
- package/dist/routing/defineRouting.d.ts.map +1 -0
- package/dist/routing/defineRouting.js +139 -0
- package/dist/routing/hooks.cjs +104 -0
- package/dist/routing/hooks.d.ts +66 -0
- package/dist/routing/hooks.d.ts.map +1 -0
- package/dist/routing/hooks.js +102 -0
- package/dist/routing/types.d.ts +35 -0
- package/dist/routing/types.d.ts.map +1 -0
- package/dist/routing/utils.cjs +94 -0
- package/dist/routing/utils.d.ts +8 -0
- package/dist/routing/utils.d.ts.map +1 -0
- package/dist/routing/utils.js +91 -0
- package/dist/routing.cjs +5 -0
- package/dist/routing.d.ts +4 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +2 -0
- package/dist/server/cache.cjs +69 -0
- package/dist/server/cache.d.ts +42 -0
- package/dist/server/cache.d.ts.map +1 -0
- package/dist/server/cache.js +66 -0
- package/dist/server/ensureInitialized.cjs +19 -0
- package/dist/server/ensureInitialized.d.ts +7 -0
- package/dist/server/ensureInitialized.d.ts.map +1 -0
- package/dist/server/ensureInitialized.js +19 -0
- package/dist/server/getI18n.cjs +115 -0
- package/dist/server/getI18n.d.ts +61 -0
- package/dist/server/getI18n.d.ts.map +1 -0
- package/dist/server/getI18n.js +114 -0
- package/dist/server/getLocale.cjs +37 -0
- package/dist/server/getLocale.d.ts +22 -0
- package/dist/server/getLocale.d.ts.map +1 -0
- package/dist/server/getLocale.js +36 -0
- package/dist/server/loadTranslations.cjs +54 -0
- package/dist/server/loadTranslations.d.ts +34 -0
- package/dist/server/loadTranslations.d.ts.map +1 -0
- package/dist/server/loadTranslations.js +54 -0
- package/dist/server/setRequestLocale.cjs +31 -0
- package/dist/server/setRequestLocale.d.ts +26 -0
- package/dist/server/setRequestLocale.d.ts.map +1 -0
- package/dist/server/setRequestLocale.js +31 -0
- package/dist/server/types.d.ts +43 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server.cjs +11 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +6 -0
- package/package.json +111 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { useRoutingConfig } from "./context.js";
|
|
4
|
+
import { getCanonicalPathname, localizeHref, stripLocalePrefix } from "./utils.js";
|
|
5
|
+
import { useCallback } from "react";
|
|
6
|
+
import { useI18n } from "@comvi/react";
|
|
7
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
8
|
+
//#region src/routing/hooks.ts
|
|
9
|
+
/**
|
|
10
|
+
* Get pathname without locale prefix
|
|
11
|
+
*
|
|
12
|
+
* This hook returns the current pathname with the locale prefix removed,
|
|
13
|
+
* making it easier to work with routes in a locale-agnostic way.
|
|
14
|
+
*
|
|
15
|
+
* @returns Pathname without locale prefix
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { usePathname } from '@comvi/next/navigation';
|
|
20
|
+
*
|
|
21
|
+
* function MyComponent() {
|
|
22
|
+
* const pathname = usePathname();
|
|
23
|
+
* // If URL is /en/about, pathname is /about
|
|
24
|
+
* return <p>Current page: {pathname}</p>;
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function usePathname$1() {
|
|
29
|
+
const pathname = usePathname() ?? "/";
|
|
30
|
+
const routing = useRoutingConfig();
|
|
31
|
+
const { locale } = useI18n();
|
|
32
|
+
if (routing) return getCanonicalPathname(stripLocalePrefix(pathname, routing.locales), routing, locale);
|
|
33
|
+
if (pathname.startsWith(`/${locale}/`)) return pathname.slice(locale.length + 1);
|
|
34
|
+
if (pathname === `/${locale}`) return "/";
|
|
35
|
+
return pathname;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Localized router with automatic locale prefixing
|
|
39
|
+
*
|
|
40
|
+
* This hook wraps Next.js useRouter and automatically adds locale
|
|
41
|
+
* prefixes to navigation methods.
|
|
42
|
+
*
|
|
43
|
+
* @returns Localized router object
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* import { useLocalizedRouter } from '@comvi/next/navigation';
|
|
48
|
+
*
|
|
49
|
+
* function MyComponent() {
|
|
50
|
+
* const router = useLocalizedRouter();
|
|
51
|
+
*
|
|
52
|
+
* const handleClick = () => {
|
|
53
|
+
* router.push('/about'); // Navigates to /en/about (or current locale)
|
|
54
|
+
* };
|
|
55
|
+
*
|
|
56
|
+
* const handleGerman = () => {
|
|
57
|
+
* router.push('/about', 'de'); // Navigates to /de/about
|
|
58
|
+
* };
|
|
59
|
+
*
|
|
60
|
+
* return <button onClick={handleClick}>Go to About</button>;
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
function useLocalizedRouter() {
|
|
65
|
+
const router = useRouter();
|
|
66
|
+
const { locale } = useI18n();
|
|
67
|
+
const routing = useRoutingConfig();
|
|
68
|
+
const push = useCallback((href, targetLocale) => {
|
|
69
|
+
const localizedHref = localizeHref(href, targetLocale ?? locale, routing ?? void 0);
|
|
70
|
+
router.push(localizedHref);
|
|
71
|
+
}, [
|
|
72
|
+
router,
|
|
73
|
+
locale,
|
|
74
|
+
routing
|
|
75
|
+
]);
|
|
76
|
+
const replace = useCallback((href, targetLocale) => {
|
|
77
|
+
const localizedHref = localizeHref(href, targetLocale ?? locale, routing ?? void 0);
|
|
78
|
+
router.replace(localizedHref);
|
|
79
|
+
}, [
|
|
80
|
+
router,
|
|
81
|
+
locale,
|
|
82
|
+
routing
|
|
83
|
+
]);
|
|
84
|
+
const prefetch = useCallback((href, targetLocale) => {
|
|
85
|
+
const localizedHref = localizeHref(href, targetLocale ?? locale, routing ?? void 0);
|
|
86
|
+
router.prefetch(localizedHref);
|
|
87
|
+
}, [
|
|
88
|
+
router,
|
|
89
|
+
locale,
|
|
90
|
+
routing
|
|
91
|
+
]);
|
|
92
|
+
return {
|
|
93
|
+
push,
|
|
94
|
+
replace,
|
|
95
|
+
back: router.back,
|
|
96
|
+
forward: router.forward,
|
|
97
|
+
refresh: router.refresh,
|
|
98
|
+
prefetch
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
export { useLocalizedRouter, usePathname$1 as usePathname };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale prefix mode for URL routing
|
|
3
|
+
*/
|
|
4
|
+
export type LocalePrefixMode = "always" | "as-needed" | "never";
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for i18n routing
|
|
7
|
+
*
|
|
8
|
+
* @typeParam T - Union type of supported locale strings (e.g., 'en' | 'uk' | 'de')
|
|
9
|
+
*/
|
|
10
|
+
export interface RoutingConfig<T extends string = string> {
|
|
11
|
+
/** Supported locales */
|
|
12
|
+
locales: readonly T[];
|
|
13
|
+
/** Default locale */
|
|
14
|
+
defaultLocale: T;
|
|
15
|
+
/**
|
|
16
|
+
* Locale prefix mode:
|
|
17
|
+
* - 'always': All routes have locale prefix (/en/about, /de/about)
|
|
18
|
+
* - 'as-needed': Only non-default locales have prefix (/about for en, /de/about for de)
|
|
19
|
+
* - 'never': No locale prefixes (use cookie/header only)
|
|
20
|
+
* @default 'as-needed'
|
|
21
|
+
*/
|
|
22
|
+
localePrefix?: LocalePrefixMode;
|
|
23
|
+
/**
|
|
24
|
+
* Cookie name for storing locale preference
|
|
25
|
+
* @default 'NEXT_LOCALE'
|
|
26
|
+
*/
|
|
27
|
+
localeCookie?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Path configurations for different locales (optional)
|
|
30
|
+
* Allows different URL paths per locale
|
|
31
|
+
* @example { '/about': { en: '/about', de: '/ueber-uns' } }
|
|
32
|
+
*/
|
|
33
|
+
pathnames?: Record<string, Partial<Record<T, string>>>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACtD,wBAAwB;IACxB,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IACtB,qBAAqB;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACxD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const require_defineRouting = require("./defineRouting.cjs");
|
|
2
|
+
//#region src/routing/utils.ts
|
|
3
|
+
var getPathnameCache = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
var isExternalHref = (href) => {
|
|
5
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith("//");
|
|
6
|
+
};
|
|
7
|
+
var isRelativeFragmentOrQuery = (href) => {
|
|
8
|
+
return href.startsWith("#") || href.startsWith("?");
|
|
9
|
+
};
|
|
10
|
+
var normalizePath = (path) => {
|
|
11
|
+
if (!path) return "/";
|
|
12
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
13
|
+
};
|
|
14
|
+
var getCanonicalPathMatch = (pathname, routing, preferredLocale) => {
|
|
15
|
+
const normalizedPath = normalizePath(pathname);
|
|
16
|
+
const localesToTry = preferredLocale ? [preferredLocale, ...routing.locales.filter((locale) => locale !== preferredLocale)] : [...routing.locales];
|
|
17
|
+
for (const [canonicalPath, localizedByLocale] of Object.entries(routing.pathnames)) {
|
|
18
|
+
const normalizedCanonicalPath = normalizePath(canonicalPath);
|
|
19
|
+
if (normalizedPath === normalizedCanonicalPath) return normalizedCanonicalPath;
|
|
20
|
+
for (const locale of localesToTry) {
|
|
21
|
+
const localizedPath = localizedByLocale[locale];
|
|
22
|
+
if (localizedPath && normalizePath(localizedPath) === normalizedPath) return normalizedCanonicalPath;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var stripLocalePrefix = (pathname, locales) => {
|
|
27
|
+
const normalized = normalizePath(pathname);
|
|
28
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
29
|
+
if (segments.length === 0) return "/";
|
|
30
|
+
const first = segments[0];
|
|
31
|
+
if (locales.includes(first)) {
|
|
32
|
+
const rest = segments.slice(1).join("/");
|
|
33
|
+
return rest ? `/${rest}` : "/";
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
};
|
|
37
|
+
var getCanonicalPathname = (pathname, routing, preferredLocale) => {
|
|
38
|
+
const normalizedPath = normalizePath(pathname);
|
|
39
|
+
return getCanonicalPathMatch(normalizedPath, routing, preferredLocale) ?? normalizedPath;
|
|
40
|
+
};
|
|
41
|
+
var splitHref = (href) => {
|
|
42
|
+
const match = href.match(/[?#]/);
|
|
43
|
+
if (!match || match.index === void 0) return {
|
|
44
|
+
path: href,
|
|
45
|
+
suffix: ""
|
|
46
|
+
};
|
|
47
|
+
const index = match.index;
|
|
48
|
+
return {
|
|
49
|
+
path: href.slice(0, index),
|
|
50
|
+
suffix: href.slice(index)
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
var localizePathname = (pathname, locale, routing) => {
|
|
54
|
+
const { path, suffix } = splitHref(pathname);
|
|
55
|
+
const canonicalPath = getCanonicalPathname(stripLocalePrefix(path, routing.locales), routing, locale);
|
|
56
|
+
let getPathname = getPathnameCache.get(routing);
|
|
57
|
+
if (!getPathname) {
|
|
58
|
+
getPathname = require_defineRouting.createGetPathname(routing);
|
|
59
|
+
getPathnameCache.set(routing, getPathname);
|
|
60
|
+
}
|
|
61
|
+
return `${getPathname({
|
|
62
|
+
locale,
|
|
63
|
+
href: canonicalPath
|
|
64
|
+
})}${suffix}`;
|
|
65
|
+
};
|
|
66
|
+
var localizeHref = (href, locale, routing) => {
|
|
67
|
+
if (isExternalHref(href)) return href;
|
|
68
|
+
if (isRelativeFragmentOrQuery(href)) return href;
|
|
69
|
+
if (!routing) {
|
|
70
|
+
const normalized = normalizePath(href);
|
|
71
|
+
return `/${locale}${normalized === "/" ? "" : normalized}`;
|
|
72
|
+
}
|
|
73
|
+
return localizePathname(href, locale, routing);
|
|
74
|
+
};
|
|
75
|
+
var localizeUrlObject = (href, locale, routing) => {
|
|
76
|
+
if (href.protocol) return href;
|
|
77
|
+
const pathname = typeof href.pathname === "string" ? href.pathname : "/";
|
|
78
|
+
if (!routing) {
|
|
79
|
+
const normalized = normalizePath(pathname);
|
|
80
|
+
return {
|
|
81
|
+
...href,
|
|
82
|
+
pathname: `/${locale}${normalized === "/" ? "" : normalized}`
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
...href,
|
|
87
|
+
pathname: localizePathname(pathname, locale, routing)
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
//#endregion
|
|
91
|
+
exports.getCanonicalPathname = getCanonicalPathname;
|
|
92
|
+
exports.localizeHref = localizeHref;
|
|
93
|
+
exports.localizeUrlObject = localizeUrlObject;
|
|
94
|
+
exports.stripLocalePrefix = stripLocalePrefix;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { UrlObject } from 'url';
|
|
2
|
+
import { RoutingConfig } from './types';
|
|
3
|
+
export declare const stripLocalePrefix: (pathname: string, locales: readonly string[]) => string;
|
|
4
|
+
export declare const getCanonicalPathname: (pathname: string, routing: Required<RoutingConfig>, preferredLocale?: string) => string;
|
|
5
|
+
export declare const localizePathname: (pathname: string, locale: string, routing: Required<RoutingConfig>) => string;
|
|
6
|
+
export declare const localizeHref: (href: string, locale: string, routing?: Required<RoutingConfig>) => string;
|
|
7
|
+
export declare const localizeUrlObject: (href: UrlObject, locale: string, routing?: Required<RoutingConfig>) => UrlObject;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/routing/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAiD7C,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,EAAE,SAAS,SAAS,MAAM,EAAE,KAAG,MAYhF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,UAAU,MAAM,EAChB,SAAS,QAAQ,CAAC,aAAa,CAAC,EAChC,kBAAkB,MAAM,KACvB,MAGF,CAAC;AAWF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,SAAS,QAAQ,CAAC,aAAa,CAAC,KAC/B,MAWF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,UAAU,QAAQ,CAAC,aAAa,CAAC,KAChC,MAQF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,SAAS,EACf,QAAQ,MAAM,EACd,UAAU,QAAQ,CAAC,aAAa,CAAC,KAChC,SAgBF,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createGetPathname } from "./defineRouting.js";
|
|
2
|
+
//#region src/routing/utils.ts
|
|
3
|
+
var getPathnameCache = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
var isExternalHref = (href) => {
|
|
5
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith("//");
|
|
6
|
+
};
|
|
7
|
+
var isRelativeFragmentOrQuery = (href) => {
|
|
8
|
+
return href.startsWith("#") || href.startsWith("?");
|
|
9
|
+
};
|
|
10
|
+
var normalizePath = (path) => {
|
|
11
|
+
if (!path) return "/";
|
|
12
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
13
|
+
};
|
|
14
|
+
var getCanonicalPathMatch = (pathname, routing, preferredLocale) => {
|
|
15
|
+
const normalizedPath = normalizePath(pathname);
|
|
16
|
+
const localesToTry = preferredLocale ? [preferredLocale, ...routing.locales.filter((locale) => locale !== preferredLocale)] : [...routing.locales];
|
|
17
|
+
for (const [canonicalPath, localizedByLocale] of Object.entries(routing.pathnames)) {
|
|
18
|
+
const normalizedCanonicalPath = normalizePath(canonicalPath);
|
|
19
|
+
if (normalizedPath === normalizedCanonicalPath) return normalizedCanonicalPath;
|
|
20
|
+
for (const locale of localesToTry) {
|
|
21
|
+
const localizedPath = localizedByLocale[locale];
|
|
22
|
+
if (localizedPath && normalizePath(localizedPath) === normalizedPath) return normalizedCanonicalPath;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var stripLocalePrefix = (pathname, locales) => {
|
|
27
|
+
const normalized = normalizePath(pathname);
|
|
28
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
29
|
+
if (segments.length === 0) return "/";
|
|
30
|
+
const first = segments[0];
|
|
31
|
+
if (locales.includes(first)) {
|
|
32
|
+
const rest = segments.slice(1).join("/");
|
|
33
|
+
return rest ? `/${rest}` : "/";
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
};
|
|
37
|
+
var getCanonicalPathname = (pathname, routing, preferredLocale) => {
|
|
38
|
+
const normalizedPath = normalizePath(pathname);
|
|
39
|
+
return getCanonicalPathMatch(normalizedPath, routing, preferredLocale) ?? normalizedPath;
|
|
40
|
+
};
|
|
41
|
+
var splitHref = (href) => {
|
|
42
|
+
const match = href.match(/[?#]/);
|
|
43
|
+
if (!match || match.index === void 0) return {
|
|
44
|
+
path: href,
|
|
45
|
+
suffix: ""
|
|
46
|
+
};
|
|
47
|
+
const index = match.index;
|
|
48
|
+
return {
|
|
49
|
+
path: href.slice(0, index),
|
|
50
|
+
suffix: href.slice(index)
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
var localizePathname = (pathname, locale, routing) => {
|
|
54
|
+
const { path, suffix } = splitHref(pathname);
|
|
55
|
+
const canonicalPath = getCanonicalPathname(stripLocalePrefix(path, routing.locales), routing, locale);
|
|
56
|
+
let getPathname = getPathnameCache.get(routing);
|
|
57
|
+
if (!getPathname) {
|
|
58
|
+
getPathname = createGetPathname(routing);
|
|
59
|
+
getPathnameCache.set(routing, getPathname);
|
|
60
|
+
}
|
|
61
|
+
return `${getPathname({
|
|
62
|
+
locale,
|
|
63
|
+
href: canonicalPath
|
|
64
|
+
})}${suffix}`;
|
|
65
|
+
};
|
|
66
|
+
var localizeHref = (href, locale, routing) => {
|
|
67
|
+
if (isExternalHref(href)) return href;
|
|
68
|
+
if (isRelativeFragmentOrQuery(href)) return href;
|
|
69
|
+
if (!routing) {
|
|
70
|
+
const normalized = normalizePath(href);
|
|
71
|
+
return `/${locale}${normalized === "/" ? "" : normalized}`;
|
|
72
|
+
}
|
|
73
|
+
return localizePathname(href, locale, routing);
|
|
74
|
+
};
|
|
75
|
+
var localizeUrlObject = (href, locale, routing) => {
|
|
76
|
+
if (href.protocol) return href;
|
|
77
|
+
const pathname = typeof href.pathname === "string" ? href.pathname : "/";
|
|
78
|
+
if (!routing) {
|
|
79
|
+
const normalized = normalizePath(pathname);
|
|
80
|
+
return {
|
|
81
|
+
...href,
|
|
82
|
+
pathname: `/${locale}${normalized === "/" ? "" : normalized}`
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
...href,
|
|
87
|
+
pathname: localizePathname(pathname, locale, routing)
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
//#endregion
|
|
91
|
+
export { getCanonicalPathname, localizeHref, localizeUrlObject, stripLocalePrefix };
|
package/dist/routing.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_defineRouting = require("./routing/defineRouting.cjs");
|
|
3
|
+
exports.createGetPathname = require_defineRouting.createGetPathname;
|
|
4
|
+
exports.defineRouting = require_defineRouting.defineRouting;
|
|
5
|
+
exports.hasLocale = require_defineRouting.hasLocale;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEtF,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/routing.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
//#region src/server/cache.ts
|
|
3
|
+
/**
|
|
4
|
+
* Request-scoped locale storage using React cache()
|
|
5
|
+
* This allows setRequestLocale() to store locale that getTranslations() can read
|
|
6
|
+
*
|
|
7
|
+
* React's cache() creates a per-request memoized value in Server Components,
|
|
8
|
+
* allowing us to share state across the component tree without prop drilling.
|
|
9
|
+
*/
|
|
10
|
+
var getRequestStore = (0, require("react").cache)(() => ({ locale: void 0 }));
|
|
11
|
+
/**
|
|
12
|
+
* Global i18n reference (set once via setI18n)
|
|
13
|
+
* This is safe because Next.js creates separate module instances for server/client
|
|
14
|
+
*/
|
|
15
|
+
var globalI18n;
|
|
16
|
+
/**
|
|
17
|
+
* Configure the global i18n instance for server-side usage
|
|
18
|
+
*
|
|
19
|
+
* Call this once in your i18n configuration file to make getTranslations() work.
|
|
20
|
+
*
|
|
21
|
+
* @param i18n - The i18n instance created with createI18n
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // i18n/index.ts
|
|
26
|
+
* import { createI18n } from '@comvi/next';
|
|
27
|
+
* import { setI18n } from '@comvi/next/server';
|
|
28
|
+
* import { translations } from './translations';
|
|
29
|
+
*
|
|
30
|
+
* export const i18n = createI18n({
|
|
31
|
+
* locale: 'en',
|
|
32
|
+
* defaultNs: 'default',
|
|
33
|
+
* translation: translations,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Configure for server-side usage
|
|
37
|
+
* setI18n(i18n);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function setI18n(i18n) {
|
|
41
|
+
globalI18n = i18n;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the global i18n instance
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
function getI18nInstance() {
|
|
48
|
+
if (!globalI18n) throw new Error("[comvi/next] i18n not configured. Call setI18n(i18n) in your i18n configuration file.");
|
|
49
|
+
return globalI18n;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set the request locale in the cache
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
function setRequestLocaleInternal(locale) {
|
|
56
|
+
getRequestStore().locale = locale;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get the request locale from cache
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
function getRequestLocaleFromCache() {
|
|
63
|
+
return getRequestStore().locale;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
exports.getI18nInstance = getI18nInstance;
|
|
67
|
+
exports.getRequestLocaleFromCache = getRequestLocaleFromCache;
|
|
68
|
+
exports.setI18n = setI18n;
|
|
69
|
+
exports.setRequestLocaleInternal = setRequestLocaleInternal;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { I18n } from '@comvi/core';
|
|
2
|
+
/**
|
|
3
|
+
* Configure the global i18n instance for server-side usage
|
|
4
|
+
*
|
|
5
|
+
* Call this once in your i18n configuration file to make getTranslations() work.
|
|
6
|
+
*
|
|
7
|
+
* @param i18n - The i18n instance created with createI18n
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // i18n/index.ts
|
|
12
|
+
* import { createI18n } from '@comvi/next';
|
|
13
|
+
* import { setI18n } from '@comvi/next/server';
|
|
14
|
+
* import { translations } from './translations';
|
|
15
|
+
*
|
|
16
|
+
* export const i18n = createI18n({
|
|
17
|
+
* locale: 'en',
|
|
18
|
+
* defaultNs: 'default',
|
|
19
|
+
* translation: translations,
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Configure for server-side usage
|
|
23
|
+
* setI18n(i18n);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function setI18n(i18n: I18n): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get the global i18n instance
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export declare function getI18nInstance(): I18n;
|
|
32
|
+
/**
|
|
33
|
+
* Set the request locale in the cache
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
export declare function setRequestLocaleInternal(locale: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get the request locale from cache
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export declare function getRequestLocaleFromCache(): string | undefined;
|
|
42
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/server/cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAsBxC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAExC;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAOtC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE7D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,GAAG,SAAS,CAE9D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { cache } from "react";
|
|
2
|
+
//#region src/server/cache.ts
|
|
3
|
+
/**
|
|
4
|
+
* Request-scoped locale storage using React cache()
|
|
5
|
+
* This allows setRequestLocale() to store locale that getTranslations() can read
|
|
6
|
+
*
|
|
7
|
+
* React's cache() creates a per-request memoized value in Server Components,
|
|
8
|
+
* allowing us to share state across the component tree without prop drilling.
|
|
9
|
+
*/
|
|
10
|
+
var getRequestStore = cache(() => ({ locale: void 0 }));
|
|
11
|
+
/**
|
|
12
|
+
* Global i18n reference (set once via setI18n)
|
|
13
|
+
* This is safe because Next.js creates separate module instances for server/client
|
|
14
|
+
*/
|
|
15
|
+
var globalI18n;
|
|
16
|
+
/**
|
|
17
|
+
* Configure the global i18n instance for server-side usage
|
|
18
|
+
*
|
|
19
|
+
* Call this once in your i18n configuration file to make getTranslations() work.
|
|
20
|
+
*
|
|
21
|
+
* @param i18n - The i18n instance created with createI18n
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // i18n/index.ts
|
|
26
|
+
* import { createI18n } from '@comvi/next';
|
|
27
|
+
* import { setI18n } from '@comvi/next/server';
|
|
28
|
+
* import { translations } from './translations';
|
|
29
|
+
*
|
|
30
|
+
* export const i18n = createI18n({
|
|
31
|
+
* locale: 'en',
|
|
32
|
+
* defaultNs: 'default',
|
|
33
|
+
* translation: translations,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Configure for server-side usage
|
|
37
|
+
* setI18n(i18n);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function setI18n(i18n) {
|
|
41
|
+
globalI18n = i18n;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the global i18n instance
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
function getI18nInstance() {
|
|
48
|
+
if (!globalI18n) throw new Error("[comvi/next] i18n not configured. Call setI18n(i18n) in your i18n configuration file.");
|
|
49
|
+
return globalI18n;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set the request locale in the cache
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
function setRequestLocaleInternal(locale) {
|
|
56
|
+
getRequestStore().locale = locale;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get the request locale from cache
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
function getRequestLocaleFromCache() {
|
|
63
|
+
return getRequestStore().locale;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { getI18nInstance, getRequestLocaleFromCache, setI18n, setRequestLocaleInternal };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/server/ensureInitialized.ts
|
|
2
|
+
var initPromises = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
* Ensure i18n instance is initialized, deduplicating concurrent calls.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
var ensureInitialized = async (i18n) => {
|
|
8
|
+
if (i18n.isInitialized) return;
|
|
9
|
+
let initPromise = initPromises.get(i18n);
|
|
10
|
+
if (!initPromise) {
|
|
11
|
+
initPromise = i18n.init().then(() => void 0).finally(() => {
|
|
12
|
+
if (initPromises.get(i18n) === initPromise) initPromises.delete(i18n);
|
|
13
|
+
});
|
|
14
|
+
initPromises.set(i18n, initPromise);
|
|
15
|
+
}
|
|
16
|
+
await initPromise;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
exports.ensureInitialized = ensureInitialized;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensureInitialized.d.ts","sourceRoot":"","sources":["../../src/server/ensureInitialized.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAIxC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,IAAI,CAmBhE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/server/ensureInitialized.ts
|
|
2
|
+
var initPromises = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
* Ensure i18n instance is initialized, deduplicating concurrent calls.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
var ensureInitialized = async (i18n) => {
|
|
8
|
+
if (i18n.isInitialized) return;
|
|
9
|
+
let initPromise = initPromises.get(i18n);
|
|
10
|
+
if (!initPromise) {
|
|
11
|
+
initPromise = i18n.init().then(() => void 0).finally(() => {
|
|
12
|
+
if (initPromises.get(i18n) === initPromise) initPromises.delete(i18n);
|
|
13
|
+
});
|
|
14
|
+
initPromises.set(i18n, initPromise);
|
|
15
|
+
}
|
|
16
|
+
await initPromise;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { ensureInitialized };
|