mirror of
https://github.com/kemalai/FreeCrawl-SEO-Tool.git
synced 2026-10-18 00:39:38 +02:00
79 lines
2.8 KiB
JavaScript
79 lines
2.8 KiB
JavaScript
#!/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`,
|
||
);
|