nuxt-i18n-micro 3.30.3 → 4.0.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 +1 -1
- package/README.md +2 -2
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/BVna_KKx.js +3 -0
- package/dist/client/_nuxt/Bw81RhAv.js +1 -0
- package/dist/client/_nuxt/CPz_jhsD.js +1 -0
- package/dist/client/_nuxt/CmvObVGq.js +1 -0
- package/dist/client/_nuxt/DKUOBR6F.js +5 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/f0c8d4bf-40d2-4915-8b4a-ebe46bde61c8.json +1 -0
- package/dist/client/_nuxt/{entry.BM-mexAv.css → entry.PSWtHhay.css} +1 -1
- package/dist/client/_nuxt/error-404.xs3fxhVJ.css +1 -0
- package/dist/client/_nuxt/error-500.C2S-4iLg.css +1 -0
- package/dist/client/index.html +1 -1
- package/dist/module.d.mts +14 -5
- package/dist/module.json +4 -1
- package/dist/module.mjs +850 -475
- package/dist/runtime/components/i18n-group.d.vue.ts +17 -9
- package/dist/runtime/components/i18n-group.vue +2 -4
- package/dist/runtime/components/i18n-group.vue.d.ts +17 -9
- package/dist/runtime/components/i18n-link.d.vue.ts +9 -6
- package/dist/runtime/components/i18n-link.vue +7 -28
- package/dist/runtime/components/i18n-link.vue.d.ts +9 -6
- package/dist/runtime/components/i18n-switcher.d.vue.ts +128 -54
- package/dist/runtime/components/i18n-switcher.vue +56 -156
- package/dist/runtime/components/i18n-switcher.vue.d.ts +128 -54
- package/dist/runtime/components/i18n-t.d.vue.ts +59 -116
- package/dist/runtime/components/i18n-t.vue +24 -71
- package/dist/runtime/components/i18n-t.vue.d.ts +59 -116
- package/dist/runtime/composables/useI18n.js +2 -38
- package/dist/runtime/composables/useI18nHead.js +21 -6
- package/dist/runtime/composables/useI18nLocale.d.ts +4 -1
- package/dist/runtime/composables/useI18nLocale.js +20 -22
- package/dist/runtime/composables/useLocaleHead.d.ts +26 -31
- package/dist/runtime/composables/useLocaleHead.js +47 -167
- package/dist/runtime/devtools/bridge.d.ts +2 -2
- package/dist/runtime/devtools/vue-devtools.d.ts +2 -2
- package/dist/runtime/devtools/vue-devtools.js +5 -5
- package/dist/runtime/middleware/i18n-redirect.global.d.ts +3 -2
- package/dist/runtime/middleware/i18n-redirect.global.js +30 -41
- package/dist/runtime/plugins/01.plugin.d.ts +156 -34
- package/dist/runtime/plugins/01.plugin.js +184 -138
- package/dist/runtime/plugins/02.meta.js +36 -43
- package/dist/runtime/plugins/04.vue-devtools.js +1 -1
- package/dist/runtime/plugins/06.redirect.d.ts +3 -3
- package/dist/runtime/plugins/06.redirect.js +65 -91
- package/dist/runtime/server/{utils → internal}/dev-live-translations.js +4 -3
- package/dist/runtime/server/internal/server-translation-cache.d.ts +9 -0
- package/dist/runtime/server/internal/server-translation-cache.js +10 -0
- package/dist/runtime/server/internal/shared-cache.d.ts +24 -0
- package/dist/runtime/server/internal/shared-cache.js +71 -0
- package/dist/runtime/server/internal/translation-watcher.d.ts +79 -0
- package/dist/runtime/server/internal/translation-watcher.js +105 -0
- package/dist/runtime/server/middleware/i18n.global.js +24 -37
- package/dist/runtime/server/payload-source.assets.d.ts +1 -0
- package/dist/runtime/server/payload-source.assets.js +3 -8
- package/dist/runtime/server/payload-source.fs.d.ts +1 -0
- package/dist/runtime/server/payload-source.fs.js +18 -7
- package/dist/runtime/server/plugins/failed-read.d.ts +7 -0
- package/dist/runtime/server/plugins/failed-read.js +23 -0
- package/dist/runtime/server/plugins/payload-cache.d.ts +6 -0
- package/dist/runtime/server/plugins/payload-cache.js +16 -0
- package/dist/runtime/server/plugins/watcher.dev.js +15 -79
- package/dist/runtime/server/routes/i18n.js +13 -14
- package/dist/runtime/server/utils/locale-detector.d.ts +32 -2
- package/dist/runtime/server/utils/locale-detector.js +48 -27
- package/dist/runtime/server/utils/locale-server-middleware.js +14 -33
- package/dist/runtime/server/utils/payload-cache.d.ts +4 -0
- package/dist/runtime/server/utils/payload-cache.js +13 -0
- package/dist/runtime/server/utils/server-loader.d.ts +17 -6
- package/dist/runtime/server/utils/server-loader.js +105 -51
- package/dist/runtime/server/utils/translation-server-middleware.js +18 -35
- package/dist/runtime/utils/cache-keys.d.ts +6 -0
- package/dist/runtime/utils/cache-keys.js +2 -0
- package/dist/runtime/utils/i18n-api.d.ts +185 -0
- package/dist/runtime/utils/i18n-api.js +196 -0
- package/dist/runtime/utils/i18n-config.d.ts +18 -0
- package/dist/runtime/utils/i18n-config.js +47 -0
- package/dist/runtime/utils/i18n-navigation.d.ts +26 -0
- package/dist/runtime/utils/i18n-navigation.js +96 -0
- package/dist/runtime/utils/nuxt-i18n-server.d.ts +26 -0
- package/dist/runtime/utils/nuxt-i18n-server.js +83 -0
- package/dist/runtime/utils/nuxt-i18n.d.ts +81 -96
- package/dist/runtime/utils/nuxt-i18n.js +180 -252
- package/dist/runtime/utils/page-head.d.ts +12 -0
- package/dist/runtime/utils/page-head.js +6 -0
- package/dist/runtime/utils/request-url.d.ts +6 -0
- package/dist/runtime/utils/request-url.js +11 -0
- package/dist/runtime/utils/storage.d.ts +31 -19
- package/dist/runtime/utils/storage.js +100 -49
- package/dist/runtime/utils/translation-entry.d.ts +6 -0
- package/dist/runtime/utils/translation-entry.js +16 -0
- package/dist/types.d.mts +4 -6
- package/internals.d.mts +9 -2
- package/package.json +78 -79
- package/dist/client/_nuxt/BOxWElQP.js +0 -21
- package/dist/client/_nuxt/CUWB4CwN.js +0 -3
- package/dist/client/_nuxt/CmUbe-uv.js +0 -1
- package/dist/client/_nuxt/DAzShkZF.js +0 -1
- package/dist/client/_nuxt/MokPP5zi.js +0 -1
- package/dist/client/_nuxt/builds/meta/60974e48-d00e-4f9b-9467-9d4b322519da.json +0 -1
- package/dist/client/_nuxt/error-404.D9Svp6Hk.css +0 -1
- package/dist/client/_nuxt/error-500.B-mjI9_9.css +0 -1
- package/dist/runtime/plugins/03.define.d.ts +0 -7
- package/dist/runtime/plugins/03.define.js +0 -42
- package/dist/runtime/plugins/05.hooks.d.ts +0 -2
- package/dist/runtime/plugins/05.hooks.js +0 -47
- package/dist/runtime/server/utils/server-translation-cache.d.ts +0 -11
- package/dist/runtime/server/utils/server-translation-cache.js +0 -20
- /package/dist/runtime/server/{utils → internal}/dev-live-translations.d.ts +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isNoPrefixStrategy } from "@i18n-micro/core";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { resolveOgLocale, warnUnresolvedOgLocale } from "@i18n-micro/utils/resolve-og-locale";
|
|
5
|
-
import { joinURL, parseURL, withQuery } from "ufo";
|
|
2
|
+
import { buildLocaleHead, filterQuery } from "@i18n-micro/utils/locale-head";
|
|
3
|
+
import { joinURL } from "ufo";
|
|
6
4
|
import { ref, unref, watch } from "vue";
|
|
7
|
-
import {
|
|
5
|
+
import { useError } from "#app/composables/error";
|
|
6
|
+
import { useRoute } from "#app/composables/router";
|
|
7
|
+
import { useState } from "#app/composables/state";
|
|
8
|
+
import { useNuxtApp } from "#app/nuxt";
|
|
8
9
|
import { applyTrailingSlash } from "../utils/trailing-slash.js";
|
|
9
10
|
export const useLocaleHead = ({
|
|
10
11
|
addDirAttribute = true,
|
|
@@ -15,181 +16,60 @@ export const useLocaleHead = ({
|
|
|
15
16
|
} = {}) => {
|
|
16
17
|
const nuxtApp = useNuxtApp();
|
|
17
18
|
const route = useRoute();
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
function filterQuery(fullPath, whitelist) {
|
|
24
|
-
const { pathname, search } = parseURL(fullPath);
|
|
25
|
-
const params = new URLSearchParams(search);
|
|
26
|
-
const filtered = {};
|
|
27
|
-
for (const key of whitelist) {
|
|
28
|
-
if (params.has(key)) {
|
|
29
|
-
filtered[key] = params.get(key);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return withQuery(pathname, filtered);
|
|
33
|
-
}
|
|
34
|
-
function filterLocalizedHref(pathOrUrl, whitelist) {
|
|
35
|
-
if (!pathOrUrl) return "";
|
|
36
|
-
const parsed = parseURL(pathOrUrl);
|
|
37
|
-
const filteredPath = filterQuery(pathOrUrl, whitelist);
|
|
38
|
-
if (parsed.protocol && parsed.host) {
|
|
39
|
-
return `${parsed.protocol}//${parsed.host}${filteredPath}`;
|
|
40
|
-
}
|
|
41
|
-
return filteredPath;
|
|
42
|
-
}
|
|
43
|
-
function clearMeta() {
|
|
44
|
-
metaObject.value = { htmlAttrs: {}, link: [], meta: [] };
|
|
45
|
-
}
|
|
46
|
-
function updateMeta() {
|
|
47
|
-
if (route.matched.length === 0 || route.matched.some((record) => record.name === "custom-fallback-route")) {
|
|
48
|
-
clearMeta();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
19
|
+
const error = useError();
|
|
20
|
+
const empty = () => ({ htmlAttrs: {}, link: [], meta: [] });
|
|
21
|
+
const metaObject = ref(empty());
|
|
22
|
+
function build() {
|
|
51
23
|
const i18nConfig = nuxtApp.$getI18nConfig();
|
|
52
|
-
const { canonicalQueryWhitelist,
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const firstSegment = route.path.replace(/^\//, "").split("/").filter(Boolean)[0];
|
|
58
|
-
const fallbackLocale = allLocales.find((loc) => loc.code === firstSegment)?.code || i18nConfig.defaultLocale || "en";
|
|
59
|
-
const locale = ($getLocale ? unref($getLocale()) : fallbackLocale) || fallbackLocale;
|
|
24
|
+
const { canonicalQueryWhitelist, strategy, trailingSlash } = i18nConfig;
|
|
25
|
+
const { $getLocale, $switchLocalePath } = nuxtApp;
|
|
26
|
+
const i18nStrategy = nuxtApp.$i18nStrategy;
|
|
27
|
+
const allLocales = nuxtApp.$getLocales();
|
|
28
|
+
const locale = $getLocale() || i18nConfig.defaultLocale;
|
|
60
29
|
const currentLocale = allLocales.find((loc) => loc.code === locale);
|
|
61
|
-
if (!currentLocale
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
const switchLocalePath = $switchLocalePath || (() => "");
|
|
66
|
-
const routeName = (route.name ?? "").toString();
|
|
67
|
-
const currentRouteLocales = findAllowedLocalesForRoute(route, routeLocales, localizedRouteNamePrefixResolved);
|
|
30
|
+
if (!currentLocale) return empty();
|
|
31
|
+
const metaDisabled = i18nStrategy.isMetaDisabled(route, locale);
|
|
32
|
+
const pageLocales = i18nStrategy.pageLocales(route);
|
|
68
33
|
const enabledLocales = allLocales.filter((loc) => !loc.disabled);
|
|
69
|
-
const locales =
|
|
70
|
-
const currentIso = currentLocale.iso || locale;
|
|
71
|
-
const currentOg = resolveOgLocale(currentLocale);
|
|
72
|
-
const missingWarn = i18nConfig.missingWarn ?? true;
|
|
73
|
-
const currentDir = currentLocale.dir || "auto";
|
|
74
|
-
let fullPath = unref(route.fullPath);
|
|
75
|
-
if (!fullPath.startsWith("/")) {
|
|
76
|
-
fullPath = `/${fullPath}`;
|
|
77
|
-
}
|
|
78
|
-
const whitelist = canonicalQueryWhitelist ?? [];
|
|
79
|
-
const trailingSlash = i18nConfig.trailingSlash;
|
|
34
|
+
const locales = pageLocales ? enabledLocales.filter((loc) => pageLocales.includes(loc.code)) : [];
|
|
80
35
|
const toSeoHref = (pathOrUrl) => {
|
|
81
36
|
if (!pathOrUrl) return "";
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
const filteredPath = filterLocalizedHref(pathOrUrl, whitelist);
|
|
87
|
-
href = joinURL(unref(baseUrl), filteredPath.startsWith("/") ? filteredPath : `/${filteredPath}`);
|
|
88
|
-
}
|
|
89
|
-
return applyTrailingSlash(href, trailingSlash);
|
|
90
|
-
};
|
|
91
|
-
const currentSwitchedPath = switchLocalePath(locale);
|
|
92
|
-
let ogUrl;
|
|
93
|
-
if (currentSwitchedPath) {
|
|
94
|
-
ogUrl = toSeoHref(currentSwitchedPath);
|
|
95
|
-
} else {
|
|
96
|
-
const matchedLocale = [...locales].sort((a, b) => b.code.length - a.code.length).find((localeItem) => fullPath.startsWith(`/${localeItem.code}`));
|
|
97
|
-
let localizedPath = fullPath;
|
|
98
|
-
if (routeName.startsWith(localizedRouteNamePrefixResolved) && matchedLocale) {
|
|
99
|
-
localizedPath = fullPath.slice(matchedLocale.code.length + 1);
|
|
100
|
-
ogUrl = applyTrailingSlash(joinURL(unref(baseUrl), locale, filterQuery(localizedPath, whitelist)), trailingSlash);
|
|
101
|
-
} else {
|
|
102
|
-
ogUrl = applyTrailingSlash(joinURL(unref(baseUrl), filterQuery(fullPath, whitelist)), trailingSlash);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
const htmlAttrs = {
|
|
106
|
-
lang: currentIso,
|
|
107
|
-
...addDirAttribute ? { dir: currentDir } : {}
|
|
37
|
+
const filtered = filterQuery(pathOrUrl, canonicalQueryWhitelist);
|
|
38
|
+
const absolute = filtered.startsWith("http://") || filtered.startsWith("https://");
|
|
39
|
+
return applyTrailingSlash(absolute ? filtered : joinURL(unref(baseUrl), filtered.startsWith("/") ? filtered : `/${filtered}`), trailingSlash);
|
|
108
40
|
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
const localesForSeo = locales.filter((loc) => loc.seo !== false);
|
|
114
|
-
if (!currentOg) {
|
|
115
|
-
warnUnresolvedOgLocale(currentLocale, { missingWarn, tag: "og:locale" });
|
|
116
|
-
}
|
|
117
|
-
const ogLocaleMeta = currentOg ? {
|
|
118
|
-
[identifierAttribute]: "i18n-og",
|
|
119
|
-
property: "og:locale",
|
|
120
|
-
content: currentOg
|
|
121
|
-
} : null;
|
|
122
|
-
const ogUrlMeta = {
|
|
123
|
-
[identifierAttribute]: "i18n-og-url",
|
|
124
|
-
property: "og:url",
|
|
125
|
-
content: ogUrl
|
|
126
|
-
};
|
|
127
|
-
const alternateOgLocalesMeta = localesForSeo.filter((loc) => loc.code !== locale).map((loc) => {
|
|
128
|
-
const ogAlt = resolveOgLocale(loc);
|
|
129
|
-
if (!ogAlt) {
|
|
130
|
-
warnUnresolvedOgLocale(loc, { missingWarn, tag: "og:locale:alternate" });
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
[identifierAttribute]: `i18n-og-alt-${ogAlt}`,
|
|
135
|
-
property: "og:locale:alternate",
|
|
136
|
-
content: ogAlt
|
|
137
|
-
};
|
|
138
|
-
}).filter((meta) => meta !== null);
|
|
139
|
-
const canonicalLink = {
|
|
140
|
-
[identifierAttribute]: "i18n-can",
|
|
141
|
-
rel: "canonical",
|
|
142
|
-
href: ogUrl
|
|
143
|
-
};
|
|
144
|
-
const defaultLocale = i18nConfig.defaultLocale || "en";
|
|
41
|
+
const hrefOf = (code) => toSeoHref($switchLocalePath(code));
|
|
42
|
+
const defaultLocale = i18nConfig.linkDefaultLocale ?? i18nConfig.defaultLocale;
|
|
145
43
|
const defaultLocaleObj = allLocales.find((loc) => loc.code === defaultLocale);
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
})();
|
|
168
|
-
let xDefaultLink = null;
|
|
169
|
-
if (!isNoPrefixStrategy(strategy) && defaultLocaleObj?.seo !== false) {
|
|
170
|
-
const defaultSwitchedPath = switchLocalePath(defaultLocale);
|
|
171
|
-
if (defaultSwitchedPath) {
|
|
172
|
-
xDefaultLink = {
|
|
173
|
-
[identifierAttribute]: "i18n-xd",
|
|
174
|
-
rel: "alternate",
|
|
175
|
-
href: toSeoHref(defaultSwitchedPath),
|
|
176
|
-
hreflang: "x-default"
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
metaObject.value = {
|
|
181
|
-
htmlAttrs,
|
|
182
|
-
meta: [...ogLocaleMeta ? [ogLocaleMeta] : [], ogUrlMeta, ...alternateOgLocalesMeta],
|
|
183
|
-
link: [canonicalLink, ...alternateLinks, ...xDefaultLink ? [xDefaultLink] : []]
|
|
184
|
-
};
|
|
44
|
+
const noPrefix = isNoPrefixStrategy(strategy);
|
|
45
|
+
const hasXDefault = !noPrefix && defaultLocaleObj?.seo !== false && pageLocales?.includes(defaultLocale);
|
|
46
|
+
return buildLocaleHead({
|
|
47
|
+
locale: currentLocale,
|
|
48
|
+
// omit `seo: false`
|
|
49
|
+
seoLocales: locales.filter((loc) => loc.seo !== false),
|
|
50
|
+
hrefOf,
|
|
51
|
+
// canonical / og:url share `$switchLocalePath` with hreflang (incl. NuxtLink trailingSlash)
|
|
52
|
+
canonical: toSeoHref($switchLocalePath(locale) || route.fullPath),
|
|
53
|
+
xDefault: hasXDefault ? hrefOf(defaultLocale) : void 0,
|
|
54
|
+
alternates: !noPrefix,
|
|
55
|
+
addDirAttribute,
|
|
56
|
+
// 404 routes and disableMeta keep the language, but must not emit SEO tags: a 404 the module answers has a matched record
|
|
57
|
+
addSeoAttributes: addSeoAttributes && !metaDisabled && route.matched.length > 0 && !error.value,
|
|
58
|
+
identifierAttribute,
|
|
59
|
+
hreflangBaseLanguage: i18nConfig.hreflangBaseLanguage,
|
|
60
|
+
missingWarn: i18nConfig.missingWarn
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function updateMeta() {
|
|
64
|
+
metaObject.value = build();
|
|
185
65
|
}
|
|
186
66
|
if (autoUpdate) {
|
|
187
67
|
const localeState = useState("i18n-locale", () => null);
|
|
188
68
|
watch(
|
|
189
|
-
() => [route.fullPath, route.name, route.matched.length, localeState.value],
|
|
69
|
+
() => [route.fullPath, route.name, route.matched.length, localeState.value, error.value],
|
|
190
70
|
() => updateMeta(),
|
|
191
71
|
{ immediate: true }
|
|
192
72
|
);
|
|
193
73
|
}
|
|
194
|
-
return { metaObject, updateMeta };
|
|
74
|
+
return { metaObject, updateMeta, build };
|
|
195
75
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResolvedI18nConfig } from '@i18n-micro/types';
|
|
2
2
|
import type { Ref } from 'vue';
|
|
3
3
|
import type { NuxtI18n } from '../utils/nuxt-i18n.js';
|
|
4
4
|
export declare const I18N_DEVTOOLS_BRIDGE_KEY = "i18n-micro-devtools-bridge";
|
|
5
5
|
export interface I18nDevtoolsBridge {
|
|
6
6
|
i18n: NuxtI18n;
|
|
7
|
-
i18nConfig:
|
|
7
|
+
i18nConfig: ResolvedI18nConfig;
|
|
8
8
|
localeState: Ref<string | null>;
|
|
9
9
|
}
|
|
10
10
|
export declare function setI18nDevtoolsBridge(value: I18nDevtoolsBridge | null): void;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResolvedI18nConfig } from '@i18n-micro/types';
|
|
2
2
|
import type { App } from 'vue';
|
|
3
3
|
import type { I18nContextChangeReason, NuxtI18n } from '../utils/nuxt-i18n.js';
|
|
4
4
|
export interface VueI18nDevtoolsContext {
|
|
5
5
|
app: App;
|
|
6
6
|
i18n: NuxtI18n;
|
|
7
|
-
i18nConfig:
|
|
7
|
+
i18nConfig: ResolvedI18nConfig;
|
|
8
8
|
onContextChange: (listener: (reason: I18nContextChangeReason) => void) => () => void;
|
|
9
9
|
onMissingKey: (listener: (locale: string, key: string, routeName: string) => void) => () => void;
|
|
10
10
|
}
|
|
@@ -22,7 +22,7 @@ function toInspectorState(snapshot) {
|
|
|
22
22
|
}
|
|
23
23
|
function createSnapshot(i18n, i18nConfig) {
|
|
24
24
|
return {
|
|
25
|
-
locale: i18n.
|
|
25
|
+
locale: i18n.getLocale(),
|
|
26
26
|
routeName: i18n.getCurrentRouteName() || "index",
|
|
27
27
|
strategy: i18nConfig.strategy,
|
|
28
28
|
defaultLocale: i18nConfig.defaultLocale,
|
|
@@ -61,7 +61,7 @@ function buildNodeState(i18n, i18nConfig, nodeId) {
|
|
|
61
61
|
{ key: "code", value: locale },
|
|
62
62
|
{ key: "displayName", value: configured?.displayName ?? locale },
|
|
63
63
|
{ key: "disabled", value: Boolean(configured?.disabled) },
|
|
64
|
-
{ key: "isActive", value: i18n.
|
|
64
|
+
{ key: "isActive", value: i18n.getLocale() === locale },
|
|
65
65
|
{ key: "loadedChunks", value: chunks.length }
|
|
66
66
|
],
|
|
67
67
|
Chunks: chunks.length ? chunks : [{ key: "\u2014", value: "No translation chunks loaded for this locale yet" }]
|
|
@@ -86,7 +86,7 @@ function buildNodeState(i18n, i18nConfig, nodeId) {
|
|
|
86
86
|
{ key: "keys", value: countTranslationKeys(chunk) },
|
|
87
87
|
{
|
|
88
88
|
key: "isActive",
|
|
89
|
-
value: i18n.
|
|
89
|
+
value: i18n.getLocale() === parsed.locale && (i18n.getCurrentRouteName() || "index") === routeName
|
|
90
90
|
}
|
|
91
91
|
],
|
|
92
92
|
Translations: entries.length ? entries : [{ key: "\u2014", value: "Chunk is loaded but empty" }]
|
|
@@ -96,7 +96,7 @@ function buildNodeState(i18n, i18nConfig, nodeId) {
|
|
|
96
96
|
const routeName = parsed.routeName || "index";
|
|
97
97
|
const segments = parsed.segments ?? [];
|
|
98
98
|
const chunk = i18n.storage.translations.get(`${parsed.locale}:${routeName}`);
|
|
99
|
-
const isActive = i18n.
|
|
99
|
+
const isActive = i18n.getLocale() === parsed.locale && (i18n.getCurrentRouteName() || "index") === routeName;
|
|
100
100
|
const source = isActive ? i18n.resolveTranslations() : chunk ?? {};
|
|
101
101
|
const value = segments.length ? getByInspectorPath(source, segments) : source;
|
|
102
102
|
if (isPlainObject(value)) {
|
|
@@ -186,7 +186,7 @@ export async function setupVueI18nDevtools(ctx) {
|
|
|
186
186
|
nodeId: "root",
|
|
187
187
|
storage: ctx.i18n.storage,
|
|
188
188
|
configuredLocales: ctx.i18nConfig.locales ?? [],
|
|
189
|
-
activeLocale: ctx.i18n.
|
|
189
|
+
activeLocale: ctx.i18n.getLocale(),
|
|
190
190
|
activeRouteName: ctx.i18n.getCurrentRouteName() || "index",
|
|
191
191
|
activeTranslations: ctx.i18n.resolveTranslations()
|
|
192
192
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Client-side locale
|
|
3
|
-
*
|
|
2
|
+
* Client-side locale redirects (SPA navigations). The decision is the strategy's
|
|
3
|
+
* (`getClientRedirect`); preferences are read from the locale state and the cookie the main
|
|
4
|
+
* plugin keeps, without creating cookie refs per navigation.
|
|
4
5
|
*/
|
|
5
6
|
declare const _default: import("nuxt/app").RouteMiddleware;
|
|
6
7
|
export default _default;
|
|
@@ -1,50 +1,39 @@
|
|
|
1
1
|
import { getEnabledLocaleCodes } from "@i18n-micro/utils/active-locales";
|
|
2
2
|
import { isInternalPath } from "@i18n-micro/utils/app-path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { decodeCookieValue, getPreferenceCookieName } from "@i18n-micro/utils/cookie";
|
|
4
|
+
import { redirectLocale } from "@i18n-micro/utils/resolve-locale";
|
|
5
|
+
import { applyTrailingSlash } from "../utils/trailing-slash.js";
|
|
6
|
+
import { defineNuxtRouteMiddleware, navigateTo, useNuxtApp, useState } from "#imports";
|
|
7
|
+
function readCookie(name) {
|
|
8
|
+
if (!name) return null;
|
|
9
|
+
const prefix = `${encodeURIComponent(name)}=`;
|
|
10
|
+
const entry = document.cookie.split("; ").find((part) => part.startsWith(prefix));
|
|
11
|
+
return entry ? decodeCookieValue(entry.slice(prefix.length)) : null;
|
|
8
12
|
}
|
|
9
13
|
export default defineNuxtRouteMiddleware((to, from) => {
|
|
10
14
|
if (import.meta.server) return;
|
|
11
15
|
const nuxtApp = useNuxtApp();
|
|
12
|
-
const getRuntimeConfig = nuxtApp
|
|
13
|
-
const i18nStrategy = nuxtApp.$i18nStrategy;
|
|
14
|
-
if (typeof getRuntimeConfig !== "function" || !i18nStrategy) return;
|
|
16
|
+
const { $getI18nConfig: getRuntimeConfig, $i18nStrategy: i18nStrategy } = nuxtApp;
|
|
15
17
|
const i18nConfig = getRuntimeConfig();
|
|
16
|
-
|
|
17
|
-
if (to.path
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const autoDetectPath = i18nConfig.autoDetectPath || "/";
|
|
22
|
-
const { getPreferredLocale } = useI18nLocale();
|
|
23
|
-
const routeLocale = i18nStrategy.getCurrentLocale(to, getPreferredLocale());
|
|
24
|
-
let preferredLocale = routeLocale || getPreferredLocale() || defaultLocale;
|
|
18
|
+
const samePage = to.path === from.path && nuxtApp.payload.serverRendered;
|
|
19
|
+
if (i18nConfig.redirects === false || samePage || isInternalPath(to.path, i18nConfig.excludePatterns, i18nConfig.apiBaseUrl)) return;
|
|
20
|
+
const defaultLocale = i18nConfig.defaultLocale;
|
|
21
|
+
const autoDetectPath = i18nConfig.autoDetectPath;
|
|
22
|
+
const anyPath = autoDetectPath === "*";
|
|
25
23
|
const path = to.path || "/";
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} else {
|
|
42
|
-
targetPath = rest ? `/${preferredLocale}/${rest}` : `/${preferredLocale}`;
|
|
43
|
-
}
|
|
44
|
-
return redirectTo(targetPath, to);
|
|
45
|
-
}
|
|
46
|
-
const redirectPath = i18nStrategy.getClientRedirect(path, preferredLocale);
|
|
47
|
-
if (redirectPath) {
|
|
48
|
-
return redirectTo(redirectPath, to);
|
|
49
|
-
}
|
|
24
|
+
const urlLocale = i18nStrategy.getLocaleFromPath(path);
|
|
25
|
+
if (urlLocale && !anyPath) return;
|
|
26
|
+
const preference = redirectLocale({
|
|
27
|
+
path,
|
|
28
|
+
urlLocale,
|
|
29
|
+
autoDetectPath,
|
|
30
|
+
alwaysPrefixed: i18nConfig.strategy === "prefix",
|
|
31
|
+
defaultLocale,
|
|
32
|
+
validLocales: getEnabledLocaleCodes(i18nConfig.locales),
|
|
33
|
+
state: useState("i18n-locale", () => null).value,
|
|
34
|
+
cookie: readCookie(getPreferenceCookieName(i18nConfig))
|
|
35
|
+
});
|
|
36
|
+
const preferred = i18nStrategy.getCurrentLocale(to, preference);
|
|
37
|
+
const target = i18nStrategy.getClientRedirect(path, preferred, { switchPrefixed: anyPath });
|
|
38
|
+
if (target) return navigateTo({ path: applyTrailingSlash(target, i18nConfig.trailingSlash), query: to.query, hash: to.hash }, { redirectCode: 302 });
|
|
50
39
|
});
|