@i18n-micro/utils 1.0.1 → 1.0.3
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 -0
- package/dist/merge-i18n-head.cjs +1 -0
- package/dist/merge-i18n-head.d.cts +12 -0
- package/dist/merge-i18n-head.d.ts +12 -0
- package/dist/merge-i18n-head.mjs +97 -0
- package/dist/resolve-og-locale.cjs +1 -0
- package/dist/resolve-og-locale.d.cts +17 -0
- package/dist/resolve-og-locale.d.ts +17 -0
- package/dist/resolve-og-locale.mjs +30 -0
- package/package.json +24 -2
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@ import { findAllowedLocalesForRoute } from '@i18n-micro/utils/route'
|
|
|
9
9
|
import { extractBaseRoutePattern } from '@i18n-micro/utils/route-pattern'
|
|
10
10
|
import { resolveI18nConfigWithRuntimeOverrides } from '@i18n-micro/utils/runtime-config'
|
|
11
11
|
import { preMergeLocales } from '@i18n-micro/utils/build'
|
|
12
|
+
import { mergeI18nHead } from '@i18n-micro/utils/merge-i18n-head'
|
|
12
13
|
```
|
|
13
14
|
|
|
15
|
+
`mergeI18nHead` merges `useLocaleHead` output with page-level overrides (`I18nHeadInput`). Used by the `02.meta` plugin; import it directly for custom tooling or unit tests that need the same merge rules (replace hreflang/canonical/og, disable groups, append meta/link).
|
|
16
|
+
|
|
14
17
|
No Vue, Nuxt, or Nitro dependencies. `sideEffects: false` for tree-shaking friendly bundlers.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("./resolve-og-locale.cjs");function u(e){return e.rel==="alternate"}function s(e){return e.rel==="alternate"&&e.hreflang==="x-default"}function m(e){return e.rel==="alternate"&&e.hreflang!=="x-default"}function g(e,t){const n=e[t];return n?`id:${n}`:e.property?`property:${e.property}`:e.name?`name:${e.name}`:`meta:${JSON.stringify(e)}`}function A(e,t){const n=e[t];return n?`id:${n}`:`link:${e.rel}:${e.hreflang??""}`}function p(e,t){const n=new Set([A(e,t)]);return e.rel==="alternate"&&e.hreflang&&n.add(`link:${e.rel}:${e.hreflang}`),e.rel==="canonical"&&n.add("link:canonical:"),[...n]}function $(e,t,n){if(g(e,n)===g(t,n)||t.property&&e.property===t.property||t.name&&e.name===t.name)return!0;const o=t[n];return!!(o&&e[n]===o)}function L(e,t,n){const o=e.filter(i=>!$(i,t,n));return o.push(t),o}function k(e,t,n){const o=new Set(p(t,n)),i=e.filter(c=>!p(c,n).some(l=>o.has(l)));return i.push(t),i}function x(e,t,n){let o=!1;const i=e.map(c=>c.rel!=="canonical"?c:(o=!0,{...c,href:t}));return o||i.unshift({[n]:"i18n-can",rel:"canonical",href:t}),i}function h(e,t,n,o,i){const c=e.filter(l=>l.property!==t);return c.push({[o]:t==="og:locale"?"i18n-og":t==="og:url"?"i18n-og-url":`i18n-page-${t}`,property:t,content:n}),c}function S(e,t,n,o){const i=[];for(const c of e){if(n&&c===n)continue;const l=t.find(f=>f.code===c);if(!l)continue;const a=d.resolveOgLocale(l);a&&i.push({[o]:`i18n-og-alt-${a}`,property:"og:locale:alternate",content:a})}return i}function M(e,t,n={}){if(!t)return{htmlAttrs:{...e.htmlAttrs},meta:[...e.meta],link:[...e.link]};const o=n.identifierAttribute??"id",i=new Set(t.disable??[]);let c={...e.htmlAttrs},l=[...e.meta],a=[...e.link];i.has("html")&&(c={}),i.has("hreflang")&&(a=a.filter(r=>!m(r))),i.has("x-default")&&(a=a.filter(r=>!s(r))),i.has("canonical")&&(a=a.filter(r=>r.rel!=="canonical")),i.has("og")&&(l=l.filter(r=>r.property!=="og:locale"&&r.property!=="og:url")),i.has("og-alternates")&&(l=l.filter(r=>r.property!=="og:locale:alternate"));const f=t.replace;if(f){if(f.canonical===!1?a=a.filter(r=>r.rel!=="canonical"):typeof f.canonical=="string"&&(a=x(a,f.canonical,o)),f.hreflang===!1?a=a.filter(r=>!u(r)):Array.isArray(f.hreflang)&&(a=a.filter(r=>!u(r)),a.push(...f.hreflang)),f.xDefault===!1?a=a.filter(r=>!s(r)):f.xDefault&&(a=a.filter(r=>!s(r)),a.push(f.xDefault)),f.ogLocale===!1?l=l.filter(r=>r.property!=="og:locale"):typeof f.ogLocale=="string"&&(l=h(l,"og:locale",f.ogLocale,o)),f.ogUrl===!1?l=l.filter(r=>r.property!=="og:url"):typeof f.ogUrl=="string"&&(l=h(l,"og:url",f.ogUrl,o)),f.ogAlternates===!1)l=l.filter(r=>r.property!=="og:locale:alternate");else if(Array.isArray(f.ogAlternates)){l=l.filter(y=>y.property!=="og:locale:alternate");const r=n.locales??[];l.push(...S(f.ogAlternates,r,n.currentLocale,o))}}t.htmlAttrs&&(c={...c,...t.htmlAttrs});for(const r of t.meta??[])l=L(l,r,o);for(const r of t.link??[])a=k(a,r,o);return{htmlAttrs:c,meta:l,link:a}}exports.mergeI18nHead=M;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { I18nHeadInput, I18nHeadLink, I18nHeadMeta, Locale } from '@i18n-micro/types';
|
|
2
|
+
export interface I18nHeadObject {
|
|
3
|
+
htmlAttrs: Record<string, string | undefined>;
|
|
4
|
+
meta: I18nHeadMeta[];
|
|
5
|
+
link: I18nHeadLink[];
|
|
6
|
+
}
|
|
7
|
+
export interface MergeI18nHeadOptions {
|
|
8
|
+
identifierAttribute?: string;
|
|
9
|
+
locales?: Locale[];
|
|
10
|
+
currentLocale?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function mergeI18nHead(base: I18nHeadObject, override: I18nHeadInput | null | undefined, options?: MergeI18nHeadOptions): I18nHeadObject;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { I18nHeadInput, I18nHeadLink, I18nHeadMeta, Locale } from '@i18n-micro/types';
|
|
2
|
+
export interface I18nHeadObject {
|
|
3
|
+
htmlAttrs: Record<string, string | undefined>;
|
|
4
|
+
meta: I18nHeadMeta[];
|
|
5
|
+
link: I18nHeadLink[];
|
|
6
|
+
}
|
|
7
|
+
export interface MergeI18nHeadOptions {
|
|
8
|
+
identifierAttribute?: string;
|
|
9
|
+
locales?: Locale[];
|
|
10
|
+
currentLocale?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function mergeI18nHead(base: I18nHeadObject, override: I18nHeadInput | null | undefined, options?: MergeI18nHeadOptions): I18nHeadObject;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { resolveOgLocale as d } from "./resolve-og-locale.mjs";
|
|
2
|
+
function u(e) {
|
|
3
|
+
return e.rel === "alternate";
|
|
4
|
+
}
|
|
5
|
+
function s(e) {
|
|
6
|
+
return e.rel === "alternate" && e.hreflang === "x-default";
|
|
7
|
+
}
|
|
8
|
+
function m(e) {
|
|
9
|
+
return e.rel === "alternate" && e.hreflang !== "x-default";
|
|
10
|
+
}
|
|
11
|
+
function p(e, t) {
|
|
12
|
+
const n = e[t];
|
|
13
|
+
return n ? `id:${n}` : e.property ? `property:${e.property}` : e.name ? `name:${e.name}` : `meta:${JSON.stringify(e)}`;
|
|
14
|
+
}
|
|
15
|
+
function A(e, t) {
|
|
16
|
+
const n = e[t];
|
|
17
|
+
return n ? `id:${n}` : `link:${e.rel}:${e.hreflang ?? ""}`;
|
|
18
|
+
}
|
|
19
|
+
function g(e, t) {
|
|
20
|
+
const n = /* @__PURE__ */ new Set([A(e, t)]);
|
|
21
|
+
return e.rel === "alternate" && e.hreflang && n.add(`link:${e.rel}:${e.hreflang}`), e.rel === "canonical" && n.add("link:canonical:"), [...n];
|
|
22
|
+
}
|
|
23
|
+
function $(e, t, n) {
|
|
24
|
+
if (p(e, n) === p(t, n) || t.property && e.property === t.property || t.name && e.name === t.name) return !0;
|
|
25
|
+
const o = t[n];
|
|
26
|
+
return !!(o && e[n] === o);
|
|
27
|
+
}
|
|
28
|
+
function L(e, t, n) {
|
|
29
|
+
const o = e.filter((i) => !$(i, t, n));
|
|
30
|
+
return o.push(t), o;
|
|
31
|
+
}
|
|
32
|
+
function x(e, t, n) {
|
|
33
|
+
const o = new Set(g(t, n)), i = e.filter((c) => !g(c, n).some((l) => o.has(l)));
|
|
34
|
+
return i.push(t), i;
|
|
35
|
+
}
|
|
36
|
+
function k(e, t, n) {
|
|
37
|
+
let o = !1;
|
|
38
|
+
const i = e.map((c) => c.rel !== "canonical" ? c : (o = !0, { ...c, href: t }));
|
|
39
|
+
return o || i.unshift({
|
|
40
|
+
[n]: "i18n-can",
|
|
41
|
+
rel: "canonical",
|
|
42
|
+
href: t
|
|
43
|
+
}), i;
|
|
44
|
+
}
|
|
45
|
+
function h(e, t, n, o, i) {
|
|
46
|
+
const c = e.filter((l) => l.property !== t);
|
|
47
|
+
return c.push({
|
|
48
|
+
[o]: t === "og:locale" ? "i18n-og" : t === "og:url" ? "i18n-og-url" : `i18n-page-${t}`,
|
|
49
|
+
property: t,
|
|
50
|
+
content: n
|
|
51
|
+
}), c;
|
|
52
|
+
}
|
|
53
|
+
function D(e, t, n, o) {
|
|
54
|
+
const i = [];
|
|
55
|
+
for (const c of e) {
|
|
56
|
+
if (n && c === n) continue;
|
|
57
|
+
const l = t.find((f) => f.code === c);
|
|
58
|
+
if (!l) continue;
|
|
59
|
+
const a = d(l);
|
|
60
|
+
a && i.push({
|
|
61
|
+
[o]: `i18n-og-alt-${a}`,
|
|
62
|
+
property: "og:locale:alternate",
|
|
63
|
+
content: a
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return i;
|
|
67
|
+
}
|
|
68
|
+
function S(e, t, n = {}) {
|
|
69
|
+
if (!t)
|
|
70
|
+
return {
|
|
71
|
+
htmlAttrs: { ...e.htmlAttrs },
|
|
72
|
+
meta: [...e.meta],
|
|
73
|
+
link: [...e.link]
|
|
74
|
+
};
|
|
75
|
+
const o = n.identifierAttribute ?? "id", i = new Set(t.disable ?? []);
|
|
76
|
+
let c = { ...e.htmlAttrs }, l = [...e.meta], a = [...e.link];
|
|
77
|
+
i.has("html") && (c = {}), i.has("hreflang") && (a = a.filter((r) => !m(r))), i.has("x-default") && (a = a.filter((r) => !s(r))), i.has("canonical") && (a = a.filter((r) => r.rel !== "canonical")), i.has("og") && (l = l.filter((r) => r.property !== "og:locale" && r.property !== "og:url")), i.has("og-alternates") && (l = l.filter((r) => r.property !== "og:locale:alternate"));
|
|
78
|
+
const f = t.replace;
|
|
79
|
+
if (f) {
|
|
80
|
+
if (f.canonical === !1 ? a = a.filter((r) => r.rel !== "canonical") : typeof f.canonical == "string" && (a = k(a, f.canonical, o)), f.hreflang === !1 ? a = a.filter((r) => !u(r)) : Array.isArray(f.hreflang) && (a = a.filter((r) => !u(r)), a.push(...f.hreflang)), f.xDefault === !1 ? a = a.filter((r) => !s(r)) : f.xDefault && (a = a.filter((r) => !s(r)), a.push(f.xDefault)), f.ogLocale === !1 ? l = l.filter((r) => r.property !== "og:locale") : typeof f.ogLocale == "string" && (l = h(l, "og:locale", f.ogLocale, o)), f.ogUrl === !1 ? l = l.filter((r) => r.property !== "og:url") : typeof f.ogUrl == "string" && (l = h(l, "og:url", f.ogUrl, o)), f.ogAlternates === !1)
|
|
81
|
+
l = l.filter((r) => r.property !== "og:locale:alternate");
|
|
82
|
+
else if (Array.isArray(f.ogAlternates)) {
|
|
83
|
+
l = l.filter((y) => y.property !== "og:locale:alternate");
|
|
84
|
+
const r = n.locales ?? [];
|
|
85
|
+
l.push(...D(f.ogAlternates, r, n.currentLocale, o));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
t.htmlAttrs && (c = { ...c, ...t.htmlAttrs });
|
|
89
|
+
for (const r of t.meta ?? [])
|
|
90
|
+
l = L(l, r, o);
|
|
91
|
+
for (const r of t.link ?? [])
|
|
92
|
+
a = x(a, r, o);
|
|
93
|
+
return { htmlAttrs: c, meta: l, link: a };
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
S as mergeI18nHead
|
|
97
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function c(n){const t=n.og?.trim();if(t)return t;const e=n.iso?.trim();if(!e)return null;const r=e.indexOf("_");if(r>0){const s=e.slice(0,r),o=e.slice(r+1);if(s.length>=2&&o.length===2)return`${s.toLowerCase()}_${o.toUpperCase()}`}const i=e.indexOf("-");if(i>0){const s=e.slice(0,i),o=e.slice(i+1);if(s.length>=2&&o.length===2&&/^[A-Za-z]{2}$/.test(o))return`${s.toLowerCase()}_${o.toUpperCase()}`}return null}function l(n,t={}){if(c(n)!==null||t.missingWarn===!1||process.env.NODE_ENV==="production")return;const e=t.tag??"og:locale",r=String(n.code??"unknown"),i=n.iso?`, iso: '${n.iso}'`:"";console.warn(`[i18n] Cannot derive ${e} for locale '${r}'${i}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`)}exports.resolveOgLocale=c;exports.warnUnresolvedOgLocale=l;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
type OgLocaleInput = Pick<Locale, 'og' | 'iso' | 'code'>;
|
|
3
|
+
export interface WarnUnresolvedOgLocaleOptions {
|
|
4
|
+
/** When false, suppresses the warning (same flag as missing translation keys). */
|
|
5
|
+
missingWarn?: boolean;
|
|
6
|
+
tag?: 'og:locale' | 'og:locale:alternate';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve Open Graph locale (`language_TERRITORY`, underscore) for `og:locale` meta tags.
|
|
10
|
+
* Returns null when the value cannot be determined safely — no tag should be emitted.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveOgLocale(locale: OgLocaleInput): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Log a dev-only hint when `og:locale` / `og:locale:alternate` cannot be derived.
|
|
15
|
+
*/
|
|
16
|
+
export declare function warnUnresolvedOgLocale(locale: OgLocaleInput, options?: WarnUnresolvedOgLocaleOptions): void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
type OgLocaleInput = Pick<Locale, 'og' | 'iso' | 'code'>;
|
|
3
|
+
export interface WarnUnresolvedOgLocaleOptions {
|
|
4
|
+
/** When false, suppresses the warning (same flag as missing translation keys). */
|
|
5
|
+
missingWarn?: boolean;
|
|
6
|
+
tag?: 'og:locale' | 'og:locale:alternate';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve Open Graph locale (`language_TERRITORY`, underscore) for `og:locale` meta tags.
|
|
10
|
+
* Returns null when the value cannot be determined safely — no tag should be emitted.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveOgLocale(locale: OgLocaleInput): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Log a dev-only hint when `og:locale` / `og:locale:alternate` cannot be derived.
|
|
15
|
+
*/
|
|
16
|
+
export declare function warnUnresolvedOgLocale(locale: OgLocaleInput, options?: WarnUnresolvedOgLocaleOptions): void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function c(n) {
|
|
2
|
+
const t = n.og?.trim();
|
|
3
|
+
if (t) return t;
|
|
4
|
+
const e = n.iso?.trim();
|
|
5
|
+
if (!e) return null;
|
|
6
|
+
const r = e.indexOf("_");
|
|
7
|
+
if (r > 0) {
|
|
8
|
+
const s = e.slice(0, r), o = e.slice(r + 1);
|
|
9
|
+
if (s.length >= 2 && o.length === 2)
|
|
10
|
+
return `${s.toLowerCase()}_${o.toUpperCase()}`;
|
|
11
|
+
}
|
|
12
|
+
const i = e.indexOf("-");
|
|
13
|
+
if (i > 0) {
|
|
14
|
+
const s = e.slice(0, i), o = e.slice(i + 1);
|
|
15
|
+
if (s.length >= 2 && o.length === 2 && /^[A-Za-z]{2}$/.test(o))
|
|
16
|
+
return `${s.toLowerCase()}_${o.toUpperCase()}`;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function l(n, t = {}) {
|
|
21
|
+
if (c(n) !== null || t.missingWarn === !1 || process.env.NODE_ENV === "production") return;
|
|
22
|
+
const e = t.tag ?? "og:locale", r = String(n.code ?? "unknown"), i = n.iso ? `, iso: '${n.iso}'` : "";
|
|
23
|
+
console.warn(
|
|
24
|
+
`[i18n] Cannot derive ${e} for locale '${r}'${i}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
c as resolveOgLocale,
|
|
29
|
+
l as warnUnresolvedOgLocale
|
|
30
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i18n-micro/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Framework-agnostic utilities for Nuxt I18n Micro (granular subpath imports).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -129,6 +129,28 @@
|
|
|
129
129
|
},
|
|
130
130
|
"default": "./dist/resolve-locale.mjs"
|
|
131
131
|
},
|
|
132
|
+
"./resolve-og-locale": {
|
|
133
|
+
"import": {
|
|
134
|
+
"types": "./dist/resolve-og-locale.d.ts",
|
|
135
|
+
"default": "./dist/resolve-og-locale.mjs"
|
|
136
|
+
},
|
|
137
|
+
"require": {
|
|
138
|
+
"types": "./dist/resolve-og-locale.d.cts",
|
|
139
|
+
"default": "./dist/resolve-og-locale.cjs"
|
|
140
|
+
},
|
|
141
|
+
"default": "./dist/resolve-og-locale.mjs"
|
|
142
|
+
},
|
|
143
|
+
"./merge-i18n-head": {
|
|
144
|
+
"import": {
|
|
145
|
+
"types": "./dist/merge-i18n-head.d.ts",
|
|
146
|
+
"default": "./dist/merge-i18n-head.mjs"
|
|
147
|
+
},
|
|
148
|
+
"require": {
|
|
149
|
+
"types": "./dist/merge-i18n-head.d.cts",
|
|
150
|
+
"default": "./dist/merge-i18n-head.cjs"
|
|
151
|
+
},
|
|
152
|
+
"default": "./dist/merge-i18n-head.mjs"
|
|
153
|
+
},
|
|
132
154
|
"./active-locales": {
|
|
133
155
|
"import": {
|
|
134
156
|
"types": "./dist/active-locales.d.ts",
|
|
@@ -236,7 +258,7 @@
|
|
|
236
258
|
},
|
|
237
259
|
"dependencies": {
|
|
238
260
|
"globby": "^14.1.0",
|
|
239
|
-
"@i18n-micro/types": "1.2.
|
|
261
|
+
"@i18n-micro/types": "1.2.6"
|
|
240
262
|
},
|
|
241
263
|
"devDependencies": {
|
|
242
264
|
"publint": "^0.3.17",
|