@quilted/preact-localize 0.1.0 → 0.3.1
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/CHANGELOG.md +16 -0
- package/build/esm/Localization.mjs +11 -3
- package/build/esm/index.mjs +2 -2
- package/build/esm/request-router.mjs +5 -5
- package/build/esm/routing/LocalizedLink.mjs +6 -6
- package/build/esm/routing/LocalizedNavigation.mjs +47 -0
- package/build/esm/routing/LocalizedRouter.mjs +34 -0
- package/build/esm/routing/localization/by-locale.mjs +5 -5
- package/build/esnext/Localization.esnext +9 -3
- package/build/esnext/index.esnext +2 -2
- package/build/esnext/request-router.esnext +5 -6
- package/build/esnext/routing/LocalizedLink.esnext +7 -7
- package/build/esnext/routing/LocalizedNavigation.esnext +35 -0
- package/build/esnext/routing/LocalizedRouter.esnext +32 -0
- package/build/esnext/routing/localization/by-locale.esnext +9 -13
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/typescript/Localization.d.ts +2 -2
- package/build/typescript/Localization.d.ts.map +1 -1
- package/build/typescript/index.d.ts +0 -1
- package/build/typescript/index.d.ts.map +1 -1
- package/build/typescript/routing/LocalizedNavigation.d.ts +13 -0
- package/build/typescript/routing/LocalizedNavigation.d.ts.map +1 -0
- package/build/typescript/routing/LocalizedRouter.d.ts +9 -0
- package/build/typescript/routing/LocalizedRouter.d.ts.map +1 -0
- package/build/typescript/routing/types.d.ts +2 -2
- package/build/typescript/routing.d.ts +2 -1
- package/build/typescript/routing.d.ts.map +1 -1
- package/package.json +5 -5
- package/source/Localization.tsx +13 -4
- package/source/index.ts +0 -1
- package/source/request-router.ts +4 -4
- package/source/routing/LocalizedLink.tsx +7 -7
- package/source/routing/LocalizedNavigation.tsx +63 -0
- package/source/routing/LocalizedRouter.ts +46 -0
- package/source/routing/localization/by-locale.ts +5 -5
- package/source/routing/types.ts +2 -2
- package/source/routing.ts +2 -1
- package/tsconfig.json +1 -5
- package/build/esm/hooks/locale-from-environment.mjs +0 -15
- package/build/esm/routing/LocalizedRouting.mjs +0 -65
- package/build/esnext/hooks/locale-from-environment.esnext +0 -13
- package/build/esnext/routing/LocalizedRouting.esnext +0 -64
- package/build/typescript/routing/LocalizedRouting.d.ts +0 -9
- package/build/typescript/routing/LocalizedRouting.d.ts.map +0 -1
- package/source/hooks/locale-from-environment.ts +0 -15
- package/source/routing/LocalizedRouting.tsx +0 -94
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @quilted/react-localize
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#788](https://github.com/lemonmade/quilt/pull/788) [`85a4b7e`](https://github.com/lemonmade/quilt/commit/85a4b7ed8e6ad58662ebf969d8fabbe8e21510a3) Thanks [@lemonmade](https://github.com/lemonmade)! - Add `Browser.locale` and use it in place of `useLocaleFromEnvironment()`
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#757](https://github.com/lemonmade/quilt/pull/757) [`00cac4b`](https://github.com/lemonmade/quilt/commit/00cac4b4d01831ba654e94152d7a67a0ef75043b) Thanks [@lemonmade](https://github.com/lemonmade)! - Simplify routing library
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [[`00cac4b`](https://github.com/lemonmade/quilt/commit/00cac4b4d01831ba654e94152d7a67a0ef75043b)]:
|
|
16
|
+
- @quilted/request-router@0.3.0
|
|
17
|
+
- @quilted/preact-router@0.2.0
|
|
18
|
+
|
|
3
19
|
## 0.2.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { useMemo } from 'preact/hooks';
|
|
2
2
|
import { createLocalizedFormatting } from '@quilted/localize';
|
|
3
|
-
import { HTMLAttributes } from '@quilted/preact-browser';
|
|
3
|
+
import { useBrowserDetails, HTMLAttributes } from '@quilted/preact-browser';
|
|
4
4
|
import { LocaleContext, LocalizedFormattingContext } from './context.mjs';
|
|
5
5
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
const RTL_LOCALES = new Set(['ar', 'arc', 'ckb', 'dv', 'fa', 'ha', 'he', 'khw', 'ks', 'ps', 'sd', 'ur', 'uz-AF', 'yi']);
|
|
8
8
|
function Localization({
|
|
9
|
-
locale,
|
|
10
|
-
direction
|
|
9
|
+
locale: explicitLocale,
|
|
10
|
+
direction: explicitDirection,
|
|
11
11
|
children
|
|
12
12
|
}) {
|
|
13
|
+
const browserDetails = useBrowserDetails({
|
|
14
|
+
optional: explicitLocale == null
|
|
15
|
+
});
|
|
16
|
+
const locale = explicitLocale ?? browserDetails?.locale.value;
|
|
17
|
+
if (locale == null) {
|
|
18
|
+
throw new Error(`Could not determine locale`);
|
|
19
|
+
}
|
|
13
20
|
const formatting = useMemo(() => createLocalizedFormatting(locale), [locale]);
|
|
21
|
+
const direction = explicitDirection ?? (RTL_LOCALES.has(locale) ? 'rtl' : 'ltr');
|
|
14
22
|
return jsx(LocaleContext.Provider, {
|
|
15
23
|
value: locale,
|
|
16
24
|
children: jsxs(LocalizedFormattingContext.Provider, {
|
package/build/esm/index.mjs
CHANGED
|
@@ -2,10 +2,10 @@ export { MissingTranslationError, MissingTranslationPlaceholderError, createLoca
|
|
|
2
2
|
export { Localization } from './Localization.mjs';
|
|
3
3
|
export { useLocalizedFormatting } from './hooks/formatting.mjs';
|
|
4
4
|
export { useLocale } from './hooks/locale.mjs';
|
|
5
|
-
export { useLocaleFromEnvironment } from './hooks/locale-from-environment.mjs';
|
|
6
5
|
export { LocalizedFormattingContext } from './context.mjs';
|
|
7
6
|
export { LocalizedLink } from './routing/LocalizedLink.mjs';
|
|
8
|
-
export {
|
|
7
|
+
export { LocalizedNavigation } from './routing/LocalizedNavigation.mjs';
|
|
8
|
+
export { LocalizedRouter } from './routing/LocalizedRouter.mjs';
|
|
9
9
|
export { useRouteLocalization } from './routing/context.mjs';
|
|
10
10
|
export { createRouteLocalization } from './routing/localization/by-locale.mjs';
|
|
11
11
|
export { createRoutePathLocalization } from './routing/localization/by-path.mjs';
|
|
@@ -7,9 +7,9 @@ function createRequestRouterLocalization({
|
|
|
7
7
|
}) {
|
|
8
8
|
const {
|
|
9
9
|
matchLocale,
|
|
10
|
-
|
|
10
|
+
redirectURL,
|
|
11
11
|
defaultLocale,
|
|
12
|
-
|
|
12
|
+
localeFromURL
|
|
13
13
|
} = localization;
|
|
14
14
|
const getDefaultLocaleFromRequest = request => {
|
|
15
15
|
const acceptLanguage = request.headers.get('Accept-Language');
|
|
@@ -20,7 +20,7 @@ function createRequestRouterLocalization({
|
|
|
20
20
|
to,
|
|
21
21
|
...options
|
|
22
22
|
}) {
|
|
23
|
-
return new RedirectResponse(
|
|
23
|
+
return new RedirectResponse(redirectURL(new URL(request.url), {
|
|
24
24
|
to
|
|
25
25
|
}), options);
|
|
26
26
|
}
|
|
@@ -32,11 +32,11 @@ function createRequestRouterLocalization({
|
|
|
32
32
|
return async (request, ...args) => {
|
|
33
33
|
if (!include(request)) return handler(request, ...args);
|
|
34
34
|
const url = new URL(request.url);
|
|
35
|
-
const urlLocale =
|
|
35
|
+
const urlLocale = localeFromURL(url);
|
|
36
36
|
const requestLocale = getLocaleForRequest(request, () => getDefaultLocaleFromRequest(request));
|
|
37
37
|
const matchedLocale = (requestLocale == null ? undefined : matchLocale(requestLocale)) ?? defaultLocale;
|
|
38
38
|
if (urlLocale !== matchedLocale) {
|
|
39
|
-
return new RedirectResponse(
|
|
39
|
+
return new RedirectResponse(redirectURL(url, {
|
|
40
40
|
to: matchedLocale
|
|
41
41
|
}));
|
|
42
42
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'preact/hooks';
|
|
2
|
-
import { useRouter,
|
|
2
|
+
import { useRouter, useCurrentURL, Link } from '@quilted/preact-router';
|
|
3
3
|
import { useRouteLocalization } from './context.mjs';
|
|
4
4
|
import { jsx } from 'preact/jsx-runtime';
|
|
5
5
|
|
|
@@ -9,16 +9,16 @@ function LocalizedLink({
|
|
|
9
9
|
...props
|
|
10
10
|
}) {
|
|
11
11
|
const router = useRouter();
|
|
12
|
-
const
|
|
12
|
+
const url = useCurrentURL();
|
|
13
13
|
const {
|
|
14
|
-
|
|
14
|
+
redirectURL
|
|
15
15
|
} = useRouteLocalization();
|
|
16
|
-
const
|
|
16
|
+
const resolvedURL = useMemo(() => redirectURL(to ? router.resolve(to).url : url, {
|
|
17
17
|
to: locale
|
|
18
|
-
}), [to,
|
|
18
|
+
}), [to, url, locale, redirectURL, router]);
|
|
19
19
|
return jsx(Link, {
|
|
20
20
|
hrefLang: locale,
|
|
21
|
-
to:
|
|
21
|
+
to: resolvedURL,
|
|
22
22
|
...props
|
|
23
23
|
});
|
|
24
24
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useMemo } from 'preact/hooks';
|
|
2
|
+
import { useBrowserDetails } from '@quilted/preact-browser';
|
|
3
|
+
import { Navigation } from '@quilted/preact-router';
|
|
4
|
+
import { Localization } from '../Localization.mjs';
|
|
5
|
+
import { LocalizedRouter } from './LocalizedRouter.mjs';
|
|
6
|
+
import { RouteLocalizationContext } from './context.mjs';
|
|
7
|
+
import { jsx } from 'preact/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
function LocalizedNavigation({
|
|
10
|
+
locale: explicitLocale,
|
|
11
|
+
router,
|
|
12
|
+
routes,
|
|
13
|
+
context,
|
|
14
|
+
localization,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const browser = useBrowserDetails({
|
|
18
|
+
optional: true
|
|
19
|
+
});
|
|
20
|
+
const resolvedRouter = useMemo(() => router ?? new LocalizedRouter(browser?.request.url, {
|
|
21
|
+
localization: localization
|
|
22
|
+
}), [router]);
|
|
23
|
+
const resolvedLocalization = resolvedRouter.localization;
|
|
24
|
+
const localeFromEnvironment = browser?.locale.value;
|
|
25
|
+
let resolvedLocale;
|
|
26
|
+
if (explicitLocale) {
|
|
27
|
+
resolvedLocale = explicitLocale;
|
|
28
|
+
} else if (localeFromEnvironment != null && localeFromEnvironment.toLowerCase().startsWith(resolvedLocalization.locale.toLowerCase())) {
|
|
29
|
+
resolvedLocale = localeFromEnvironment;
|
|
30
|
+
} else {
|
|
31
|
+
resolvedLocale = resolvedLocalization.locale;
|
|
32
|
+
}
|
|
33
|
+
return jsx(Localization, {
|
|
34
|
+
locale: resolvedLocale,
|
|
35
|
+
children: jsx(RouteLocalizationContext.Provider, {
|
|
36
|
+
value: resolvedLocalization,
|
|
37
|
+
children: jsx(Navigation, {
|
|
38
|
+
router: resolvedRouter,
|
|
39
|
+
routes: routes,
|
|
40
|
+
context: context,
|
|
41
|
+
children: children
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { LocalizedNavigation };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Router } from '@quilted/preact-router';
|
|
2
|
+
|
|
3
|
+
class LocalizedRouter extends Router {
|
|
4
|
+
constructor(initial, {
|
|
5
|
+
localization,
|
|
6
|
+
isExternal: explicitIsExternal
|
|
7
|
+
}) {
|
|
8
|
+
const {
|
|
9
|
+
localeFromURL
|
|
10
|
+
} = localization;
|
|
11
|
+
super(initial, {
|
|
12
|
+
isExternal(url, currentURL) {
|
|
13
|
+
return matchedLocale !== localeFromURL(url) || (explicitIsExternal?.(url, currentURL) ?? false);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const currentURL = this.currentRequest.url;
|
|
17
|
+
const matchedLocale = localeFromURL(currentURL);
|
|
18
|
+
const resolvedLocalization = {
|
|
19
|
+
locale: matchedLocale ?? localization.defaultLocale,
|
|
20
|
+
...localization
|
|
21
|
+
};
|
|
22
|
+
this.localization = resolvedLocalization;
|
|
23
|
+
const {
|
|
24
|
+
pathname: rootPath
|
|
25
|
+
} = localization.redirectURL(new URL('/', currentURL), {
|
|
26
|
+
to: resolvedLocalization.locale
|
|
27
|
+
});
|
|
28
|
+
if (rootPath.length > 1) Object.assign(this, {
|
|
29
|
+
base: rootPath
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { LocalizedRouter };
|
|
@@ -6,16 +6,16 @@ function createRouteLocalization({
|
|
|
6
6
|
const locales = [...localeMap.keys()].sort((a, b) => b.length - a.length);
|
|
7
7
|
return {
|
|
8
8
|
locales,
|
|
9
|
-
|
|
9
|
+
redirectURL,
|
|
10
10
|
matchLocale,
|
|
11
|
-
|
|
11
|
+
localeFromURL,
|
|
12
12
|
defaultLocale
|
|
13
13
|
};
|
|
14
14
|
function matchLocale(requestLocale) {
|
|
15
15
|
const language = requestLocale.split('-')[0];
|
|
16
16
|
return locales.find(locale => locale === requestLocale || locale === language);
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
function localeFromURL(url) {
|
|
19
19
|
const hostname = url.hostname.toLowerCase();
|
|
20
20
|
const pathname = normalizePath(url.pathname.toLowerCase());
|
|
21
21
|
for (const [locale, target] of sortedLocaleMap) {
|
|
@@ -26,10 +26,10 @@ function createRouteLocalization({
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function redirectURL(from, {
|
|
30
30
|
to: toLocale
|
|
31
31
|
}) {
|
|
32
|
-
const fromLocale =
|
|
32
|
+
const fromLocale = localeFromURL(from);
|
|
33
33
|
const toUrl = new URL(from);
|
|
34
34
|
if (fromLocale === toLocale) return toUrl;
|
|
35
35
|
const target = localeMap.get(toLocale) ?? localeMap.get(defaultLocale);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'preact/hooks';
|
|
3
3
|
import { createLocalizedFormatting } from '@quilted/localize';
|
|
4
|
-
import { HTMLAttributes } from '@quilted/preact-browser';
|
|
4
|
+
import { useBrowserDetails, HTMLAttributes } from '@quilted/preact-browser';
|
|
5
5
|
import { LocaleContext, LocalizedFormattingContext } from './context.esnext';
|
|
6
6
|
|
|
7
7
|
const RTL_LOCALES = /* @__PURE__ */ new Set([
|
|
@@ -21,11 +21,17 @@ const RTL_LOCALES = /* @__PURE__ */ new Set([
|
|
|
21
21
|
"yi"
|
|
22
22
|
]);
|
|
23
23
|
function Localization({
|
|
24
|
-
locale,
|
|
25
|
-
direction
|
|
24
|
+
locale: explicitLocale,
|
|
25
|
+
direction: explicitDirection,
|
|
26
26
|
children
|
|
27
27
|
}) {
|
|
28
|
+
const browserDetails = useBrowserDetails({ optional: explicitLocale == null });
|
|
29
|
+
const locale = explicitLocale ?? browserDetails?.locale.value;
|
|
30
|
+
if (locale == null) {
|
|
31
|
+
throw new Error(`Could not determine locale`);
|
|
32
|
+
}
|
|
28
33
|
const formatting = useMemo(() => createLocalizedFormatting(locale), [locale]);
|
|
34
|
+
const direction = explicitDirection ?? (RTL_LOCALES.has(locale) ? "rtl" : "ltr");
|
|
29
35
|
return /* @__PURE__ */ jsx(LocaleContext.Provider, { value: locale, children: /* @__PURE__ */ jsxs(LocalizedFormattingContext.Provider, { value: formatting, children: [
|
|
30
36
|
/* @__PURE__ */ jsx(HTMLAttributes, { lang: locale, dir: direction }),
|
|
31
37
|
children
|
|
@@ -2,10 +2,10 @@ export { MissingTranslationError, MissingTranslationPlaceholderError, createLoca
|
|
|
2
2
|
export { Localization } from './Localization.esnext';
|
|
3
3
|
export { useLocalizedFormatting } from './hooks/formatting.esnext';
|
|
4
4
|
export { useLocale } from './hooks/locale.esnext';
|
|
5
|
-
export { useLocaleFromEnvironment } from './hooks/locale-from-environment.esnext';
|
|
6
5
|
export { LocalizedFormattingContext } from './context.esnext';
|
|
7
6
|
export { LocalizedLink } from './routing/LocalizedLink.esnext';
|
|
8
|
-
export {
|
|
7
|
+
export { LocalizedNavigation } from './routing/LocalizedNavigation.esnext';
|
|
8
|
+
export { LocalizedRouter } from './routing/LocalizedRouter.esnext';
|
|
9
9
|
export { useRouteLocalization } from './routing/context.esnext';
|
|
10
10
|
export { createRouteLocalization } from './routing/localization/by-locale.esnext';
|
|
11
11
|
export { createRoutePathLocalization } from './routing/localization/by-path.esnext';
|
|
@@ -5,7 +5,7 @@ function createRequestRouterLocalization({
|
|
|
5
5
|
localization,
|
|
6
6
|
requestLocale: customRequestLocale
|
|
7
7
|
}) {
|
|
8
|
-
const { matchLocale,
|
|
8
|
+
const { matchLocale, redirectURL, defaultLocale, localeFromURL } = localization;
|
|
9
9
|
const getDefaultLocaleFromRequest = (request) => {
|
|
10
10
|
const acceptLanguage = request.headers.get("Accept-Language");
|
|
11
11
|
return acceptLanguage && parseAcceptLanguageHeader(acceptLanguage) || void 0;
|
|
@@ -16,7 +16,7 @@ function createRequestRouterLocalization({
|
|
|
16
16
|
...options
|
|
17
17
|
}) {
|
|
18
18
|
return new RedirectResponse(
|
|
19
|
-
|
|
19
|
+
redirectURL(new URL(request.url), { to }),
|
|
20
20
|
options
|
|
21
21
|
);
|
|
22
22
|
}
|
|
@@ -24,10 +24,9 @@ function createRequestRouterLocalization({
|
|
|
24
24
|
redirect: localeRedirect,
|
|
25
25
|
localizedRequestHandler(handler, { include = () => true } = {}) {
|
|
26
26
|
return async (request, ...args) => {
|
|
27
|
-
if (!include(request))
|
|
28
|
-
return handler(request, ...args);
|
|
27
|
+
if (!include(request)) return handler(request, ...args);
|
|
29
28
|
const url = new URL(request.url);
|
|
30
|
-
const urlLocale =
|
|
29
|
+
const urlLocale = localeFromURL(url);
|
|
31
30
|
const requestLocale = getLocaleForRequest(
|
|
32
31
|
request,
|
|
33
32
|
() => getDefaultLocaleFromRequest(request)
|
|
@@ -35,7 +34,7 @@ function createRequestRouterLocalization({
|
|
|
35
34
|
const matchedLocale = (requestLocale == null ? void 0 : matchLocale(requestLocale)) ?? defaultLocale;
|
|
36
35
|
if (urlLocale !== matchedLocale) {
|
|
37
36
|
return new RedirectResponse(
|
|
38
|
-
|
|
37
|
+
redirectURL(url, {
|
|
39
38
|
to: matchedLocale
|
|
40
39
|
})
|
|
41
40
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'preact/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'preact/hooks';
|
|
3
|
-
import { useRouter,
|
|
3
|
+
import { useRouter, useCurrentURL, Link } from '@quilted/preact-router';
|
|
4
4
|
import { useRouteLocalization } from './context.esnext';
|
|
5
5
|
|
|
6
6
|
function LocalizedLink({
|
|
@@ -9,13 +9,13 @@ function LocalizedLink({
|
|
|
9
9
|
...props
|
|
10
10
|
}) {
|
|
11
11
|
const router = useRouter();
|
|
12
|
-
const
|
|
13
|
-
const {
|
|
14
|
-
const
|
|
15
|
-
() =>
|
|
16
|
-
[to,
|
|
12
|
+
const url = useCurrentURL();
|
|
13
|
+
const { redirectURL } = useRouteLocalization();
|
|
14
|
+
const resolvedURL = useMemo(
|
|
15
|
+
() => redirectURL(to ? router.resolve(to).url : url, { to: locale }),
|
|
16
|
+
[to, url, locale, redirectURL, router]
|
|
17
17
|
);
|
|
18
|
-
return /* @__PURE__ */ jsx(Link, { hrefLang: locale, to:
|
|
18
|
+
return /* @__PURE__ */ jsx(Link, { hrefLang: locale, to: resolvedURL, ...props });
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export { LocalizedLink };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx } from 'preact/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'preact/hooks';
|
|
3
|
+
import { useBrowserDetails } from '@quilted/preact-browser';
|
|
4
|
+
import { Navigation } from '@quilted/preact-router';
|
|
5
|
+
import { Localization } from '../Localization.esnext';
|
|
6
|
+
import { LocalizedRouter } from './LocalizedRouter.esnext';
|
|
7
|
+
import { RouteLocalizationContext } from './context.esnext';
|
|
8
|
+
|
|
9
|
+
function LocalizedNavigation({
|
|
10
|
+
locale: explicitLocale,
|
|
11
|
+
router,
|
|
12
|
+
routes,
|
|
13
|
+
context,
|
|
14
|
+
localization,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
const browser = useBrowserDetails({ optional: true });
|
|
18
|
+
const resolvedRouter = useMemo(
|
|
19
|
+
() => router ?? new LocalizedRouter(browser?.request.url, { localization }),
|
|
20
|
+
[router]
|
|
21
|
+
);
|
|
22
|
+
const resolvedLocalization = resolvedRouter.localization;
|
|
23
|
+
const localeFromEnvironment = browser?.locale.value;
|
|
24
|
+
let resolvedLocale;
|
|
25
|
+
if (explicitLocale) {
|
|
26
|
+
resolvedLocale = explicitLocale;
|
|
27
|
+
} else if (localeFromEnvironment != null && localeFromEnvironment.toLowerCase().startsWith(resolvedLocalization.locale.toLowerCase())) {
|
|
28
|
+
resolvedLocale = localeFromEnvironment;
|
|
29
|
+
} else {
|
|
30
|
+
resolvedLocale = resolvedLocalization.locale;
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsx(Localization, { locale: resolvedLocale, children: /* @__PURE__ */ jsx(RouteLocalizationContext.Provider, { value: resolvedLocalization, children: /* @__PURE__ */ jsx(Navigation, { router: resolvedRouter, routes, context, children }) }) });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { LocalizedNavigation };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Router } from '@quilted/preact-router';
|
|
2
|
+
|
|
3
|
+
class LocalizedRouter extends Router {
|
|
4
|
+
localization;
|
|
5
|
+
constructor(initial, {
|
|
6
|
+
localization,
|
|
7
|
+
isExternal: explicitIsExternal
|
|
8
|
+
}) {
|
|
9
|
+
const { localeFromURL } = localization;
|
|
10
|
+
super(initial, {
|
|
11
|
+
isExternal(url, currentURL2) {
|
|
12
|
+
return matchedLocale !== localeFromURL(url) || (explicitIsExternal?.(url, currentURL2) ?? false);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const currentURL = this.currentRequest.url;
|
|
16
|
+
const matchedLocale = localeFromURL(currentURL);
|
|
17
|
+
const resolvedLocalization = {
|
|
18
|
+
locale: matchedLocale ?? localization.defaultLocale,
|
|
19
|
+
...localization
|
|
20
|
+
};
|
|
21
|
+
this.localization = resolvedLocalization;
|
|
22
|
+
const { pathname: rootPath } = localization.redirectURL(
|
|
23
|
+
new URL("/", currentURL),
|
|
24
|
+
{
|
|
25
|
+
to: resolvedLocalization.locale
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
if (rootPath.length > 1) Object.assign(this, { base: rootPath });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { LocalizedRouter };
|
|
@@ -8,9 +8,9 @@ function createRouteLocalization({
|
|
|
8
8
|
const locales = [...localeMap.keys()].sort((a, b) => b.length - a.length);
|
|
9
9
|
return {
|
|
10
10
|
locales,
|
|
11
|
-
|
|
11
|
+
redirectURL,
|
|
12
12
|
matchLocale,
|
|
13
|
-
|
|
13
|
+
localeFromURL,
|
|
14
14
|
defaultLocale
|
|
15
15
|
};
|
|
16
16
|
function matchLocale(requestLocale) {
|
|
@@ -19,24 +19,21 @@ function createRouteLocalization({
|
|
|
19
19
|
(locale) => locale === requestLocale || locale === language
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function localeFromURL(url) {
|
|
23
23
|
const hostname = url.hostname.toLowerCase();
|
|
24
24
|
const pathname = normalizePath(url.pathname.toLowerCase());
|
|
25
25
|
for (const [locale, target] of sortedLocaleMap) {
|
|
26
26
|
if (target.startsWith("/")) {
|
|
27
|
-
if (pathname.startsWith(target))
|
|
28
|
-
return locale;
|
|
27
|
+
if (pathname.startsWith(target)) return locale;
|
|
29
28
|
} else {
|
|
30
|
-
if (hostname === target)
|
|
31
|
-
return locale;
|
|
29
|
+
if (hostname === target) return locale;
|
|
32
30
|
}
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
|
-
function
|
|
36
|
-
const fromLocale =
|
|
33
|
+
function redirectURL(from, { to: toLocale }) {
|
|
34
|
+
const fromLocale = localeFromURL(from);
|
|
37
35
|
const toUrl = new URL(from);
|
|
38
|
-
if (fromLocale === toLocale)
|
|
39
|
-
return toUrl;
|
|
36
|
+
if (fromLocale === toLocale) return toUrl;
|
|
40
37
|
const target = localeMap.get(toLocale) ?? localeMap.get(defaultLocale);
|
|
41
38
|
if (target.startsWith("/")) {
|
|
42
39
|
const fromTarget = fromLocale == null ? "/" : localeMap.get(fromLocale) ?? "/";
|
|
@@ -50,8 +47,7 @@ function createRouteLocalization({
|
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
function normalizePath(path) {
|
|
53
|
-
if (path.length === 0)
|
|
54
|
-
return "/";
|
|
50
|
+
if (path.length === 0) return "/";
|
|
55
51
|
return path.endsWith("/") && path.length > 1 ? path.slice(0, -1) : path;
|
|
56
52
|
}
|
|
57
53
|
|