@xema/omni-protocol 0.1.127 → 0.1.128
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/index.js +8 -1
- package/dist/validation.js +13 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -160,7 +160,8 @@ export function localizedText(text, languages) {
|
|
|
160
160
|
return undefined;
|
|
161
161
|
const byTag = new Map(Object.entries(text).map(([tag, value]) => [tag.toLowerCase(), value]));
|
|
162
162
|
for (const language of languages) {
|
|
163
|
-
|
|
163
|
+
// RFC 4647 Lookup: drop subtags from the end, and a single-letter extension marker with the one before it.
|
|
164
|
+
for (let tag = language.toLowerCase(); tag !== ""; tag = shorterTag(tag)) {
|
|
164
165
|
const found = byTag.get(tag);
|
|
165
166
|
if (found !== undefined)
|
|
166
167
|
return found;
|
|
@@ -168,6 +169,12 @@ export function localizedText(text, languages) {
|
|
|
168
169
|
}
|
|
169
170
|
return undefined;
|
|
170
171
|
}
|
|
172
|
+
function shorterTag(tag) {
|
|
173
|
+
if (!tag.includes("-"))
|
|
174
|
+
return "";
|
|
175
|
+
const shorter = tag.slice(0, tag.lastIndexOf("-"));
|
|
176
|
+
return /-[a-z0-9]$/.test(shorter) ? shorter.slice(0, -2) : shorter;
|
|
177
|
+
}
|
|
171
178
|
// ---------------------------------------------------------------------------
|
|
172
179
|
// Utilities.
|
|
173
180
|
// ---------------------------------------------------------------------------
|
package/dist/validation.js
CHANGED
|
@@ -561,8 +561,17 @@ export function validateManifest(manifest, path = "manifest") {
|
|
|
561
561
|
}
|
|
562
562
|
return into.violations;
|
|
563
563
|
}
|
|
564
|
-
/**
|
|
565
|
-
|
|
564
|
+
/** A well-formed BCP 47 tag as ECMA-402 reads one, a Unicode locale identifier: judged by its spelling, never by what the machine has installed. */
|
|
565
|
+
function isLanguageTag(value) {
|
|
566
|
+
if (typeof value !== "string" || value === "")
|
|
567
|
+
return false;
|
|
568
|
+
try {
|
|
569
|
+
return Intl.getCanonicalLocales(value).length === 1;
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
566
575
|
/** The agent's languages, as a host states them on both contexts: BCP 47 tags, most preferred first, at least one. */
|
|
567
576
|
export function validateLanguages(value, path = "context.languages") {
|
|
568
577
|
const into = new Collector();
|
|
@@ -572,7 +581,7 @@ export function validateLanguages(value, path = "context.languages") {
|
|
|
572
581
|
}
|
|
573
582
|
const seen = new Set();
|
|
574
583
|
value.forEach((tag, index) => {
|
|
575
|
-
if (
|
|
584
|
+
if (!isLanguageTag(tag)) {
|
|
576
585
|
into.add("context.languages.tag", `${path}[${index}]`, `${describeValue(tag)} is not a BCP 47 language tag`);
|
|
577
586
|
return;
|
|
578
587
|
}
|
|
@@ -633,7 +642,7 @@ function validateLocalizedText(value, rule, path, into) {
|
|
|
633
642
|
}
|
|
634
643
|
const seen = new Set();
|
|
635
644
|
for (const [tag, text] of Object.entries(value)) {
|
|
636
|
-
if (!into.require(
|
|
645
|
+
if (!into.require(isLanguageTag(tag), `${rule}.language`, `${path}.${tag}`, `${describeValue(tag)} is not a language tag such as en, hi or en-IN`))
|
|
637
646
|
continue;
|
|
638
647
|
into.require(!seen.has(tag.toLowerCase()), `${rule}.language.unique`, `${path}.${tag}`, "language tags are case-insensitive, and each language is stated once");
|
|
639
648
|
seen.add(tag.toLowerCase());
|