diff --git a/docs/ldml/tr35-messageFormat.md b/docs/ldml/tr35-messageFormat.md
index 0030e0518b7..376a0c3f46f 100644
--- a/docs/ldml/tr35-messageFormat.md
+++ b/docs/ldml/tr35-messageFormat.md
@@ -1,3 +1,6 @@
+---
+linkify: true
+---
## Unicode Technical Standard #35
# Unicode Locale Data Markup Language (LDML)
Part 9: Message Format
diff --git a/tools/scripts/tr-archive/archive.js b/tools/scripts/tr-archive/archive.js
index ba5493efd29..68085ac1fe3 100644
--- a/tools/scripts/tr-archive/archive.js
+++ b/tools/scripts/tr-archive/archive.js
@@ -4,7 +4,7 @@ const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const path = require("path");
const markedAlert = require("marked-alert");
-
+const matter = require("gray-matter");
// Setup some options for our markdown renderer
marked.setOptions({
renderer: new marked.Renderer(),
@@ -34,9 +34,13 @@ marked.use(markedAlert());
async function renderit(infile) {
const gtag = (await fs.readFile("gtag.html", "utf-8")).trim();
console.log(`Reading ${infile}`);
- basename = path.basename(infile, ".md");
+ const basename = path.basename(infile, ".md");
const outfile = path.join(path.dirname(infile), `${basename}.html`);
let f1 = await fs.readFile(infile, "utf-8");
+ // any metadata on the file?
+ const { data, content } = matter(f1);
+
+ f1 = content; // skip the frontmatter (YAML block within ---)
// oh the irony of removing a BOM before posting to unicode.org
if (f1.charCodeAt(0) == 0xfeff) {
@@ -215,6 +219,11 @@ async function renderit(infile) {
a.setAttribute("name", parid);
}
+ // If the document requests it, linkify terms
+ if (data.linkify) {
+ linkify(dom.window.document);
+ }
+
// OK, done munging the DOM, write it out.
console.log(`Writing ${outfile}`);
@@ -246,3 +255,70 @@ fixall().then(
process.exitCode = 1;
}
);
+
+function linkify(document) {
+ const terms = findTerms(document);
+ const missing = new Set();
+ const used = new Set();
+ const links = document.querySelectorAll("em");
+
+ links.forEach((item) => {
+ const target = generateId(item.textContent);
+ if (terms.has(target)) {
+ const el = item.lastElementChild ?? item;
+ el.innerHTML = `${item.textContent}`;
+
+ used.add(target);
+ } else {
+ missing.add(target);
+ }
+ });
+
+ if (missing.size > 0) {
+ console.log("Potentially missing definitions:");
+ Array.from(missing)
+ .sort()
+ .forEach((item) => {
+ console.log(item);
+ });
+ }
+
+ if (terms.size === used.size) return;
+ console.log("Some definitions were not used:");
+ Array.from(terms).forEach((item) => {
+ if (!used.has(item)) {
+ console.log(item);
+ }
+ });
+}
+
+function findTerms(document) {
+ const terms = new Set();
+ let duplicateCount = 0;
+ document.querySelectorAll("dfn").forEach((item) => {
+ const term = generateId(item.textContent);
+ if (term.length === 0) return; // skip empty terms
+ if (terms.has(term)) {
+ console.log(`Duplicate term: ${term}`);
+ duplicateCount++;
+ }
+ terms.add(term);
+ item.setAttribute("id", term);
+ });
+
+ if (duplicateCount > 0) {
+ console.log("Duplicate Terms: " + duplicateCount);
+ }
+ return terms;
+}
+
+function generateId(term) {
+ const id = term.toLowerCase().replace(/\s+/g, "-"); // Replaces spaces safely
+ // TODO: do better than hardcoding the one case in message-format
+ if (id.endsWith("rategies")) {
+ return id.slice(0, -3) + "y";
+ } else if (id.endsWith("s") && id !== "status") {
+ return id.slice(0, -1);
+ }
+ return id;
+}
diff --git a/tools/scripts/tr-archive/package-lock.json b/tools/scripts/tr-archive/package-lock.json
index f2ab33daa7c..9769d5ecdc2 100644
--- a/tools/scripts/tr-archive/package-lock.json
+++ b/tools/scripts/tr-archive/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"@not-dalia/gfm-toc": "github:not-dalia/gfm-toc#995683cdac2aa0cce1f175104eb6cce63fb99c8d",
"anchor-js": "^5.0.0",
+ "gray-matter": "^4.0.3",
"highlight.js": "^11.7.0",
"jsdom": "^22.1.0",
"marked": "^12.0.2",
@@ -171,6 +172,14 @@
"resolved": "https://registry.npmjs.org/anchor-js/-/anchor-js-5.0.0.tgz",
"integrity": "sha512-2bOqCsBIXAYhjAN3iI4QevoAJtB2gRWAiY9P3P7CVW8lIjA3Dl6ldhDlWeeQvCHif+V5vIndfLOag/5I8tzTzA=="
},
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -336,6 +345,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
@@ -354,6 +374,20 @@
"node": ">= 6"
}
},
+ "node_modules/gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
"node_modules/highlight.js": {
"version": "11.7.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
@@ -409,11 +443,31 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
},
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/jsdom": {
"version": "22.1.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
@@ -513,6 +567,14 @@
"node": ">=14"
}
},
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -657,6 +719,18 @@
"node": ">=v12.22.7"
}
},
+ "node_modules/section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -666,6 +740,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "node_modules/strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -942,6 +1029,14 @@
"resolved": "https://registry.npmjs.org/anchor-js/-/anchor-js-5.0.0.tgz",
"integrity": "sha512-2bOqCsBIXAYhjAN3iI4QevoAJtB2gRWAiY9P3P7CVW8lIjA3Dl6ldhDlWeeQvCHif+V5vIndfLOag/5I8tzTzA=="
},
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -1058,6 +1153,14 @@
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
@@ -1073,6 +1176,17 @@
"mime-types": "^2.1.12"
}
},
+ "gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "requires": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ }
+ },
"highlight.js": {
"version": "11.7.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
@@ -1113,11 +1227,25 @@
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="
+ },
"is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
},
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
"jsdom": {
"version": "22.1.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
@@ -1193,6 +1321,11 @@
}
}
},
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
+ },
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -1305,12 +1438,31 @@
"xmlchars": "^2.2.0"
}
},
+ "section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ }
+ },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"optional": true
},
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "strip-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="
+ },
"symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
diff --git a/tools/scripts/tr-archive/package.json b/tools/scripts/tr-archive/package.json
index e2fcf28e0be..0b5f64f8ede 100644
--- a/tools/scripts/tr-archive/package.json
+++ b/tools/scripts/tr-archive/package.json
@@ -6,6 +6,7 @@
"dependencies": {
"@not-dalia/gfm-toc": "github:not-dalia/gfm-toc#995683cdac2aa0cce1f175104eb6cce63fb99c8d",
"anchor-js": "^5.0.0",
+ "gray-matter": "^4.0.3",
"highlight.js": "^11.7.0",
"jsdom": "^22.1.0",
"marked": "^12.0.2",