@verbaly/nuxt 0.47.0 → 0.49.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/README.md +3 -2
- package/dist/runtime/plugin.js +11 -3
- package/dist/runtime/plugin.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
Server-rendered pages arrive already translated in the visitor's language (
|
|
14
|
+
Server-rendered pages arrive already translated in the visitor's language (the address first when your URLs carry it, then the cookie, then `Accept-Language`, then your fallback) and the client hydrates with the **same locale and the same catalog**, so there's no flash of untranslated text and no hydration mismatch. Each request gets its **own instance**: no locale leaking between concurrent users.
|
|
15
15
|
|
|
16
16
|
One line in `nuxt.config` wires everything: the Vite plugin (live extraction + the `virtual:verbaly` module), the per-request negotiation and `<html lang>`/`<html dir>`.
|
|
17
17
|
|
|
@@ -65,7 +65,7 @@ const verbaly = useVerbaly();
|
|
|
65
65
|
</template>
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
That's it. The module
|
|
68
|
+
That's it. The module resolves the locale per request (URL → cookie → `Accept-Language` → fallback), awaits the catalog **before** render, installs the Vue plugin, and keeps `<html lang>` and `<html dir>` in sync.
|
|
69
69
|
|
|
70
70
|
## 📖 Options
|
|
71
71
|
|
|
@@ -76,6 +76,7 @@ Via the `verbaly` key in `nuxt.config` or inline module options (fully typed in
|
|
|
76
76
|
| `cookie` | Cookie read/written for the user's choice (default `verbaly-locale`); `false` = `Accept-Language` only. |
|
|
77
77
|
| `fallback` | Locale when nothing matches (defaults to the source locale). |
|
|
78
78
|
|
|
79
|
+
- **When your URLs carry the language, the address decides it** and the cookie is not consulted: on `/es/docs` a visitor gets Spanish whatever they picked before, and on an unprefixed page they get your source language. That follows your `routing` setting; nothing to configure here.
|
|
79
80
|
- No dependency on `nuxt` or `@nuxt/kit`: the module is typed structurally; the only moving parts are core primitives (`resolveRequestLocale`) and the generated `createRequestInstance`.
|
|
80
81
|
- For fully static sites (`nuxi generate`), consider [`verbaly render`](https://www.npmjs.com/package/@verbaly/compiler) for pre-translated output per locale.
|
|
81
82
|
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { defineNuxtPlugin, useHead, useRuntimeConfig, useState } from "#imports";
|
|
1
|
+
import { defineNuxtPlugin, useHead, useRequestURL, useRuntimeConfig, useState } from "#imports";
|
|
2
2
|
import { verbalyPlugin } from "@verbaly/vue";
|
|
3
3
|
import { LOCALE_STORAGE_KEY, localeDirection, resolveRequestLocale } from "verbaly";
|
|
4
|
-
import { createRequestInstance, locales, sourceLocale } from "virtual:verbaly";
|
|
4
|
+
import { createRequestInstance, locales, routing, sourceLocale } from "virtual:verbaly";
|
|
5
5
|
import { shallowRef } from "vue";
|
|
6
6
|
//#region src/runtime/plugin.ts
|
|
7
7
|
function readCookie(header, name) {
|
|
@@ -20,19 +20,27 @@ function readCookie(header, name) {
|
|
|
20
20
|
}
|
|
21
21
|
var plugin_default = defineNuxtPlugin(async (nuxtApp) => {
|
|
22
22
|
if (!Array.isArray(locales) || locales.length === 0) throw new Error("[verbaly] no `locales` in 'virtual:verbaly': declare them in verbaly.config or in the module options (`verbaly: { locales: [...] }` in nuxt.config)");
|
|
23
|
-
const
|
|
23
|
+
const runtime = useRuntimeConfig();
|
|
24
|
+
const config = runtime.public.verbaly ?? {};
|
|
24
25
|
const cookieName = config.cookie === false ? false : config.cookie || LOCALE_STORAGE_KEY;
|
|
25
26
|
const fallback = config.fallback ?? sourceLocale;
|
|
27
|
+
const url = {
|
|
28
|
+
path: useRequestURL().pathname,
|
|
29
|
+
routing,
|
|
30
|
+
base: runtime.app?.baseURL
|
|
31
|
+
};
|
|
26
32
|
const locale = useState("verbaly:locale", () => {
|
|
27
33
|
const headers = nuxtApp.ssrContext?.event?.headers;
|
|
28
34
|
if (headers) return resolveRequestLocale({
|
|
29
35
|
supported: locales,
|
|
36
|
+
...url,
|
|
30
37
|
cookie: cookieName ? readCookie(headers.get("cookie"), cookieName) : void 0,
|
|
31
38
|
header: headers.get("accept-language"),
|
|
32
39
|
fallback
|
|
33
40
|
});
|
|
34
41
|
return resolveRequestLocale({
|
|
35
42
|
supported: locales,
|
|
43
|
+
...url,
|
|
36
44
|
cookie: cookieName && typeof document !== "undefined" ? readCookie(document.cookie, cookieName) : void 0,
|
|
37
45
|
header: typeof navigator !== "undefined" ? navigator.languages?.join(",") ?? navigator.language : void 0,
|
|
38
46
|
fallback
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useHead, useRuntimeConfig, useState } from '#imports';\nimport { verbalyPlugin, type VerbalyPlugin } from '@verbaly/vue';\nimport { LOCALE_STORAGE_KEY, localeDirection, resolveRequestLocale } from 'verbaly';\nimport { createRequestInstance, locales, sourceLocale } from 'virtual:verbaly';\nimport { shallowRef } from 'vue';\n\ninterface VerbalyRuntimeConfig {\n cookie?: string | false;\n fallback?: string;\n}\n\n// structural subset of NuxtApp: the real one arrives at runtime\ninterface NuxtAppLike {\n vueApp: { use(plugin: VerbalyPlugin): unknown };\n ssrContext?: { event?: { headers?: { get(name: string): string | null } } };\n}\n\n// one cookie value out of a Cookie header / document.cookie\nfunction readCookie(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined;\n for (const part of header.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n if (part.slice(0, eq).trim() !== name) continue;\n const value = part.slice(eq + 1).trim();\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n }\n return undefined;\n}\n\nexport default defineNuxtPlugin(async (nuxtApp: NuxtAppLike) => {\n if (!Array.isArray(locales) || locales.length === 0) {\n throw new Error(\n \"[verbaly] no `locales` in 'virtual:verbaly': declare them in verbaly.config \" +\n 'or in the module options (`verbaly: { locales: [...] }` in nuxt.config)',\n );\n }\n const
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useHead, useRequestURL, useRuntimeConfig, useState } from '#imports';\nimport { verbalyPlugin, type VerbalyPlugin } from '@verbaly/vue';\nimport { LOCALE_STORAGE_KEY, localeDirection, resolveRequestLocale } from 'verbaly';\nimport { createRequestInstance, locales, routing, sourceLocale } from 'virtual:verbaly';\nimport { shallowRef } from 'vue';\n\ninterface VerbalyRuntimeConfig {\n cookie?: string | false;\n fallback?: string;\n}\n\n// structural subset of NuxtApp: the real one arrives at runtime\ninterface NuxtAppLike {\n vueApp: { use(plugin: VerbalyPlugin): unknown };\n ssrContext?: { event?: { headers?: { get(name: string): string | null } } };\n}\n\n// one cookie value out of a Cookie header / document.cookie\nfunction readCookie(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined;\n for (const part of header.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n if (part.slice(0, eq).trim() !== name) continue;\n const value = part.slice(eq + 1).trim();\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n }\n return undefined;\n}\n\nexport default defineNuxtPlugin(async (nuxtApp: NuxtAppLike) => {\n if (!Array.isArray(locales) || locales.length === 0) {\n throw new Error(\n \"[verbaly] no `locales` in 'virtual:verbaly': declare them in verbaly.config \" +\n 'or in the module options (`verbaly: { locales: [...] }` in nuxt.config)',\n );\n }\n const runtime = useRuntimeConfig();\n const config = (runtime.public.verbaly ?? {}) as VerbalyRuntimeConfig;\n const cookieName = config.cookie === false ? false : config.cookie || LOCALE_STORAGE_KEY;\n const fallback = config.fallback ?? sourceLocale;\n // the address is the same on both sides of hydration, unlike the header and the cookie\n const url = { path: useRequestURL().pathname, routing, base: runtime.app?.baseURL };\n\n // negotiated on the server, hydrated from the payload: the client renders the same locale\n const locale = useState<string>('verbaly:locale', () => {\n const headers = nuxtApp.ssrContext?.event?.headers;\n if (headers) {\n return resolveRequestLocale({\n supported: locales,\n ...url,\n cookie: cookieName ? readCookie(headers.get('cookie'), cookieName) : undefined,\n header: headers.get('accept-language'),\n fallback,\n });\n }\n // client-only app (ssr: false): url → cookie → navigator.languages → fallback\n return resolveRequestLocale({\n supported: locales,\n ...url,\n cookie:\n cookieName && typeof document !== 'undefined'\n ? readCookie(document.cookie, cookieName)\n : undefined,\n header:\n typeof navigator !== 'undefined'\n ? (navigator.languages?.join(',') ?? navigator.language)\n : undefined,\n fallback,\n });\n });\n\n // fresh instance per request, catalog awaited BEFORE render: the no-FOUC contract\n const instance = await createRequestInstance(locale.value);\n nuxtApp.vueApp.use(verbalyPlugin(instance));\n\n // <html lang> and <html dir> follow the live locale\n const lang = shallowRef(instance.locale);\n const dir = shallowRef(localeDirection(instance.locale));\n instance.subscribe(() => {\n lang.value = instance.locale;\n dir.value = localeDirection(instance.locale);\n });\n useHead({ htmlAttrs: { lang, dir } });\n});\n"],"mappings":";;;;;;AAkBA,SAAS,WAAW,QAAmC,MAAkC;CACvF,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,KAAK,MAAM,QAAQ,OAAO,MAAM,GAAG,GAAG;EACpC,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,IAAI,OAAO,IAAI;EACf,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,MAAM,MAAM;EACvC,MAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK;EACtC,IAAI;GACF,OAAO,mBAAmB,KAAK;EACjC,QAAQ;GACN,OAAO;EACT;CACF;AAEF;AAEA,IAAA,iBAAe,iBAAiB,OAAO,YAAyB;CAC9D,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAChD,MAAM,IAAI,MACR,qJAEF;CAEF,MAAM,UAAU,iBAAiB;CACjC,MAAM,SAAU,QAAQ,OAAO,WAAW,CAAC;CAC3C,MAAM,aAAa,OAAO,WAAW,QAAQ,QAAQ,OAAO,UAAU;CACtE,MAAM,WAAW,OAAO,YAAY;CAEpC,MAAM,MAAM;EAAE,MAAM,cAAc,CAAC,CAAC;EAAU;EAAS,MAAM,QAAQ,KAAK;CAAQ;CAGlF,MAAM,SAAS,SAAiB,wBAAwB;EACtD,MAAM,UAAU,QAAQ,YAAY,OAAO;EAC3C,IAAI,SACF,OAAO,qBAAqB;GAC1B,WAAW;GACX,GAAG;GACH,QAAQ,aAAa,WAAW,QAAQ,IAAI,QAAQ,GAAG,UAAU,IAAI,KAAA;GACrE,QAAQ,QAAQ,IAAI,iBAAiB;GACrC;EACF,CAAC;EAGH,OAAO,qBAAqB;GAC1B,WAAW;GACX,GAAG;GACH,QACE,cAAc,OAAO,aAAa,cAC9B,WAAW,SAAS,QAAQ,UAAU,IACtC,KAAA;GACN,QACE,OAAO,cAAc,cAChB,UAAU,WAAW,KAAK,GAAG,KAAK,UAAU,WAC7C,KAAA;GACN;EACF,CAAC;CACH,CAAC;CAGD,MAAM,WAAW,MAAM,sBAAsB,OAAO,KAAK;CACzD,QAAQ,OAAO,IAAI,cAAc,QAAQ,CAAC;CAG1C,MAAM,OAAO,WAAW,SAAS,MAAM;CACvC,MAAM,MAAM,WAAW,gBAAgB,SAAS,MAAM,CAAC;CACvD,SAAS,gBAAgB;EACvB,KAAK,QAAQ,SAAS;EACtB,IAAI,QAAQ,gBAAgB,SAAS,MAAM;CAC7C,CAAC;CACD,QAAQ,EAAE,WAAW;EAAE;EAAM;CAAI,EAAE,CAAC;AACtC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verbaly/nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"description": "Nuxt integration for Verbaly: zero-config module with per-request locale negotiation and flash-free hydration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -41,20 +41,20 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@verbaly/compiler": "^0.
|
|
45
|
-
"@verbaly/vite": "^0.
|
|
44
|
+
"@verbaly/compiler": "^0.49.0",
|
|
45
|
+
"@verbaly/vite": "^0.49.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"vue": "^3.4.0",
|
|
49
|
-
"@verbaly/vue": "^0.
|
|
50
|
-
"verbaly": "^0.
|
|
49
|
+
"@verbaly/vue": "^0.49.0",
|
|
50
|
+
"verbaly": "^0.49.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@nuxt/schema": "^4.5.2",
|
|
54
|
-
"happy-dom": "^20.12.
|
|
54
|
+
"happy-dom": "^20.12.1",
|
|
55
55
|
"vue": "^3.5.42",
|
|
56
|
-
"@verbaly/vue": "^0.
|
|
57
|
-
"verbaly": "^0.
|
|
56
|
+
"@verbaly/vue": "^0.49.0",
|
|
57
|
+
"verbaly": "^0.49.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "tsdown",
|