nuxt-i18n-micro 3.30.2 → 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/f020fec8-462b-480b-82d8-6b0cb65617e8.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,65 +1,119 @@
|
|
|
1
1
|
import { isEnabledLocale } from "@i18n-micro/utils/active-locales";
|
|
2
|
-
import { normalizeConfiguredLocales, toPremergedStorageKey } from "@i18n-micro/utils/merge-source";
|
|
2
|
+
import { mergeOverRoot, normalizeConfiguredLocales, PREMERGED_ROOT_PAGE, toPremergedStorageKey } from "@i18n-micro/utils/merge-source";
|
|
3
3
|
import { fetchTranslationPayloadFromHost } from "@i18n-micro/utils/payload-fetch";
|
|
4
4
|
import { resolveTranslationPayloadPage } from "@i18n-micro/utils/payload-url";
|
|
5
|
-
import { resolveI18nConfigWithRuntimeOverrides } from "@i18n-micro/utils/runtime-config";
|
|
6
5
|
import { loadSourceTranslationsFromStorage } from "@i18n-micro/utils/source-loader";
|
|
7
6
|
import { toTranslations } from "@i18n-micro/utils/normalize";
|
|
8
|
-
import { readPayload } from "#i18n-internal/payload-source";
|
|
7
|
+
import { embeddedPayloads, readPayload } from "#i18n-internal/payload-source";
|
|
9
8
|
import { getI18nPrivateConfig } from "#i18n-internal/config";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { getOrCreateServerTranslationCache } from "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
import { loadLiveDevTranslations } from "../internal/dev-live-translations.js";
|
|
10
|
+
import { getI18nServerConfig } from "./locale-detector.js";
|
|
11
|
+
import { getOrCreateServerTranslationCache } from "../internal/server-translation-cache.js";
|
|
12
|
+
import { readSharedChunk, sharedChunkKey, writeSharedChunk } from "../internal/shared-cache.js";
|
|
13
|
+
import { takeRootMark, toEntry } from "../../utils/translation-entry.js";
|
|
14
|
+
const EMPTY = { data: {}, json: "{}" };
|
|
15
|
+
export const NO_FILE = { data: {}, json: "{}" };
|
|
16
|
+
const pending = /* @__PURE__ */ new Map();
|
|
17
|
+
const requestBoundIo = typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers";
|
|
18
|
+
function runtimeHost() {
|
|
19
|
+
try {
|
|
20
|
+
return process.env.NUXT_I18N_APP_BASE_SERVER_HOST;
|
|
21
|
+
} catch {
|
|
22
|
+
return void 0;
|
|
19
23
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
}
|
|
25
|
+
export function resolveServerHost() {
|
|
26
|
+
return runtimeHost() ?? getI18nPrivateConfig().apiBaseServerHost;
|
|
27
|
+
}
|
|
28
|
+
export async function loadTranslationsFromServer(locale, routeName) {
|
|
29
|
+
const config = getI18nServerConfig();
|
|
30
|
+
if (!isEnabledLocale(config.locales, locale)) return EMPTY;
|
|
31
|
+
const page = resolveTranslationPayloadPage(routeName, config.routesLocaleLinks || {});
|
|
32
|
+
if (import.meta.dev && !resolveServerHost()) return toEntry(await loadLiveDevTranslations(locale, page, config));
|
|
33
|
+
return cached(`${locale}:${page}`, () => readChunk(locale, page, config));
|
|
34
|
+
}
|
|
35
|
+
function cached(key, read) {
|
|
36
|
+
const cache = getOrCreateServerTranslationCache();
|
|
37
|
+
const hit = cache.get(key);
|
|
38
|
+
if (hit) return Promise.resolve(hit);
|
|
39
|
+
const inFlight = requestBoundIo && !isEmbeddedRead() ? void 0 : pending.get(key);
|
|
40
|
+
if (inFlight) return inFlight;
|
|
41
|
+
const promise = read().then(({ entry, shared }) => {
|
|
42
|
+
if (!shared) cache.set(key, entry);
|
|
43
|
+
return entry;
|
|
44
|
+
}).finally(() => pending.delete(key));
|
|
45
|
+
pending.set(key, promise);
|
|
46
|
+
return promise;
|
|
47
|
+
}
|
|
48
|
+
const isEmbeddedRead = () => embeddedPayloads && !resolveServerHost();
|
|
49
|
+
const rootChunk = (locale, config) => cached(`${locale}:${PREMERGED_ROOT_PAGE}`, () => readChunk(locale, PREMERGED_ROOT_PAGE, config));
|
|
50
|
+
function readChunk(locale, page, config) {
|
|
51
|
+
const key = isEmbeddedRead() ? null : sharedChunkKey(locale, page, config, resolveServerHost());
|
|
52
|
+
return key ? readThroughShared(key, locale, page, config) : load(locale, page, config);
|
|
53
|
+
}
|
|
54
|
+
async function readThroughShared(key, locale, page, config) {
|
|
55
|
+
const hit = await readSharedChunk(key);
|
|
56
|
+
if (hit) return { entry: hit };
|
|
57
|
+
const loaded = await load(locale, page, config);
|
|
58
|
+
const { entry, shared, partial, marked } = loaded;
|
|
59
|
+
if (entry === NO_FILE || partial) return loaded;
|
|
60
|
+
if (shared) return { entry };
|
|
61
|
+
const json = JSON.stringify(entry.data);
|
|
62
|
+
if (json === "{}") return { entry };
|
|
63
|
+
if (page === PREMERGED_ROOT_PAGE) {
|
|
64
|
+
await writeSharedChunk(key, json, config);
|
|
65
|
+
return { entry };
|
|
26
66
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
67
|
+
const root = await rootChunk(locale, config).catch(() => null);
|
|
68
|
+
if (!root || !Object.keys(root.data).length) return { entry };
|
|
69
|
+
if (!marked && JSON.stringify(root.data) === json) return { entry: root };
|
|
70
|
+
if (Object.keys(root.data).every((rootKey) => Object.hasOwn(entry.data, rootKey))) await writeSharedChunk(key, json, config);
|
|
71
|
+
return { entry };
|
|
72
|
+
}
|
|
73
|
+
function toEntryWithMark(data, mark) {
|
|
74
|
+
const entry = toEntry(data);
|
|
75
|
+
entry.mark = mark;
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
async function load(locale, page, config) {
|
|
79
|
+
const apiBaseServerHost = resolveServerHost();
|
|
80
|
+
if (apiBaseServerHost) {
|
|
81
|
+
const data = await fetchTranslationPayloadFromHost(
|
|
82
|
+
{ apiBaseUrl: config.apiBaseUrl, apiBaseServerHost, dateBuild: config.dateBuild },
|
|
32
83
|
locale,
|
|
33
|
-
|
|
84
|
+
page,
|
|
34
85
|
$fetch
|
|
35
86
|
);
|
|
36
|
-
|
|
37
|
-
const entry2 = { data: data2, json: json2 };
|
|
38
|
-
cc.set(cacheKey, entry2);
|
|
39
|
-
return entry2;
|
|
87
|
+
return data ? settle(locale, page, data, config) : { entry: NO_FILE, shared: true };
|
|
40
88
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
disablePageLocales: config.disablePageLocales
|
|
55
|
-
}
|
|
56
|
-
);
|
|
57
|
-
} else {
|
|
58
|
-
data = toTranslations(await readPayload(toPremergedStorageKey(resolvedPage, locale)));
|
|
59
|
-
}
|
|
89
|
+
if (config.translationPayloadMode === "source") {
|
|
90
|
+
const data = await loadSourceTranslationsFromStorage(
|
|
91
|
+
{ getItem: (key) => readPayload(key) },
|
|
92
|
+
{
|
|
93
|
+
locale,
|
|
94
|
+
pageName: page,
|
|
95
|
+
// a fallback may live on another domain: its file is still this build's
|
|
96
|
+
locales: normalizeConfiguredLocales(config.linkLocales ?? config.locales),
|
|
97
|
+
globalFallbackLocale: config.fallbackLocale,
|
|
98
|
+
disablePageLocales: config.disablePageLocales
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
return { entry: toEntry(data) };
|
|
60
102
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
103
|
+
const own = toTranslations(await readPayload(toPremergedStorageKey(page, locale)));
|
|
104
|
+
if (Object.keys(own).length || page === PREMERGED_ROOT_PAGE) return settle(locale, page, own, config);
|
|
105
|
+
return { entry: await rootChunk(locale, config), shared: true };
|
|
106
|
+
}
|
|
107
|
+
async function settle(locale, page, file, config) {
|
|
108
|
+
const mark = takeRootMark(file);
|
|
109
|
+
if (!mark) return { entry: toEntry(file) };
|
|
110
|
+
if (page === PREMERGED_ROOT_PAGE) return { entry: toEntryWithMark(file, mark) };
|
|
111
|
+
let root = await rootChunk(locale, config);
|
|
112
|
+
if (root.mark && root.mark !== mark) {
|
|
113
|
+
getOrCreateServerTranslationCache().delete(`${locale}:${PREMERGED_ROOT_PAGE}`);
|
|
114
|
+
root = await rootChunk(locale, config);
|
|
115
|
+
}
|
|
116
|
+
const merged = mergeOverRoot(root.data, file);
|
|
117
|
+
const entry = merged === root.data ? root : toEntry(merged);
|
|
118
|
+
return root === NO_FILE ? { entry, shared: true, partial: true } : { entry, marked: true };
|
|
65
119
|
}
|
|
@@ -1,44 +1,27 @@
|
|
|
1
1
|
import { interpolate, resolveTranslation } from "@i18n-micro/core";
|
|
2
|
-
import {
|
|
3
|
-
import { resolveI18nConfigWithRuntimeOverrides } from "@i18n-micro/utils/runtime-config";
|
|
4
|
-
import { getI18nConfig } from "#i18n-internal/strategy";
|
|
5
|
-
import { useRuntimeConfig } from "#imports";
|
|
6
|
-
import { detectCurrentLocale } from "./locale-detector.js";
|
|
2
|
+
import { getI18nServerConfig, getRequestLocale } from "./locale-detector.js";
|
|
7
3
|
import { loadTranslationsFromServer } from "./server-loader.js";
|
|
8
4
|
const I18N_CONTEXT_KEY = "__i18n_translations__";
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
locales: getEnabledLocales(locales),
|
|
21
|
-
localeCookie: config.localeCookie,
|
|
22
|
-
autoDetectLanguage: config.autoDetectLanguage
|
|
23
|
-
},
|
|
24
|
-
defaultLocale
|
|
25
|
-
);
|
|
26
|
-
if (!event.context[I18N_CONTEXT_KEY]) {
|
|
27
|
-
let translations2;
|
|
28
|
-
if (event.context.i18n?.translations && Object.keys(event.context.i18n.translations).length > 0) {
|
|
29
|
-
translations2 = event.context.i18n.translations;
|
|
30
|
-
} else {
|
|
31
|
-
const { data } = await loadTranslationsFromServer(locale, "index");
|
|
32
|
-
translations2 = data;
|
|
33
|
-
}
|
|
34
|
-
event.context[I18N_CONTEXT_KEY] = translations2;
|
|
5
|
+
async function dictionaryOf(event, locale) {
|
|
6
|
+
const loaded = event.context[I18N_CONTEXT_KEY] ??= /* @__PURE__ */ Object.create(null);
|
|
7
|
+
const own = loaded[locale];
|
|
8
|
+
if (own) return own;
|
|
9
|
+
const page = event.context.i18n;
|
|
10
|
+
const preloaded = page?.locale === locale && page.translations && Object.keys(page.translations).length > 0 ? page.translations : null;
|
|
11
|
+
if (preloaded) return loaded[locale] = preloaded;
|
|
12
|
+
const chunk = await loadTranslationsFromServer(locale, "index").catch(() => null);
|
|
13
|
+
if (!chunk) {
|
|
14
|
+
console.warn("[i18n] Translation load failed:", locale, "index");
|
|
15
|
+
return {};
|
|
35
16
|
}
|
|
36
|
-
|
|
17
|
+
return loaded[locale] = chunk.data;
|
|
18
|
+
}
|
|
19
|
+
export const useTranslationServerMiddleware = async (event, defaultLocale, currentLocale) => {
|
|
20
|
+
const locale = currentLocale || getRequestLocale(event, getI18nServerConfig(event), defaultLocale);
|
|
21
|
+
const translations = await dictionaryOf(event, locale);
|
|
37
22
|
function t(key, params, defaultValue) {
|
|
38
23
|
const value = resolveTranslation(translations, key);
|
|
39
|
-
if (value === null)
|
|
40
|
-
return defaultValue || key;
|
|
41
|
-
}
|
|
24
|
+
if (value === null) return defaultValue && params ? interpolate(defaultValue, params) : defaultValue || key;
|
|
42
25
|
const str = typeof value === "string" ? value : String(value);
|
|
43
26
|
return params ? interpolate(str, params) : str;
|
|
44
27
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const STORAGE_CC_KEY: unique symbol;
|
|
2
|
+
/**
|
|
3
|
+
* Entries the server keeps when `cacheMaxSize` is not set. Never unbounded: every distinct
|
|
4
|
+
* `locale:page` a request names would otherwise stay in memory for the life of the process.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_SERVER_CACHE_SIZE = 1000;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type { PathStrategy, ResolvedRouteLike, RouteLike } from '@i18n-micro/path-strategy';
|
|
2
|
+
import type { DefineI18nRouteConfig, I18nRouteParams, MissingHandler, ResolvedI18nConfig, Translations } from '@i18n-micro/types';
|
|
3
|
+
import type { RouteLocationNamedRaw, RouteLocationNormalizedLoaded, RouteLocationResolved, RouteLocationResolvedGeneric, Router } from 'vue-router';
|
|
4
|
+
import type { useI18nLocale } from '../composables/useI18nLocale.js';
|
|
5
|
+
import type { NuxtI18n, NuxtTranslationLoader } from './nuxt-i18n.js';
|
|
6
|
+
/** URL of a switch result: the strategy hands out a URL string or a resolved route (fullPath set). */
|
|
7
|
+
export declare function switchedPath(switched: RouteLike | string): string;
|
|
8
|
+
export interface NuxtI18nPluginApiDeps {
|
|
9
|
+
i18n: NuxtI18n;
|
|
10
|
+
loader: NuxtTranslationLoader;
|
|
11
|
+
i18nStrategy: PathStrategy;
|
|
12
|
+
i18nConfig: ResolvedI18nConfig;
|
|
13
|
+
router: Router;
|
|
14
|
+
locale: ReturnType<typeof useI18nLocale>;
|
|
15
|
+
getCurrentLocale: (route?: ResolvedRouteLike) => string;
|
|
16
|
+
i18nRouteParams: {
|
|
17
|
+
value: I18nRouteParams;
|
|
18
|
+
};
|
|
19
|
+
navigateTo: (to: string, options?: {
|
|
20
|
+
redirectCode?: number;
|
|
21
|
+
external?: boolean;
|
|
22
|
+
}) => unknown;
|
|
23
|
+
setMissingHandler: (handler: MissingHandler | null) => void;
|
|
24
|
+
isHydrating: () => boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function createNuxtI18nPluginApi(deps: NuxtI18nPluginApiDeps): {
|
|
27
|
+
helper: {
|
|
28
|
+
mergeTranslation(locale: string, routeName: string, newTranslations: Translations): Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
provide: {
|
|
31
|
+
i18nStrategy: PathStrategy;
|
|
32
|
+
getLocale: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric) => string;
|
|
33
|
+
getLocaleName: () => string | null;
|
|
34
|
+
defaultLocale: () => string;
|
|
35
|
+
getLocales: () => import("@i18n-micro/types").Locale[];
|
|
36
|
+
getRouteName: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric, _locale?: string) => string;
|
|
37
|
+
t: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string | null, routeContext?: unknown) => import("@i18n-micro/types").CleanTranslation;
|
|
38
|
+
ts: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string, routeContext?: unknown) => string;
|
|
39
|
+
_t: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<import("@i18n-micro/types").CleanTranslation>;
|
|
40
|
+
_ts: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<string>;
|
|
41
|
+
tc: (key: import("@i18n-micro/types").TranslationKey, count: number | import("@i18n-micro/types").Params, defaultValue?: string) => string;
|
|
42
|
+
pluralFunc: import("@i18n-micro/types").PluralFunc;
|
|
43
|
+
pluralLocale: () => string;
|
|
44
|
+
tn: {
|
|
45
|
+
(value: number, options?: Intl.NumberFormatOptions): string;
|
|
46
|
+
(value: number, key: string, overrides?: Intl.NumberFormatOptions): string;
|
|
47
|
+
(value: number, key: string, locale: string, overrides?: Intl.NumberFormatOptions): string;
|
|
48
|
+
};
|
|
49
|
+
td: {
|
|
50
|
+
(value: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
|
51
|
+
(value: Date | number | string, key: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
52
|
+
(value: Date | number | string, key: string, locale: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
53
|
+
};
|
|
54
|
+
tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string;
|
|
55
|
+
has: (key: import("@i18n-micro/types").TranslationKey, routeContext?: unknown) => boolean;
|
|
56
|
+
resolveTranslations: (routeContext?: unknown) => Translations;
|
|
57
|
+
setTranslation: (key: import("@i18n-micro/types").TranslationKey, value: unknown) => void;
|
|
58
|
+
mergeTranslations: (newTranslations: Translations) => void;
|
|
59
|
+
switchLocaleRoute: (toLocale: string) => string | import("vue-router").RouteLocationAsRelativeGeneric | import("vue-router").RouteLocationAsPathGeneric;
|
|
60
|
+
clearCache: () => void;
|
|
61
|
+
switchLocalePath: (toLocale: string) => string;
|
|
62
|
+
switchLocale: (toLocale: string) => Promise<boolean>;
|
|
63
|
+
switchRoute: (route: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, toLocale?: string) => Promise<unknown>;
|
|
64
|
+
localeRoute(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): RouteLocationResolved;
|
|
65
|
+
localePath(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): string;
|
|
66
|
+
setI18nRouteParams: (value: I18nRouteParams) => I18nRouteParams;
|
|
67
|
+
loadPageTranslations: (locale: string, routeName: string, translations: Translations) => Promise<void>;
|
|
68
|
+
setMissingHandler: (handler: MissingHandler | null) => void;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export type NuxtI18nPluginApi = ReturnType<typeof createNuxtI18nPluginApi>;
|
|
72
|
+
export type NuxtI18nPluginProvide = NuxtI18nPluginApi['provide'];
|
|
73
|
+
/** The page's own translations: on the active locale, and again on each switch while the page lives. */
|
|
74
|
+
declare function createDefineI18nRoute({ getLocale, mergeTranslations }: Pick<NuxtI18nPluginProvide, 'getLocale' | 'mergeTranslations'>): ({ locales }: DefineI18nRouteConfig) => Promise<void>;
|
|
75
|
+
export interface I18nProvideDeps {
|
|
76
|
+
api: NuxtI18nPluginApi;
|
|
77
|
+
i18nConfig: ResolvedI18nConfig;
|
|
78
|
+
router: Router;
|
|
79
|
+
i18nRouteParams: {
|
|
80
|
+
value: I18nRouteParams;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* What the plugin provides: each helper as `$name` on the app, and under both spellings in `useI18n()`.
|
|
85
|
+
* `install` is apart so that the plugin's return type, which `NuxtApp` is made of, does not depend on `NuxtApp`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createI18nProvide({ api: { helper, provide }, i18nConfig, router, i18nRouteParams }: I18nProvideDeps): {
|
|
88
|
+
provide: {
|
|
89
|
+
i18n: {
|
|
90
|
+
helper: {
|
|
91
|
+
mergeTranslation(locale: string, routeName: string, newTranslations: Translations): Promise<void>;
|
|
92
|
+
};
|
|
93
|
+
getI18nConfig: () => ResolvedI18nConfig;
|
|
94
|
+
__micro: boolean;
|
|
95
|
+
i18nStrategy: PathStrategy;
|
|
96
|
+
getLocale: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric) => string;
|
|
97
|
+
getLocaleName: () => string | null;
|
|
98
|
+
defaultLocale: () => string;
|
|
99
|
+
getLocales: () => import("@i18n-micro/types").Locale[];
|
|
100
|
+
getRouteName: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric, _locale?: string) => string;
|
|
101
|
+
t: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string | null, routeContext?: unknown) => import("@i18n-micro/types").CleanTranslation;
|
|
102
|
+
ts: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string, routeContext?: unknown) => string;
|
|
103
|
+
_t: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<import("@i18n-micro/types").CleanTranslation>;
|
|
104
|
+
_ts: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<string>;
|
|
105
|
+
tc: (key: import("@i18n-micro/types").TranslationKey, count: number | import("@i18n-micro/types").Params, defaultValue?: string) => string;
|
|
106
|
+
pluralFunc: import("@i18n-micro/types").PluralFunc;
|
|
107
|
+
pluralLocale: () => string;
|
|
108
|
+
tn: {
|
|
109
|
+
(value: number, options?: Intl.NumberFormatOptions): string;
|
|
110
|
+
(value: number, key: string, overrides?: Intl.NumberFormatOptions): string;
|
|
111
|
+
(value: number, key: string, locale: string, overrides?: Intl.NumberFormatOptions): string;
|
|
112
|
+
};
|
|
113
|
+
td: {
|
|
114
|
+
(value: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
|
115
|
+
(value: Date | number | string, key: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
116
|
+
(value: Date | number | string, key: string, locale: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
117
|
+
};
|
|
118
|
+
tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string;
|
|
119
|
+
has: (key: import("@i18n-micro/types").TranslationKey, routeContext?: unknown) => boolean;
|
|
120
|
+
resolveTranslations: (routeContext?: unknown) => Translations;
|
|
121
|
+
setTranslation: (key: import("@i18n-micro/types").TranslationKey, value: unknown) => void;
|
|
122
|
+
mergeTranslations: (newTranslations: Translations) => void;
|
|
123
|
+
switchLocaleRoute: (toLocale: string) => string | import("vue-router").RouteLocationAsRelativeGeneric | import("vue-router").RouteLocationAsPathGeneric;
|
|
124
|
+
clearCache: () => void;
|
|
125
|
+
switchLocalePath: (toLocale: string) => string;
|
|
126
|
+
switchLocale: (toLocale: string) => Promise<boolean>;
|
|
127
|
+
switchRoute: (route: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, toLocale?: string) => Promise<unknown>;
|
|
128
|
+
localeRoute(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): RouteLocationResolved;
|
|
129
|
+
localePath(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): string;
|
|
130
|
+
loadPageTranslations: (locale: string, routeName: string, translations: Translations) => Promise<void>;
|
|
131
|
+
setMissingHandler: (handler: MissingHandler | null) => void;
|
|
132
|
+
};
|
|
133
|
+
defineI18nRoute: ReturnType<typeof createDefineI18nRoute>;
|
|
134
|
+
helper: {
|
|
135
|
+
mergeTranslation(locale: string, routeName: string, newTranslations: Translations): Promise<void>;
|
|
136
|
+
};
|
|
137
|
+
getI18nConfig: () => ResolvedI18nConfig;
|
|
138
|
+
__micro: boolean;
|
|
139
|
+
i18nStrategy: PathStrategy;
|
|
140
|
+
getLocale: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric) => string;
|
|
141
|
+
getLocaleName: () => string | null;
|
|
142
|
+
defaultLocale: () => string;
|
|
143
|
+
getLocales: () => import("@i18n-micro/types").Locale[];
|
|
144
|
+
getRouteName: (route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric, _locale?: string) => string;
|
|
145
|
+
t: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string | null, routeContext?: unknown) => import("@i18n-micro/types").CleanTranslation;
|
|
146
|
+
ts: (key: import("@i18n-micro/types").TranslationKey, params?: import("@i18n-micro/types").Params, defaultValue?: string, routeContext?: unknown) => string;
|
|
147
|
+
_t: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<import("@i18n-micro/types").CleanTranslation>;
|
|
148
|
+
_ts: (route: RouteLocationNormalizedLoaded) => import("./nuxt-i18n.js").TranslationFn<string>;
|
|
149
|
+
tc: (key: import("@i18n-micro/types").TranslationKey, count: number | import("@i18n-micro/types").Params, defaultValue?: string) => string;
|
|
150
|
+
pluralFunc: import("@i18n-micro/types").PluralFunc;
|
|
151
|
+
pluralLocale: () => string;
|
|
152
|
+
tn: {
|
|
153
|
+
(value: number, options?: Intl.NumberFormatOptions): string;
|
|
154
|
+
(value: number, key: string, overrides?: Intl.NumberFormatOptions): string;
|
|
155
|
+
(value: number, key: string, locale: string, overrides?: Intl.NumberFormatOptions): string;
|
|
156
|
+
};
|
|
157
|
+
td: {
|
|
158
|
+
(value: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
|
159
|
+
(value: Date | number | string, key: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
160
|
+
(value: Date | number | string, key: string, locale: string, overrides?: Intl.DateTimeFormatOptions): string;
|
|
161
|
+
};
|
|
162
|
+
tdr: (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions) => string;
|
|
163
|
+
has: (key: import("@i18n-micro/types").TranslationKey, routeContext?: unknown) => boolean;
|
|
164
|
+
resolveTranslations: (routeContext?: unknown) => Translations;
|
|
165
|
+
setTranslation: (key: import("@i18n-micro/types").TranslationKey, value: unknown) => void;
|
|
166
|
+
mergeTranslations: (newTranslations: Translations) => void;
|
|
167
|
+
switchLocaleRoute: (toLocale: string) => string | import("vue-router").RouteLocationAsRelativeGeneric | import("vue-router").RouteLocationAsPathGeneric;
|
|
168
|
+
clearCache: () => void;
|
|
169
|
+
switchLocalePath: (toLocale: string) => string;
|
|
170
|
+
switchLocale: (toLocale: string) => Promise<boolean>;
|
|
171
|
+
switchRoute: (route: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, toLocale?: string) => Promise<unknown>;
|
|
172
|
+
localeRoute(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): RouteLocationResolved;
|
|
173
|
+
localePath(to: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string, locale?: string): string;
|
|
174
|
+
loadPageTranslations: (locale: string, routeName: string, translations: Translations) => Promise<void>;
|
|
175
|
+
setMissingHandler: (handler: MissingHandler | null) => void;
|
|
176
|
+
};
|
|
177
|
+
install: (nuxtApp: {
|
|
178
|
+
vueApp: {
|
|
179
|
+
config: {
|
|
180
|
+
globalProperties: Record<string, unknown>;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
}) => void;
|
|
184
|
+
};
|
|
185
|
+
export {};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { isNoPrefixStrategy, urlPath } from "@i18n-micro/core";
|
|
2
|
+
import { trimTrailingSlashes } from "@i18n-micro/utils/app-path";
|
|
3
|
+
import { hasProtocol } from "ufo";
|
|
4
|
+
import { getCurrentInstance, onActivated, watch } from "vue";
|
|
5
|
+
import { domains, defineRoute, serverPathFallback } from "#build/i18n.strategy.mjs";
|
|
6
|
+
import { usePageRoute } from "./page-head.js";
|
|
7
|
+
import { applyTrailingSlash } from "./trailing-slash.js";
|
|
8
|
+
function toRouteLocationResolved(result) {
|
|
9
|
+
const fullPath = result.fullPath ?? result.path ?? "";
|
|
10
|
+
const path = result.path ?? urlPath(fullPath);
|
|
11
|
+
const out = { path, fullPath, href: fullPath };
|
|
12
|
+
if (result.name) out.name = result.name;
|
|
13
|
+
if (result.params && Object.keys(result.params).length) out.params = result.params;
|
|
14
|
+
if (result.query && Object.keys(result.query).length) out.query = result.query;
|
|
15
|
+
if (result.hash) out.hash = result.hash;
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
const URL_SCHEME = /^(?:https?:|mailto:|tel:)/i;
|
|
19
|
+
const DUPLICATED = 16;
|
|
20
|
+
const ABORTED = 4;
|
|
21
|
+
const APP_SCHEME = /^(?:mailto:|tel:)/i;
|
|
22
|
+
export function switchedPath(switched) {
|
|
23
|
+
return typeof switched === "string" ? switched : switched.fullPath ?? switched.path ?? "";
|
|
24
|
+
}
|
|
25
|
+
export function createNuxtI18nPluginApi(deps) {
|
|
26
|
+
const {
|
|
27
|
+
i18n,
|
|
28
|
+
loader,
|
|
29
|
+
i18nStrategy,
|
|
30
|
+
i18nConfig,
|
|
31
|
+
router,
|
|
32
|
+
locale: localeState,
|
|
33
|
+
getCurrentLocale,
|
|
34
|
+
i18nRouteParams,
|
|
35
|
+
navigateTo,
|
|
36
|
+
setMissingHandler,
|
|
37
|
+
isHydrating
|
|
38
|
+
} = deps;
|
|
39
|
+
const { getEffectiveLocale, setLocale, isValidLocale } = localeState;
|
|
40
|
+
const setLocaleState = (code) => {
|
|
41
|
+
localeState.locale.value = code;
|
|
42
|
+
};
|
|
43
|
+
const isNoPrefix = isNoPrefixStrategy(i18nConfig.strategy);
|
|
44
|
+
const withSlashRule = (switched) => i18nConfig.trailingSlash ? applyTrailingSlash(switchedPath(switched), i18nConfig.trailingSlash) : switched;
|
|
45
|
+
const linkRoute = () => {
|
|
46
|
+
const route = router.currentRoute.value;
|
|
47
|
+
if (!route.hash || !isHydrating()) return route;
|
|
48
|
+
return { ...route, hash: "", fullPath: route.fullPath.slice(0, route.fullPath.indexOf("#")) };
|
|
49
|
+
};
|
|
50
|
+
const switchedLink = (toLocale) => i18nStrategy.switchLocaleRoute(toLocale, linkRoute(), { i18nRouteParams: i18nRouteParams.value });
|
|
51
|
+
const isUrl = (to) => typeof to === "string" && URL_SCHEME.test(to);
|
|
52
|
+
const localized = (to, locale) => i18nStrategy.localeRoute(locale !== void 0 && locale !== "" ? String(locale) : getCurrentLocale(), to);
|
|
53
|
+
const switchLocaleLogic = (toLocale, i18nParams, to) => {
|
|
54
|
+
if (typeof to === "string" && APP_SCHEME.test(to)) return navigateTo(to, { redirectCode: 200, external: true });
|
|
55
|
+
const from = typeof to === "string" ? i18nStrategy.localeRoute(getCurrentLocale(), to) : to ?? router.currentRoute.value;
|
|
56
|
+
const switchedRoute = i18nStrategy.switchLocaleRoute(toLocale, from, {
|
|
57
|
+
i18nRouteParams: i18nParams,
|
|
58
|
+
named: isNoPrefix
|
|
59
|
+
});
|
|
60
|
+
const url = switchedPath(switchedRoute);
|
|
61
|
+
const domainUrl = i18nConfig.locales?.find((locale) => locale.code === toLocale)?.baseUrl;
|
|
62
|
+
const domain = domainUrl && trimTrailingSlashes(domainUrl);
|
|
63
|
+
if (domain && (url === domain || url.startsWith(`${domain}/`))) return navigateTo(url, { redirectCode: 200, external: true });
|
|
64
|
+
if (isNoPrefix) {
|
|
65
|
+
const { path, fullPath, ...named } = switchedRoute;
|
|
66
|
+
return router.replace({ ...named.name ? named : { path, fullPath, ...named }, force: true });
|
|
67
|
+
}
|
|
68
|
+
return router.push(withSlashRule(switchedRoute));
|
|
69
|
+
};
|
|
70
|
+
const settleSwitch = (toLocale, failure) => {
|
|
71
|
+
const type = failure instanceof Error ? failure.type : void 0;
|
|
72
|
+
const reloaded = serverPathFallback && type === ABORTED && !i18nStrategy.probe(provide.switchLocalePath(toLocale))?.matched?.length;
|
|
73
|
+
if (reloaded) setLocale(toLocale);
|
|
74
|
+
else if (failure instanceof Error && type !== DUPLICATED) setLocaleState(i18n.getLocale());
|
|
75
|
+
else if (type === DUPLICATED || i18n.getLocale() === toLocale) setLocale(toLocale);
|
|
76
|
+
};
|
|
77
|
+
const helper = {
|
|
78
|
+
async mergeTranslation(locale, routeName, newTranslations) {
|
|
79
|
+
await i18n.mergeTranslationAsync(locale, routeName, newTranslations, (l, r) => loader.loadAsync(l, r));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const provide = {
|
|
83
|
+
i18nStrategy,
|
|
84
|
+
getLocale: (route) => getEffectiveLocale(route, (r) => getCurrentLocale(r)),
|
|
85
|
+
getLocaleName: () => i18nStrategy.getCurrentLocaleName(router.currentRoute.value, getCurrentLocale() ?? null),
|
|
86
|
+
defaultLocale: () => i18nConfig.defaultLocale,
|
|
87
|
+
getLocales: () => i18nConfig.locales,
|
|
88
|
+
getRouteName: (route, _locale) => i18nStrategy.getRouteBaseName(route ?? router.currentRoute.value) ?? "",
|
|
89
|
+
t: i18n.t.bind(i18n),
|
|
90
|
+
ts: i18n.ts.bind(i18n),
|
|
91
|
+
_t: (route) => i18n.tForRoute(route),
|
|
92
|
+
_ts: (route) => i18n.tsForRoute(route),
|
|
93
|
+
tc: i18n.tc.bind(i18n),
|
|
94
|
+
pluralFunc: i18n.pluralFunc,
|
|
95
|
+
pluralLocale: i18n.pluralLocale.bind(i18n),
|
|
96
|
+
tn: i18n.tn.bind(i18n),
|
|
97
|
+
td: i18n.td.bind(i18n),
|
|
98
|
+
tdr: i18n.tdr.bind(i18n),
|
|
99
|
+
has: i18n.has.bind(i18n),
|
|
100
|
+
resolveTranslations: i18n.resolveTranslations.bind(i18n),
|
|
101
|
+
setTranslation: i18n.setTranslation.bind(i18n),
|
|
102
|
+
mergeTranslations: i18n.mergeTranslations.bind(i18n),
|
|
103
|
+
switchLocaleRoute: (toLocale) => {
|
|
104
|
+
const switched = switchedLink(toLocale);
|
|
105
|
+
if (typeof switched === "string" || !i18nConfig.trailingSlash) return switched;
|
|
106
|
+
const fullPath = applyTrailingSlash(switchedPath(switched), i18nConfig.trailingSlash);
|
|
107
|
+
return { path: urlPath(fullPath), fullPath, query: switched.query, hash: switched.hash };
|
|
108
|
+
},
|
|
109
|
+
clearCache: () => {
|
|
110
|
+
void loader.reload();
|
|
111
|
+
},
|
|
112
|
+
switchLocalePath: (toLocale) => applyTrailingSlash(switchedPath(switchedLink(toLocale)), i18nConfig.trailingSlash),
|
|
113
|
+
switchLocale: async (toLocale) => {
|
|
114
|
+
if (!isValidLocale(toLocale)) {
|
|
115
|
+
if (process.env.NODE_ENV !== "production") console.warn(`[i18n] Invalid locale '${toLocale}'`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
const urlless = isNoPrefix || i18nConfig.hashMode;
|
|
119
|
+
const retry = getCurrentLocale() === toLocale && i18n.getLocale() !== toLocale;
|
|
120
|
+
const route = router.currentRoute.value;
|
|
121
|
+
const loaded = urlless || retry ? await loader.switchContext(toLocale, i18nStrategy.getPluginRouteName(route, toLocale)) : null;
|
|
122
|
+
if (loaded === false) return false;
|
|
123
|
+
if (urlless || hasProtocol(provide.switchLocalePath(toLocale))) setLocale(toLocale);
|
|
124
|
+
else setLocaleState(toLocale);
|
|
125
|
+
try {
|
|
126
|
+
const failure = await switchLocaleLogic(toLocale, i18nRouteParams.value);
|
|
127
|
+
if (!urlless) settleSwitch(toLocale, failure);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (!urlless) setLocaleState(i18n.getLocale());
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
return loaded ?? i18n.getLocale() === toLocale;
|
|
133
|
+
},
|
|
134
|
+
switchRoute: async (route, toLocale) => {
|
|
135
|
+
return switchLocaleLogic(toLocale ?? getCurrentLocale(), i18nRouteParams.value, route);
|
|
136
|
+
},
|
|
137
|
+
localeRoute(to, locale) {
|
|
138
|
+
return toRouteLocationResolved(isUrl(to) ? { path: to, fullPath: to } : localized(to, locale));
|
|
139
|
+
},
|
|
140
|
+
localePath(to, locale) {
|
|
141
|
+
return isUrl(to) ? to : applyTrailingSlash(switchedPath(localized(to, locale)), i18nConfig.trailingSlash);
|
|
142
|
+
},
|
|
143
|
+
setI18nRouteParams: (value) => {
|
|
144
|
+
i18nRouteParams.value = value;
|
|
145
|
+
return i18nRouteParams.value;
|
|
146
|
+
},
|
|
147
|
+
loadPageTranslations: i18n.loadPageTranslations.bind(i18n),
|
|
148
|
+
setMissingHandler
|
|
149
|
+
};
|
|
150
|
+
if (domains) {
|
|
151
|
+
const { switchLocale } = provide;
|
|
152
|
+
provide.switchLocale = async (code) => {
|
|
153
|
+
if (isValidLocale(code) || !i18nConfig.linkLocales?.some((locale) => locale.code === code && !locale.disabled)) return switchLocale(code);
|
|
154
|
+
await navigateTo(provide.switchLocalePath(code), { external: true });
|
|
155
|
+
return true;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { helper, provide };
|
|
159
|
+
}
|
|
160
|
+
function createDefineI18nRoute({ getLocale, mergeTranslations }) {
|
|
161
|
+
return async ({ locales }) => {
|
|
162
|
+
if (!locales || Array.isArray(locales)) return;
|
|
163
|
+
const apply = () => {
|
|
164
|
+
const translations = locales[getLocale()];
|
|
165
|
+
if (translations) mergeTranslations(translations);
|
|
166
|
+
};
|
|
167
|
+
apply();
|
|
168
|
+
if (import.meta.client) watch(() => getLocale(), apply);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
export function createI18nProvide({ api: { helper, provide }, i18nConfig, router, i18nRouteParams }) {
|
|
172
|
+
const { setI18nRouteParams, ...provided } = provide;
|
|
173
|
+
const pageRouteParams = {
|
|
174
|
+
enumerable: true,
|
|
175
|
+
get: () => {
|
|
176
|
+
const page = getCurrentInstance() && usePageRoute();
|
|
177
|
+
if (!page) return setI18nRouteParams;
|
|
178
|
+
let own;
|
|
179
|
+
onActivated(() => own && setI18nRouteParams(own));
|
|
180
|
+
return (value) => {
|
|
181
|
+
if (page.path !== router.currentRoute.value.path) return i18nRouteParams.value;
|
|
182
|
+
own = value;
|
|
183
|
+
return setI18nRouteParams(value);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const bound = { ...provided, helper, getI18nConfig: () => i18nConfig, __micro: true };
|
|
188
|
+
const dollar = Object.fromEntries(Object.entries(bound).map(([key, value]) => [`$${key}`, value]));
|
|
189
|
+
const spellings = Object.defineProperties({ ...bound, ...dollar }, { setI18nRouteParams: pageRouteParams, $setI18nRouteParams: pageRouteParams });
|
|
190
|
+
const install = (nuxtApp) => {
|
|
191
|
+
Object.defineProperty(nuxtApp, "$setI18nRouteParams", pageRouteParams);
|
|
192
|
+
nuxtApp.vueApp.config.globalProperties.$setI18nRouteParams = setI18nRouteParams;
|
|
193
|
+
};
|
|
194
|
+
const define = defineRoute ? { defineI18nRoute: createDefineI18nRoute(provide) } : {};
|
|
195
|
+
return { provide: { ...bound, ...define, i18n: spellings }, install };
|
|
196
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ModuleOptionsExtend, ResolvedI18nConfig } from '@i18n-micro/types';
|
|
2
|
+
import { type RuntimeI18nOverrides } from '@i18n-micro/utils/runtime-config';
|
|
3
|
+
import type { NuxtApp } from 'nuxt/app';
|
|
4
|
+
/** What the server resolved: overrides and the host. */
|
|
5
|
+
type Shipped = RuntimeI18nOverrides & {
|
|
6
|
+
domain?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* What the browser has to be told, or null when the server resolved what the build says. By value:
|
|
10
|
+
* Nitro and the app bundle each hold their own copy of the build config, so `config !== base` is always true.
|
|
11
|
+
*/
|
|
12
|
+
export declare function shippedOverrides(config: ModuleOptionsExtend, base: ModuleOptionsExtend): Shipped | null;
|
|
13
|
+
/**
|
|
14
|
+
* The module config with runtime overrides, the same on server and client: routing (the path
|
|
15
|
+
* strategy), validation (`useI18nLocale`) and redirects all read this one.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useResolvedI18nConfig(nuxtApp: NuxtApp): ResolvedI18nConfig;
|
|
18
|
+
export {};
|