nuxt-i18n-micro 2.12.0 → 2.13.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.
@@ -8,5 +8,5 @@
8
8
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/CBxwnKtU.js">
9
9
  <link rel="prefetch" as="style" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/error-500.BqKd8Zt-.css">
10
10
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/BYEpoBUk.js">
11
- <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1763994971266,false]</script>
12
- <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"01201220-c0fd-464a-8476-6d05efe648a4",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
11
+ <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1764747146016,false]</script>
12
+ <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"f40c5766-8279-4da4-899a-f27704c47097",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
@@ -8,5 +8,5 @@
8
8
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/CBxwnKtU.js">
9
9
  <link rel="prefetch" as="style" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/error-500.BqKd8Zt-.css">
10
10
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/BYEpoBUk.js">
11
- <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1763994971267,false]</script>
12
- <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"01201220-c0fd-464a-8476-6d05efe648a4",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
11
+ <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1764747146016,false]</script>
12
+ <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"f40c5766-8279-4da4-899a-f27704c47097",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
@@ -1 +1 @@
1
- {"id":"01201220-c0fd-464a-8476-6d05efe648a4","timestamp":1763994964382}
1
+ {"id":"f40c5766-8279-4da4-899a-f27704c47097","timestamp":1764747140130}
@@ -0,0 +1 @@
1
+ {"id":"f40c5766-8279-4da4-899a-f27704c47097","timestamp":1764747140130,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
@@ -8,5 +8,5 @@
8
8
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/CBxwnKtU.js">
9
9
  <link rel="prefetch" as="style" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/error-500.BqKd8Zt-.css">
10
10
  <link rel="prefetch" as="script" crossorigin href="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/BYEpoBUk.js">
11
- <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1763994971267,false]</script>
12
- <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"01201220-c0fd-464a-8476-6d05efe648a4",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
11
+ <script type="module" src="/__NUXT_DEVTOOLS_I18N_BASE__/_nuxt/XZXfxmri.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1764747146016,false]</script>
12
+ <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__NUXT_DEVTOOLS_I18N_BASE__/",buildId:"f40c5766-8279-4da4-899a-f27704c47097",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
3
  "configKey": "i18n",
4
- "version": "2.12.0",
4
+ "version": "2.13.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -3,7 +3,7 @@
3
3
  </template>
4
4
 
5
5
  <script setup>
6
- import { useRoute, useRouter, useI18n, createError, navigateTo, useRuntimeConfig } from "#imports";
6
+ import { useRoute, useRouter, useI18n, createError, navigateTo, useRuntimeConfig, showError } from "#imports";
7
7
  import { isInternalPath } from "../utils/path-utils";
8
8
  import { isPrefixStrategy, isPrefixExceptDefaultStrategy } from "nuxt-i18n-micro-core";
9
9
  const route = useRoute();
@@ -17,10 +17,17 @@ const defaultLocale = $defaultLocale() || "en";
17
17
  const pathSegments = route.fullPath.split("/");
18
18
  const firstSegment = pathSegments[1];
19
19
  if (isInternalPath(route.fullPath, i18nConfig?.excludePatterns)) {
20
- throw createError({
21
- statusCode: 404,
22
- statusMessage: "Static file - should not be processed by i18n"
23
- });
20
+ if (import.meta.client) {
21
+ showError({
22
+ statusCode: 404,
23
+ statusMessage: "Static file - should not be processed by i18n"
24
+ });
25
+ } else {
26
+ throw createError({
27
+ statusCode: 404,
28
+ statusMessage: "Static file - should not be processed by i18n"
29
+ });
30
+ }
24
31
  }
25
32
  const handleRedirect = (path) => {
26
33
  const finalPath = route.query && Object.keys(route.query).length > 0 ? `${path}?${new URLSearchParams(route.query).toString()}` : path;
@@ -41,31 +48,74 @@ const routeExists = (path) => {
41
48
  };
42
49
  const globalLocaleRoutes = route.meta.globalLocaleRoutes ?? {};
43
50
  const currentPageName = route.path.split("/").filter(Boolean).join("-");
51
+ let shouldThrow404 = false;
52
+ let redirectHandled = false;
44
53
  if (locales.includes(firstSegment)) {
45
54
  const pathWithoutPrefix = "/" + pathSegments.slice(2).join("/");
46
55
  if (isPrefixExceptDefaultStrategy(strategy) && firstSegment === defaultLocale) {
47
- throw createError({
48
- statusCode: 404,
49
- statusMessage: `Page not found for default locale with prefix ('${firstSegment}')`
50
- });
56
+ if (import.meta.client) {
57
+ showError({
58
+ statusCode: 404,
59
+ statusMessage: `Page not found for default locale with prefix ('${firstSegment}')`
60
+ });
61
+ } else {
62
+ throw createError({
63
+ statusCode: 404,
64
+ statusMessage: `Page not found for default locale with prefix ('${firstSegment}')`
65
+ });
66
+ }
51
67
  }
52
68
  const customPath = globalLocaleRoutes[currentPageName]?.[firstSegment];
53
69
  if (customPath && customPath !== pathWithoutPrefix) {
54
70
  handleRedirect(`/${firstSegment}${customPath}`);
71
+ redirectHandled = true;
72
+ } else if (isPrefixExceptDefaultStrategy(strategy) && firstSegment !== defaultLocale) {
73
+ if (!routeExists(route.fullPath)) {
74
+ shouldThrow404 = true;
75
+ }
76
+ } else if (isPrefixStrategy(strategy)) {
77
+ if (!routeExists(route.fullPath)) {
78
+ shouldThrow404 = true;
79
+ }
80
+ } else {
81
+ if (!redirectHandled) {
82
+ shouldThrow404 = true;
83
+ }
55
84
  }
56
85
  } else {
57
86
  const customPath = globalLocaleRoutes[currentPageName]?.[defaultLocale];
58
87
  if (customPath && customPath !== route.fullPath) {
59
88
  const targetPath = isPrefixStrategy(strategy) ? `/${defaultLocale}${customPath}` : customPath;
60
89
  handleRedirect(targetPath);
90
+ redirectHandled = true;
61
91
  } else if (isPrefixStrategy(strategy)) {
62
92
  const newPathWithPrefix = `/${defaultLocale}${route.fullPath}`;
63
93
  if (routeExists(newPathWithPrefix)) {
64
94
  handleRedirect(newPathWithPrefix);
95
+ redirectHandled = true;
96
+ } else {
97
+ shouldThrow404 = true;
98
+ }
99
+ } else if (isPrefixExceptDefaultStrategy(strategy)) {
100
+ if (!routeExists(route.fullPath)) {
101
+ shouldThrow404 = true;
65
102
  }
103
+ } else {
104
+ if (!redirectHandled) {
105
+ shouldThrow404 = true;
106
+ }
107
+ }
108
+ }
109
+ if (shouldThrow404) {
110
+ if (import.meta.client) {
111
+ showError({
112
+ statusCode: 404,
113
+ statusMessage: "Page Not Found"
114
+ });
115
+ } else {
116
+ throw createError({
117
+ statusCode: 404
118
+ });
66
119
  }
67
120
  }
68
- throw createError({
69
- statusCode: 404
70
- });
71
121
  </script>
@@ -3,7 +3,12 @@ import { useRuntimeConfig } from "#imports";
3
3
  export const useLocaleServerMiddleware = (event, defaultLocale, currentLocale) => {
4
4
  const config = useRuntimeConfig(event);
5
5
  const { locales, defaultLocale: configDefaultLocale, fallbackLocale } = config.public.i18nConfig;
6
- const detectedLocale = currentLocale || detectCurrentLocale(event, { fallbackLocale, defaultLocale: defaultLocale || configDefaultLocale });
6
+ const detectedLocale = currentLocale || detectCurrentLocale(event, {
7
+ fallbackLocale,
8
+ defaultLocale: defaultLocale || configDefaultLocale,
9
+ locales
10
+ // Pass the list of locales
11
+ });
7
12
  const localeConfig = locales?.find((l) => l.code === detectedLocale) ?? null;
8
13
  const availableLocales = locales?.map((l) => l.code) ?? [];
9
14
  const isDefault = detectedLocale === (defaultLocale || configDefaultLocale || "en");
@@ -30,8 +30,13 @@ export const useTranslationServerMiddleware = async (event, defaultLocale, curre
30
30
  }
31
31
  const requestScopedCache = event.context[I18N_CONTEXT_KEY];
32
32
  const { getTranslation, loadTranslations, hasGeneralTranslation } = useTranslationHelper(requestScopedCache);
33
- const config = useRuntimeConfig(event).i18nConfig;
34
- const locale = currentLocale || detectCurrentLocale(event, config, defaultLocale);
33
+ const config = useRuntimeConfig(event).public.i18nConfig;
34
+ const { locales, fallbackLocale, defaultLocale: configDefaultLocale } = config;
35
+ const locale = currentLocale || detectCurrentLocale(event, {
36
+ fallbackLocale,
37
+ defaultLocale: defaultLocale || configDefaultLocale,
38
+ locales
39
+ }, defaultLocale);
35
40
  if (!hasGeneralTranslation(locale)) {
36
41
  const translations = await fetchTranslations(locale);
37
42
  await loadTranslations(locale, translations);
@@ -5,10 +5,14 @@ import type { H3Event } from 'h3';
5
5
  * @param config - Runtime configuration with i18n settings
6
6
  * @param config.fallbackLocale - Fallback locale from config
7
7
  * @param config.defaultLocale - Default locale from config
8
+ * @param config.locales - List of available locales
8
9
  * @param defaultLocale - Optional default locale override
9
10
  * @returns The detected locale code
10
11
  */
11
12
  export declare const detectCurrentLocale: (event: H3Event, config: {
12
13
  fallbackLocale?: string;
13
14
  defaultLocale?: string;
15
+ locales?: {
16
+ code: string;
17
+ }[];
14
18
  }, defaultLocale?: string) => string;
@@ -1,5 +1,20 @@
1
- import { getQuery, getCookie } from "h3";
1
+ import { getQuery, getCookie, getRequestURL } from "h3";
2
2
  export const detectCurrentLocale = (event, config, defaultLocale) => {
3
- const { fallbackLocale, defaultLocale: configDefaultLocale } = config;
4
- return (event.context.params?.locale || getQuery(event)?.locale || getCookie(event, "user-locale") || event.headers.get("accept-language")?.split(",")[0] || fallbackLocale || defaultLocale || configDefaultLocale || "en").toString();
3
+ const { fallbackLocale, defaultLocale: configDefaultLocale, locales } = config;
4
+ if (event.context.params?.locale) {
5
+ return event.context.params.locale.toString();
6
+ }
7
+ const queryLocale = getQuery(event)?.locale;
8
+ if (queryLocale) {
9
+ return queryLocale.toString();
10
+ }
11
+ if (locales && locales.length > 0) {
12
+ const url = getRequestURL(event);
13
+ const cleanPath = url.pathname.split("?")[0].split("#")[0];
14
+ const firstSegment = cleanPath.split("/").filter(Boolean)[0];
15
+ if (firstSegment && locales.some((l) => l.code === firstSegment)) {
16
+ return firstSegment;
17
+ }
18
+ }
19
+ return (getCookie(event, "user-locale") || event.headers.get("accept-language")?.split(",")[0] || fallbackLocale || defaultLocale || configDefaultLocale || "en").toString();
5
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
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",
@@ -61,9 +61,9 @@
61
61
  "globby": "^14.1.0",
62
62
  "sirv": "^2.0.4",
63
63
  "ufo": "^1.5.4",
64
- "nuxt-i18n-micro-core": "1.0.25",
65
- "nuxt-i18n-micro-test-utils": "1.0.7",
66
- "nuxt-i18n-micro-types": "1.0.15"
64
+ "nuxt-i18n-micro-core": "1.0.26",
65
+ "nuxt-i18n-micro-types": "1.0.15",
66
+ "nuxt-i18n-micro-test-utils": "1.0.7"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@nuxt/devtools": "^2.6.3",
@@ -1 +0,0 @@
1
- {"id":"01201220-c0fd-464a-8476-6d05efe648a4","timestamp":1763994964382,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}