nuxt-i18n-micro 1.1.8 → 1.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71.json +1 -0
- package/dist/client/index.html +1 -1
- package/dist/module.d.mts +1 -0
- package/dist/module.d.ts +1 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +34 -16
- package/dist/runtime/composables/useI18n.d.ts +1 -1
- package/dist/runtime/composables/useI18n.js +1 -0
- package/dist/runtime/{01.plugin.d.ts → plugins/01.plugin.d.ts} +16 -4
- package/dist/runtime/plugins/01.plugin.js +159 -0
- package/dist/runtime/{03.define.js → plugins/03.define.js} +7 -1
- package/dist/runtime/server/middleware/i18n-loader.d.ts +6 -0
- package/dist/runtime/server/middleware/i18n-loader.js +22 -0
- package/dist/runtime/translationHelper.d.ts +12 -0
- package/dist/runtime/translationHelper.js +115 -0
- package/package.json +1 -1
- package/dist/client/_nuxt/builds/meta/7d3d3cf9-6064-4ba3-a2ec-347447f8edd0.json +0 -1
- package/dist/runtime/01.plugin.js +0 -150
- /package/dist/runtime/{02.meta.d.ts → plugins/02.meta.d.ts} +0 -0
- /package/dist/runtime/{02.meta.js → plugins/02.meta.js} +0 -0
- /package/dist/runtime/{03.define.d.ts → plugins/03.define.d.ts} +0 -0
- /package/dist/runtime/{04.auto-detect.d.ts → plugins/04.auto-detect.d.ts} +0 -0
- /package/dist/runtime/{04.auto-detect.js → plugins/04.auto-detect.js} +0 -0
package/dist/client/200.html
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
<link rel="prefetch" as="style" href="/__nuxt-i18n-micro/_nuxt/error-500.B4KzowuE.css">
|
|
9
9
|
<link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/HZLiFEh-.js">
|
|
10
10
|
<script type="module" src="/__nuxt-i18n-micro/_nuxt/6EJ4fAZ2.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"serverRendered":1},false]</script>
|
|
11
|
-
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"
|
|
11
|
+
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
|
package/dist/client/404.html
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
<link rel="prefetch" as="style" href="/__nuxt-i18n-micro/_nuxt/error-500.B4KzowuE.css">
|
|
9
9
|
<link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/HZLiFEh-.js">
|
|
10
10
|
<script type="module" src="/__nuxt-i18n-micro/_nuxt/6EJ4fAZ2.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"serverRendered":1},false]</script>
|
|
11
|
-
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"
|
|
11
|
+
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"id":"
|
|
1
|
+
{"id":"f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71","timestamp":1724070947234}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71","timestamp":1724070947234,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
|
package/dist/client/index.html
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
<link rel="prefetch" as="style" href="/__nuxt-i18n-micro/_nuxt/error-500.B4KzowuE.css">
|
|
9
9
|
<link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/HZLiFEh-.js">
|
|
10
10
|
<script type="module" src="/__nuxt-i18n-micro/_nuxt/6EJ4fAZ2.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"serverRendered":1},false]</script>
|
|
11
|
-
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"
|
|
11
|
+
<script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"f1ddbdf9-9b7b-4ddb-bddb-a5d520509f71",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
|
package/dist/module.d.mts
CHANGED
package/dist/module.d.ts
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
-
import { useNuxt, defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerHandler, extendPages } from '@nuxt/kit';
|
|
4
|
+
import { useNuxt, defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerHandler, extendPages, addPrerenderRoutes } from '@nuxt/kit';
|
|
5
5
|
import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
|
|
6
6
|
|
|
7
7
|
const DEVTOOLS_UI_PORT = 3030;
|
|
@@ -79,6 +79,7 @@ const module = defineNuxtModule({
|
|
|
79
79
|
translationDir: "locales",
|
|
80
80
|
autoDetectLanguage: true,
|
|
81
81
|
includeDefaultLocaleRoute: false,
|
|
82
|
+
cache: false,
|
|
82
83
|
plural: `function (translation, count, _locale) {
|
|
83
84
|
const forms = translation.toString().split('|')
|
|
84
85
|
if (count === 0 && forms.length > 2) {
|
|
@@ -90,7 +91,7 @@ const module = defineNuxtModule({
|
|
|
90
91
|
return (forms.length > 2 ? forms[2].trim() : forms[forms.length - 1].trim()).replace('{count}', count.toString())
|
|
91
92
|
}`
|
|
92
93
|
},
|
|
93
|
-
setup(options, nuxt) {
|
|
94
|
+
setup: function(options, nuxt) {
|
|
94
95
|
const resolver = createResolver(import.meta.url);
|
|
95
96
|
nuxt.options.runtimeConfig.public.i18nConfig = {
|
|
96
97
|
rootDir: nuxt.options.rootDir,
|
|
@@ -100,38 +101,45 @@ const module = defineNuxtModule({
|
|
|
100
101
|
defaultLocale: options.defaultLocale ?? "en",
|
|
101
102
|
translationDir: options.translationDir ?? "locales",
|
|
102
103
|
autoDetectLanguage: options.autoDetectLanguage ?? true,
|
|
103
|
-
includeDefaultLocaleRoute: options.includeDefaultLocaleRoute ?? false
|
|
104
|
+
includeDefaultLocaleRoute: options.includeDefaultLocaleRoute ?? false,
|
|
105
|
+
cache: options.cache ?? false
|
|
104
106
|
};
|
|
105
107
|
addPlugin({
|
|
106
|
-
src: resolver.resolve("./runtime/01.plugin"),
|
|
108
|
+
src: resolver.resolve("./runtime/plugins/01.plugin"),
|
|
107
109
|
order: 1
|
|
108
110
|
});
|
|
111
|
+
if (options.mata) {
|
|
112
|
+
addPlugin({
|
|
113
|
+
src: resolver.resolve("./runtime/plugins/02.meta"),
|
|
114
|
+
order: 2
|
|
115
|
+
});
|
|
116
|
+
}
|
|
109
117
|
addPlugin({
|
|
110
|
-
src: resolver.resolve("./runtime/
|
|
111
|
-
order:
|
|
112
|
-
});
|
|
113
|
-
addPlugin({
|
|
114
|
-
src: resolver.resolve("./runtime/03.define"),
|
|
115
|
-
order: 2
|
|
118
|
+
src: resolver.resolve("./runtime/plugins/03.define"),
|
|
119
|
+
order: 3
|
|
116
120
|
});
|
|
117
121
|
if (options.autoDetectLanguage) {
|
|
118
122
|
addPlugin({
|
|
119
|
-
src: resolver.resolve("./runtime/04.auto-detect"),
|
|
123
|
+
src: resolver.resolve("./runtime/plugins/04.auto-detect"),
|
|
120
124
|
mode: "client",
|
|
121
|
-
order:
|
|
125
|
+
order: 4
|
|
122
126
|
});
|
|
123
127
|
}
|
|
124
128
|
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
125
129
|
if (options.includeDefaultLocaleRoute) {
|
|
126
130
|
addServerHandler({
|
|
127
131
|
middleware: true,
|
|
128
|
-
handler: resolver.resolve("./runtime/server/middleware/i18n-redirect
|
|
132
|
+
handler: resolver.resolve("./runtime/server/middleware/i18n-redirect")
|
|
129
133
|
});
|
|
130
134
|
}
|
|
135
|
+
addServerHandler({
|
|
136
|
+
route: "/_locales/:page/:locale/data.json",
|
|
137
|
+
handler: resolver.resolve("./runtime/server/middleware/i18n-loader")
|
|
138
|
+
});
|
|
131
139
|
const localeRegex = options.locales.filter((locale) => locale.code !== options.defaultLocale || options.includeDefaultLocaleRoute).map((locale) => locale.code).join("|");
|
|
132
140
|
const pagesDir = path.resolve(nuxt.options.rootDir, options.translationDir, "pages");
|
|
133
141
|
extendPages((pages) => {
|
|
134
|
-
|
|
142
|
+
const pagesNames = pages.map((page) => page.name);
|
|
135
143
|
const newRoutes = pages.map((page) => {
|
|
136
144
|
options.locales.forEach((locale) => {
|
|
137
145
|
pages.forEach((page2) => {
|
|
@@ -155,6 +163,15 @@ const module = defineNuxtModule({
|
|
|
155
163
|
};
|
|
156
164
|
});
|
|
157
165
|
pages.push(...newRoutes);
|
|
166
|
+
nuxt.options.generate.routes = Array.isArray(nuxt.options.generate.routes) ? nuxt.options.generate.routes : [];
|
|
167
|
+
if (nuxt.options?._generate) {
|
|
168
|
+
options.locales?.forEach((locale) => {
|
|
169
|
+
pagesNames.forEach((name) => {
|
|
170
|
+
addPrerenderRoutes(`/_locales/${name}/${locale.code}/data.json`);
|
|
171
|
+
});
|
|
172
|
+
addPrerenderRoutes(`/_locales/general/${locale.code}/data.json`);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
158
175
|
});
|
|
159
176
|
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
160
177
|
const routes = nitroConfig.prerender?.routes || [];
|
|
@@ -163,15 +180,16 @@ const module = defineNuxtModule({
|
|
|
163
180
|
options.locales.forEach((locale) => {
|
|
164
181
|
if (locale.code !== options.defaultLocale || options.includeDefaultLocaleRoute) {
|
|
165
182
|
pages.forEach((page) => {
|
|
166
|
-
routes.push(`/${locale}${page}`);
|
|
183
|
+
routes.push(`/${locale.code}${page}`);
|
|
167
184
|
});
|
|
168
185
|
}
|
|
169
186
|
});
|
|
170
187
|
nitroConfig.prerender = nitroConfig.prerender || {};
|
|
171
188
|
nitroConfig.prerender.routes = routes;
|
|
172
189
|
});
|
|
173
|
-
if (nuxt.options.dev)
|
|
190
|
+
if (nuxt.options.dev) {
|
|
174
191
|
setupDevToolsUI(options, resolver.resolve);
|
|
192
|
+
}
|
|
175
193
|
}
|
|
176
194
|
});
|
|
177
195
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { PluginsInjections } from '../01.plugin.js';
|
|
1
|
+
import type { PluginsInjections } from '../plugins/01.plugin.js';
|
|
2
2
|
export declare function useI18n(): PluginsInjections;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RouteLocationRaw } from 'vue-router';
|
|
2
|
-
interface Translations {
|
|
2
|
+
export interface Translations {
|
|
3
3
|
[key: string]: string | number | boolean | Translations | PluralTranslations | unknown[] | null;
|
|
4
4
|
}
|
|
5
5
|
interface PluralTranslations {
|
|
@@ -8,17 +8,19 @@ interface PluralTranslations {
|
|
|
8
8
|
}
|
|
9
9
|
declare const _default: import("#app").Plugin<{
|
|
10
10
|
getLocale: () => string;
|
|
11
|
-
getLocales: () => import("
|
|
11
|
+
getLocales: () => import("../../module").Locale[];
|
|
12
12
|
t: <T extends Record<string, string | number | boolean>>(key: string, params?: T, defaultValue?: string) => string | number | boolean | Translations | PluralTranslations | unknown[] | unknown | null;
|
|
13
13
|
tc: (key: string, count: number, defaultValue?: string) => string;
|
|
14
|
+
has: (key: string) => boolean;
|
|
14
15
|
mergeTranslations: (newTranslations: Translations) => void;
|
|
15
16
|
switchLocale: (locale: string) => void;
|
|
16
17
|
localeRoute: (to: RouteLocationRaw, locale?: string) => RouteLocationRaw;
|
|
17
18
|
}> & import("#app").ObjectPlugin<{
|
|
18
19
|
getLocale: () => string;
|
|
19
|
-
getLocales: () => import("
|
|
20
|
+
getLocales: () => import("../../module").Locale[];
|
|
20
21
|
t: <T extends Record<string, string | number | boolean>>(key: string, params?: T, defaultValue?: string) => string | number | boolean | Translations | PluralTranslations | unknown[] | unknown | null;
|
|
21
22
|
tc: (key: string, count: number, defaultValue?: string) => string;
|
|
23
|
+
has: (key: string) => boolean;
|
|
22
24
|
mergeTranslations: (newTranslations: Translations) => void;
|
|
23
25
|
switchLocale: (locale: string) => void;
|
|
24
26
|
localeRoute: (to: RouteLocationRaw, locale?: string) => RouteLocationRaw;
|
|
@@ -29,6 +31,7 @@ export interface PluginsInjections {
|
|
|
29
31
|
$getLocales: () => string[];
|
|
30
32
|
$t: <T extends Record<string, string | number | boolean>>(key: string, params?: T, defaultValue?: string) => string | number | boolean | Translations | PluralTranslations | unknown[] | unknown | null;
|
|
31
33
|
$tc: (key: string, count: number, defaultValue?: string) => string;
|
|
34
|
+
$has: (key: string) => boolean;
|
|
32
35
|
$mergeTranslations: (newTranslations: Translations) => void;
|
|
33
36
|
$switchLocale: (locale: string) => void;
|
|
34
37
|
$localeRoute: (to: RouteLocationRaw, locale?: string) => RouteLocationRaw;
|
|
@@ -43,7 +46,16 @@ declare module 'nuxt/dist/app/nuxt' {
|
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
declare module '@vue/runtime-core' {
|
|
46
|
-
interface ComponentCustomProperties
|
|
49
|
+
interface ComponentCustomProperties {
|
|
50
|
+
$getLocale: () => string;
|
|
51
|
+
$getLocales: () => string[];
|
|
52
|
+
$t: <T extends Record<string, string | number | boolean>>(key: string, params?: T, defaultValue?: string) => string | number | boolean | Translations | PluralTranslations | unknown[] | unknown | null;
|
|
53
|
+
$tc: (key: string, count: number, defaultValue?: string) => string;
|
|
54
|
+
$has: (key: string) => boolean;
|
|
55
|
+
$mergeTranslations: (newTranslations: Translations) => void;
|
|
56
|
+
$switchLocale: (locale: string) => void;
|
|
57
|
+
$localeRoute: (to: RouteLocationRaw, locale?: string) => RouteLocationRaw;
|
|
58
|
+
$loadPageTranslations: (locale: string, routeName: string) => Promise<void>;
|
|
47
59
|
}
|
|
48
60
|
}
|
|
49
61
|
declare module 'vue' {
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useTranslationHelper } from "../translationHelper.js";
|
|
2
|
+
import { defineNuxtPlugin, useRuntimeConfig } from "#app";
|
|
3
|
+
import { useFetch, useRoute, useRouter } from "#imports";
|
|
4
|
+
const i18nHelper = useTranslationHelper();
|
|
5
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
6
|
+
function interpolate(template, params) {
|
|
7
|
+
return template.replace(/\{(\w+)\}/g, (_, match) => {
|
|
8
|
+
return params[match] !== void 0 ? String(params[match]) : `{${match}}`;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function switchLocale(locale, route, router, i18nConfig) {
|
|
12
|
+
const checkLocale = i18nConfig.locales?.find((l) => l.code === locale);
|
|
13
|
+
if (!checkLocale) {
|
|
14
|
+
console.warn(`Locale ${locale} is not available`);
|
|
15
|
+
return Promise.reject(`Locale ${locale} is not available`);
|
|
16
|
+
}
|
|
17
|
+
const { defaultLocale } = i18nConfig;
|
|
18
|
+
const routeName = route.name.replace(`localized-`, "");
|
|
19
|
+
const newRouteName = locale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute ? `localized-${routeName}` : routeName;
|
|
20
|
+
const newParams = { ...route.params };
|
|
21
|
+
delete newParams.locale;
|
|
22
|
+
if (locale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute) {
|
|
23
|
+
newParams.locale = locale;
|
|
24
|
+
}
|
|
25
|
+
return router.push({ name: newRouteName, params: newParams });
|
|
26
|
+
}
|
|
27
|
+
function getLocalizedRoute(to, router, route, i18nConfig, locale) {
|
|
28
|
+
const { defaultLocale } = i18nConfig;
|
|
29
|
+
const currentLocale = (locale || route.params.locale || defaultLocale).toString();
|
|
30
|
+
const selectRoute = router.resolve(to);
|
|
31
|
+
const routeName = selectRoute.name.replace(`localized-`, "");
|
|
32
|
+
const newRouteName = currentLocale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute ? `localized-${routeName}` : routeName;
|
|
33
|
+
const newParams = { ...route.params };
|
|
34
|
+
delete newParams.locale;
|
|
35
|
+
if (currentLocale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute) {
|
|
36
|
+
newParams.locale = currentLocale;
|
|
37
|
+
}
|
|
38
|
+
return router.resolve({ name: newRouteName, params: newParams });
|
|
39
|
+
}
|
|
40
|
+
export default defineNuxtPlugin(async (nuxtApp) => {
|
|
41
|
+
const router = useRouter();
|
|
42
|
+
if (!nuxtApp.payload.data.translations) {
|
|
43
|
+
nuxtApp.payload.data.translations = {};
|
|
44
|
+
}
|
|
45
|
+
if (import.meta.server) {
|
|
46
|
+
nuxtApp.hook("app:rendered", async () => {
|
|
47
|
+
if (import.meta.server) {
|
|
48
|
+
const route2 = useRoute();
|
|
49
|
+
const locale = (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
50
|
+
const routeName = (route2?.name ?? "").toString().replace(`localized-`, "");
|
|
51
|
+
const cacheKey = `${locale}:${routeName}`;
|
|
52
|
+
nuxtApp.payload.data.translations[cacheKey] = i18nHelper.getCache(locale, routeName) ?? /* @__PURE__ */ new Map();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
router.beforeEach(async (to, from, next) => {
|
|
57
|
+
const locale = (to.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
58
|
+
const routeName = to.name.replace(`localized-`, "");
|
|
59
|
+
const cacheKey = `${locale}:${routeName}`;
|
|
60
|
+
if (nuxtApp.payload.data.translations) {
|
|
61
|
+
i18nHelper.setCache(locale, routeName, nuxtApp.payload.data.translations[cacheKey] || /* @__PURE__ */ new Map());
|
|
62
|
+
}
|
|
63
|
+
next();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const route = useRoute();
|
|
67
|
+
const config = useRuntimeConfig();
|
|
68
|
+
const i18nConfig = config.public.i18nConfig;
|
|
69
|
+
const initialLocale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
70
|
+
const initialRouteName = route.name.replace(`localized-`, "");
|
|
71
|
+
const plural = new Function("return " + i18nConfig.plural)();
|
|
72
|
+
router.beforeEach(async (to, from, next) => {
|
|
73
|
+
if (import.meta.client) {
|
|
74
|
+
const locale = (to.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
75
|
+
const routeName = to.name.replace(`localized-`, "");
|
|
76
|
+
if (!i18nHelper.hasPageTranslation(locale, routeName)) {
|
|
77
|
+
const resp = await fetch(`/_locales/${routeName}/${locale}/data.json`);
|
|
78
|
+
if (resp.ok) {
|
|
79
|
+
await i18nHelper.loadPageTranslations(locale, routeName, await resp.json());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
next();
|
|
84
|
+
});
|
|
85
|
+
const { data } = await useFetch(`/_locales/general/${initialLocale}/data.json`);
|
|
86
|
+
await i18nHelper.loadTranslations(initialLocale, initialRouteName, data.value ?? {});
|
|
87
|
+
if (import.meta.server) {
|
|
88
|
+
const locale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
89
|
+
const routeName = route.name.replace(`localized-`, "");
|
|
90
|
+
const { data: data2 } = await useFetch(`/_locales/${routeName}/${locale}/data.json`);
|
|
91
|
+
await i18nHelper.loadPageTranslations(initialLocale, initialRouteName, data2.value ?? {});
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
provide: {
|
|
95
|
+
getLocale: () => {
|
|
96
|
+
const route2 = useRoute();
|
|
97
|
+
return (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
98
|
+
},
|
|
99
|
+
getLocales: () => i18nConfig.locales || [],
|
|
100
|
+
t: (key, params, defaultValue) => {
|
|
101
|
+
if (!key) {
|
|
102
|
+
console.log(`$t: key not exist`);
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
const route2 = useRoute();
|
|
106
|
+
const locale = (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
107
|
+
const routeName = route2.name.replace(`localized-`, "");
|
|
108
|
+
let value = i18nHelper.getTranslation(locale, routeName, key, !!i18nConfig.cache);
|
|
109
|
+
if (!value) {
|
|
110
|
+
if (isDev && import.meta.client) {
|
|
111
|
+
}
|
|
112
|
+
value = defaultValue || key;
|
|
113
|
+
}
|
|
114
|
+
if (typeof value === "string" && params) {
|
|
115
|
+
value = interpolate(value, params);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
},
|
|
119
|
+
tc: (key, count, defaultValue) => {
|
|
120
|
+
if (!key) {
|
|
121
|
+
console.log(`$tc: key not exist`);
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
const route2 = useRoute();
|
|
125
|
+
const locale = (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
126
|
+
const routeName = route2.name.replace(`localized-`, "");
|
|
127
|
+
let translation = i18nHelper.getTranslation(locale, routeName, key, !!i18nConfig.cache);
|
|
128
|
+
if (!translation) {
|
|
129
|
+
if (isDev && import.meta.client) {
|
|
130
|
+
console.warn(`Not found '${key}' key in '${locale}' locale messages.`);
|
|
131
|
+
}
|
|
132
|
+
translation = defaultValue || key;
|
|
133
|
+
}
|
|
134
|
+
return plural(translation.toString(), count, locale);
|
|
135
|
+
},
|
|
136
|
+
has: (key) => {
|
|
137
|
+
const route2 = useRoute();
|
|
138
|
+
const locale = (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
139
|
+
const routeName = route2.name.replace(`localized-`, "");
|
|
140
|
+
const translation = i18nHelper.getTranslation(locale, routeName, key, !!i18nConfig.cache);
|
|
141
|
+
return !!translation;
|
|
142
|
+
},
|
|
143
|
+
mergeTranslations: (newTranslations) => {
|
|
144
|
+
const route2 = useRoute();
|
|
145
|
+
const routeName = route2.name.replace(`localized-`, "");
|
|
146
|
+
const locale = (route2.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
147
|
+
i18nHelper.margeTranslation(routeName, locale, newTranslations);
|
|
148
|
+
},
|
|
149
|
+
switchLocale: (locale) => {
|
|
150
|
+
const route2 = useRoute();
|
|
151
|
+
switchLocale(locale, route2, router, i18nConfig);
|
|
152
|
+
},
|
|
153
|
+
localeRoute: (to, locale) => {
|
|
154
|
+
const route2 = useRoute();
|
|
155
|
+
return getLocalizedRoute(to, router, route2, i18nConfig, locale);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
});
|
|
@@ -10,8 +10,14 @@ export default defineNuxtPlugin((_nuxtApp) => {
|
|
|
10
10
|
const { locales } = routeDefinition;
|
|
11
11
|
const { name } = route;
|
|
12
12
|
if (locales && !locales.includes(currentLocale)) {
|
|
13
|
-
|
|
13
|
+
let defaultRouteName = name?.toString().replace("localized-", "");
|
|
14
14
|
const resolvedRoute = router.resolve({ name: defaultRouteName });
|
|
15
|
+
const newParams = { ...route.params };
|
|
16
|
+
delete newParams.locale;
|
|
17
|
+
if (i18nConfig.includeDefaultLocaleRoute) {
|
|
18
|
+
defaultRouteName = `localized-${defaultRouteName}`;
|
|
19
|
+
newParams.locale = i18nConfig.defaultLocale;
|
|
20
|
+
}
|
|
15
21
|
return router.push(resolvedRoute);
|
|
16
22
|
}
|
|
17
23
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ModuleOptions } from '../../../module.js';
|
|
2
|
+
export interface ModuleOptionsExtend extends ModuleOptions {
|
|
3
|
+
rootDir?: string;
|
|
4
|
+
}
|
|
5
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { defineEventHandler } from "h3";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const { page, locale } = event.context.params;
|
|
7
|
+
const config = useRuntimeConfig();
|
|
8
|
+
const { rootDir, translationDir } = config.public.i18nConfig;
|
|
9
|
+
let path = `${locale}.json`;
|
|
10
|
+
if (page !== "general") {
|
|
11
|
+
path = `pages/${page}/${locale}.json`;
|
|
12
|
+
}
|
|
13
|
+
const translationPath = resolve(rootDir, translationDir, path);
|
|
14
|
+
try {
|
|
15
|
+
const fileContent = await readFile(translationPath, "utf-8");
|
|
16
|
+
return JSON.parse(fileContent);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.log("error", error);
|
|
19
|
+
event.node.res.statusCode = 404;
|
|
20
|
+
return { error: "Translations not found" };
|
|
21
|
+
}
|
|
22
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Translations } from './plugins/01.plugin.js';
|
|
2
|
+
export declare function useTranslationHelper(): {
|
|
3
|
+
hasCache(locale: string, page: string): boolean;
|
|
4
|
+
getCache(locale: string, routeName: string): Map<string, unknown>;
|
|
5
|
+
setCache(locale: string, routeName: string, cache: Map<string, Translations | unknown>): void;
|
|
6
|
+
margeTranslation(locale: string, routeName: string, newTranslations: Translations): void;
|
|
7
|
+
hasGeneralTranslation(locale: string): boolean;
|
|
8
|
+
hasPageTranslation(locale: string, routeName: string): boolean;
|
|
9
|
+
getTranslation: <T = unknown>(locale: string, routeName: string, key: string, useCache: boolean) => T | null;
|
|
10
|
+
loadPageTranslations: (locale: string, routeName: string, translations: Translations) => Promise<void>;
|
|
11
|
+
loadTranslations: (locale: string, routeName: string, translations: Translations) => Promise<void>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const generalLocaleCache = {};
|
|
2
|
+
const routeLocaleCache = {};
|
|
3
|
+
const dynamicTranslationsCaches = [];
|
|
4
|
+
const serverTranslationCache = {};
|
|
5
|
+
const serverTranslationInit = {};
|
|
6
|
+
function deepClone(value) {
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
return value.slice();
|
|
9
|
+
} else if (typeof value === "object" && value !== null) {
|
|
10
|
+
return { ...value };
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function findTranslation(translations, parts) {
|
|
15
|
+
let value = translations;
|
|
16
|
+
for (let i = 0; i < parts.length; i++) {
|
|
17
|
+
if (value && typeof value === "object" && parts[i] in value) {
|
|
18
|
+
value = value[parts[i]];
|
|
19
|
+
} else {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === "object" && value !== null) {
|
|
24
|
+
return deepClone(value);
|
|
25
|
+
}
|
|
26
|
+
return value ?? null;
|
|
27
|
+
}
|
|
28
|
+
export function useTranslationHelper() {
|
|
29
|
+
return {
|
|
30
|
+
hasCache(locale, page) {
|
|
31
|
+
return serverTranslationInit[`${locale}:${page}`] ?? false;
|
|
32
|
+
},
|
|
33
|
+
getCache(locale, routeName) {
|
|
34
|
+
return serverTranslationCache[`${locale}:${routeName}`];
|
|
35
|
+
},
|
|
36
|
+
setCache(locale, routeName, cache) {
|
|
37
|
+
serverTranslationCache[`${locale}:${routeName}`] = cache;
|
|
38
|
+
serverTranslationInit[`${locale}:index`] = true;
|
|
39
|
+
serverTranslationInit[`${locale}:${routeName}`] = true;
|
|
40
|
+
},
|
|
41
|
+
margeTranslation(locale, routeName, newTranslations) {
|
|
42
|
+
if (!routeLocaleCache[`${locale}:${routeName}`]) {
|
|
43
|
+
console.error(`marge: route ${routeName} not loaded`);
|
|
44
|
+
}
|
|
45
|
+
routeLocaleCache[`${locale}:${routeName}`] = {
|
|
46
|
+
...generalLocaleCache[locale],
|
|
47
|
+
...newTranslations
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
hasGeneralTranslation(locale) {
|
|
51
|
+
return !!generalLocaleCache[locale];
|
|
52
|
+
},
|
|
53
|
+
hasPageTranslation(locale, routeName) {
|
|
54
|
+
return !!routeLocaleCache[`${locale}:${routeName}`];
|
|
55
|
+
},
|
|
56
|
+
getTranslation: (locale, routeName, key, useCache) => {
|
|
57
|
+
const cacheKey = `${locale}:${routeName}`;
|
|
58
|
+
if (useCache && serverTranslationCache[cacheKey]) {
|
|
59
|
+
const cached = serverTranslationCache[cacheKey].get(key);
|
|
60
|
+
if (cached) {
|
|
61
|
+
return cached;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const parts = key.split(".");
|
|
65
|
+
let result = null;
|
|
66
|
+
if (dynamicTranslationsCaches.length) {
|
|
67
|
+
for (const dynamicCache of dynamicTranslationsCaches) {
|
|
68
|
+
const value = findTranslation(dynamicCache[locale], parts);
|
|
69
|
+
if (value !== null) {
|
|
70
|
+
result = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!result) {
|
|
75
|
+
const value = findTranslation(routeLocaleCache[`${locale}:${routeName}`], parts);
|
|
76
|
+
if (value !== null) {
|
|
77
|
+
result = value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!result) {
|
|
81
|
+
const value = findTranslation(generalLocaleCache[locale], parts);
|
|
82
|
+
if (value !== null) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (useCache && result) {
|
|
87
|
+
if (!serverTranslationCache[cacheKey]) {
|
|
88
|
+
serverTranslationCache[cacheKey] = /* @__PURE__ */ new Map();
|
|
89
|
+
}
|
|
90
|
+
serverTranslationCache[cacheKey].set(key, result);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
},
|
|
94
|
+
loadPageTranslations: async (locale, routeName, translations) => {
|
|
95
|
+
try {
|
|
96
|
+
if (!routeLocaleCache[`${locale}:${routeName}`]) {
|
|
97
|
+
routeLocaleCache[`${locale}:${routeName}`] = { ...translations };
|
|
98
|
+
serverTranslationInit[`${locale}:${routeName}`] = true;
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(`Error loading translations for ${locale} and ${routeName}:`, error);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
loadTranslations: async (locale, routeName, translations) => {
|
|
105
|
+
try {
|
|
106
|
+
if (!generalLocaleCache[locale]) {
|
|
107
|
+
generalLocaleCache[locale] = { ...translations };
|
|
108
|
+
serverTranslationInit[`${locale}:index`] = true;
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(`Error loading translations for general ${locale}:`, error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-i18n-micro",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"description": "Nuxt I18n Micro is a lightweight, high-performance internationalization module for Nuxt, designed to handle multi-language support with minimal overhead, fast build times, and efficient runtime performance.",
|
|
5
5
|
"repository": "s00d/nuxt-i18n-micro",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"id":"7d3d3cf9-6064-4ba3-a2ec-347447f8edd0","timestamp":1723968282041,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { defineNuxtPlugin, useRuntimeConfig } from "#app";
|
|
2
|
-
import { useRoute, useRouter } from "#imports";
|
|
3
|
-
const generalLocaleCache = {};
|
|
4
|
-
const routeLocaleCache = {};
|
|
5
|
-
const dynamicTranslationsCaches = [];
|
|
6
|
-
function deepClone(value) {
|
|
7
|
-
if (Array.isArray(value)) {
|
|
8
|
-
return value.slice();
|
|
9
|
-
} else if (typeof value === "object" && value !== null) {
|
|
10
|
-
return { ...value };
|
|
11
|
-
}
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
function getTranslation(translations, key) {
|
|
15
|
-
const value = key.split(".").reduce((acc, part) => {
|
|
16
|
-
if (typeof acc === "object" && acc !== null && part in acc) {
|
|
17
|
-
return acc[part];
|
|
18
|
-
}
|
|
19
|
-
return void 0;
|
|
20
|
-
}, translations);
|
|
21
|
-
if (value && typeof value === "object") {
|
|
22
|
-
return deepClone(value);
|
|
23
|
-
}
|
|
24
|
-
return value ?? null;
|
|
25
|
-
}
|
|
26
|
-
function interpolate(template, params) {
|
|
27
|
-
return template.replace(/\{(\w+)\}/g, (_, match) => {
|
|
28
|
-
return params[match] !== void 0 ? String(params[match]) : `{${match}}`;
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
function getPluralTranslation(translations, key) {
|
|
32
|
-
return getTranslation(translations, key);
|
|
33
|
-
}
|
|
34
|
-
async function loadTranslations(locale, routeName, translationDir) {
|
|
35
|
-
try {
|
|
36
|
-
if (!generalLocaleCache[locale]) {
|
|
37
|
-
const translations = await import(`~/${translationDir}/${locale}.json`);
|
|
38
|
-
generalLocaleCache[locale] = { ...translations.default };
|
|
39
|
-
}
|
|
40
|
-
if (!routeLocaleCache[`${locale}:${routeName}`]) {
|
|
41
|
-
const translations = await import(`~/${translationDir}/pages/${routeName}/${locale}.json`);
|
|
42
|
-
routeLocaleCache[`${locale}:${routeName}`] = { ...translations.default };
|
|
43
|
-
}
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error(`Error loading translations for ${locale} and ${routeName}:`, error);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function mergeTranslations(routeName, locale, newTranslations) {
|
|
49
|
-
routeLocaleCache[`${locale}:${routeName}`] = {
|
|
50
|
-
...generalLocaleCache[locale],
|
|
51
|
-
...newTranslations
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function switchLocale(locale, route, router, i18nConfig) {
|
|
55
|
-
const checkLocale = i18nConfig.locales?.find((l) => l.code === locale);
|
|
56
|
-
if (!checkLocale) {
|
|
57
|
-
console.warn(`Locale ${locale} is not available`);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const { defaultLocale } = i18nConfig;
|
|
61
|
-
const routeName = route.name.replace(`localized-`, "");
|
|
62
|
-
const newRouteName = locale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute ? `localized-${routeName}` : routeName;
|
|
63
|
-
const newParams = { ...route.params };
|
|
64
|
-
delete newParams.locale;
|
|
65
|
-
if (locale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute) {
|
|
66
|
-
newParams.locale = locale;
|
|
67
|
-
}
|
|
68
|
-
router.push({ name: newRouteName, params: newParams });
|
|
69
|
-
}
|
|
70
|
-
function getLocalizedRoute(to, router, route, i18nConfig, locale) {
|
|
71
|
-
const { defaultLocale } = i18nConfig;
|
|
72
|
-
const currentLocale = (locale || route.params.locale || defaultLocale).toString();
|
|
73
|
-
const selectRoute = router.resolve(to);
|
|
74
|
-
const routeName = selectRoute.name.replace(`localized-`, "");
|
|
75
|
-
const newRouteName = currentLocale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute ? `localized-${routeName}` : routeName;
|
|
76
|
-
const newParams = { ...route.params };
|
|
77
|
-
delete newParams.locale;
|
|
78
|
-
if (currentLocale !== defaultLocale || i18nConfig.includeDefaultLocaleRoute) {
|
|
79
|
-
newParams.locale = currentLocale;
|
|
80
|
-
}
|
|
81
|
-
return router.resolve({ name: newRouteName, params: newParams });
|
|
82
|
-
}
|
|
83
|
-
export default defineNuxtPlugin(async (_nuxtApp) => {
|
|
84
|
-
const router = useRouter();
|
|
85
|
-
const route = useRoute();
|
|
86
|
-
const config = useRuntimeConfig();
|
|
87
|
-
const i18nConfig = config.public.i18nConfig;
|
|
88
|
-
const initialLocale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
89
|
-
const initialRouteName = route.name.replace(`localized-`, "");
|
|
90
|
-
const plural = new Function("return " + i18nConfig.plural)();
|
|
91
|
-
router.beforeEach(async (to, from, next) => {
|
|
92
|
-
const locale = (to.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
93
|
-
const routeName = to.name.replace(`localized-`, "");
|
|
94
|
-
if (!routeLocaleCache[`${locale}:${routeName}`]) {
|
|
95
|
-
await loadTranslations(locale, routeName, i18nConfig.translationDir);
|
|
96
|
-
}
|
|
97
|
-
next();
|
|
98
|
-
});
|
|
99
|
-
await loadTranslations(initialLocale, initialRouteName, i18nConfig.translationDir);
|
|
100
|
-
return {
|
|
101
|
-
provide: {
|
|
102
|
-
getLocale: () => (route.params?.locale ?? i18nConfig.defaultLocale).toString(),
|
|
103
|
-
getLocales: () => i18nConfig.locales || [],
|
|
104
|
-
t: (key, params, defaultValue) => {
|
|
105
|
-
if (!key) {
|
|
106
|
-
console.log(`$t: key not exist`);
|
|
107
|
-
return "";
|
|
108
|
-
}
|
|
109
|
-
const locale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
110
|
-
const routeName = route.name.replace(`localized-`, "");
|
|
111
|
-
let value = getTranslation(routeLocaleCache[`${locale}:${routeName}`] ?? {}, key) || getTranslation(generalLocaleCache[locale] ?? {}, key) || dynamicTranslationsCaches.reduce((result, cache) => {
|
|
112
|
-
return result || getTranslation(cache[locale] ?? {}, key);
|
|
113
|
-
}, null);
|
|
114
|
-
if (!value) {
|
|
115
|
-
value = defaultValue || key;
|
|
116
|
-
}
|
|
117
|
-
if (typeof value === "string" && params) {
|
|
118
|
-
value = interpolate(value, params);
|
|
119
|
-
}
|
|
120
|
-
return value;
|
|
121
|
-
},
|
|
122
|
-
tc: (key, count, defaultValue) => {
|
|
123
|
-
if (!key) {
|
|
124
|
-
console.log(`$tc: key not exist`);
|
|
125
|
-
return "";
|
|
126
|
-
}
|
|
127
|
-
const locale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
128
|
-
const routeName = route.name.replace(`localized-`, "");
|
|
129
|
-
let translation = getPluralTranslation(routeLocaleCache[`${locale}:${routeName}`] ?? {}, key) || getPluralTranslation(generalLocaleCache[locale] ?? {}, key) || dynamicTranslationsCaches.reduce((result, cache) => {
|
|
130
|
-
return result || getPluralTranslation(cache[locale] ?? {}, key);
|
|
131
|
-
}, null);
|
|
132
|
-
if (!translation) {
|
|
133
|
-
translation = defaultValue || key;
|
|
134
|
-
}
|
|
135
|
-
return plural(translation.toString(), count, locale);
|
|
136
|
-
},
|
|
137
|
-
mergeTranslations: (newTranslations) => {
|
|
138
|
-
const routeName = route.name.replace(`localized-`, "");
|
|
139
|
-
const locale = (route.params?.locale ?? i18nConfig.defaultLocale).toString();
|
|
140
|
-
mergeTranslations(routeName, locale, newTranslations);
|
|
141
|
-
},
|
|
142
|
-
switchLocale: (locale) => {
|
|
143
|
-
switchLocale(locale, route, router, i18nConfig);
|
|
144
|
-
},
|
|
145
|
-
localeRoute: (to, locale) => {
|
|
146
|
-
return getLocalizedRoute(to, router, route, i18nConfig, locale);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|