Files
FreeCrawl-SEO-Tool/scripts/generate-hreflang-codes.mjs
T

79 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Regenerates `packages/shared-types/src/hreflang-codes.ts` — the code
* tables `isValidHreflangCode` checks against.
*
* Why a generated table instead of asking `Intl` at run time: the desktop
* app validates hreflang inside Electron, and Chromium ships a trimmed ICU
* that has no display name for dozens of valid codes (`ff` Fula, `kl`,
* `se`, the UN M.49 region `419` behind `es-419`, …). Asking ICU there
* reported real codes as invalid, while the same check passed under Node.
* The table is read from Node's full ICU here, once, so every runtime
* judges a code the same way.
*
* Run under Node (not Electron) after a Node / ICU upgrade:
* node scripts/generate-hreflang-codes.mjs
*/
import { writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
if (process.versions.electron) {
console.error('Run this with Node: Electron’s ICU lacks many language and region names.');
process.exit(1);
}
const A = 'abcdefghijklmnopqrstuvwxyz';
const named = (type) => {
const dn = new Intl.DisplayNames(['en'], { type, fallback: 'none' });
return (code) => {
try {
return dn.of(code) !== undefined;
} catch {
return false;
}
};
};
const isLanguage = named('language');
const isRegion = named('region');
const isScript = named('script');
const languages = [];
const regions = [];
for (const a of A) {
for (const b of A) {
if (isLanguage(a + b)) languages.push(a + b);
const r = (a + b).toUpperCase();
if (isRegion(r)) regions.push(r);
}
}
const numericRegions = [];
for (let i = 0; i < 1000; i++) {
const r = String(i).padStart(3, '0');
if (isRegion(r)) numericRegions.push(r);
}
const scripts = [];
for (const a of A) for (const b of A) for (const c of A) for (const d of A) {
const s = a.toUpperCase() + b + c + d;
if (isScript(s)) scripts.push(s);
}
const out = join(dirname(fileURLToPath(import.meta.url)), '..', 'packages', 'shared-types', 'src', 'hreflang-codes.ts');
const line = (name, doc, list) => `/** ${doc} */\nexport const ${name} = '${list.join(' ')}';\n`;
writeFileSync(
out,
`// Generated by scripts/generate-hreflang-codes.mjs from ICU ${process.versions.icu}` +
` (Node ${process.version}). Do not edit by hand — re-run the script.\n\n` +
line('LANGUAGES_2', 'Two-letter (ISO 639-1) language subtags.', languages) +
'\n' +
line('SCRIPTS', 'ISO 15924 script subtags.', scripts) +
'\n' +
line('REGIONS_2', 'Two-letter region subtags (ISO 3166-1 and the aliases ICU knows).', regions) +
'\n' +
line('REGIONS_NUMERIC', 'UN M.49 numeric region subtags.', numericRegions),
);
console.log(
`hreflang-codes.ts: ${languages.length} languages, ${scripts.length} scripts, ` +
`${regions.length} regions, ${numericRegions.length} numeric regions`,
);