this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 129 lines 3.7 kB view raw
1import fs from 'node:fs'; 2 3// Dependency from Lingui, not listed in package.json 4import PO from 'pofile'; 5 6let listedLocales = []; 7try { 8 listedLocales = JSON.parse( 9 fs.readFileSync('src/data/listed-locales.json', 'utf8'), 10 ); 11} catch (e) {} 12 13const DEFAULT_LANG = 'en'; 14const IGNORE_LANGS = [DEFAULT_LANG, 'pseudo-LOCALE']; 15 16const files = fs.readdirSync('src/locales'); 17const catalogs = {}; 18 19const enCatalog = files.find((file) => file.endsWith('en.po')); 20const enContent = fs.readFileSync(`src/locales/${enCatalog}`, 'utf8'); 21const enPo = PO.parse(enContent); 22const total = enPo.items.length; 23console.log('Total strings:', total); 24 25const codeMaps = { 26 'kab-KAB': 'kab', 27}; 28 29files.forEach((file) => { 30 if (file.endsWith('.po')) { 31 const code = file.replace(/\.po$/, ''); 32 if (IGNORE_LANGS.includes(code)) return; 33 const content = fs.readFileSync(`src/locales/${file}`, 'utf8'); 34 const po = PO.parse(content); 35 const { items } = po; 36 // Percentage of translated strings 37 const translated = items.filter( 38 (item) => item.msgstr !== '' && item.msgstr[0] !== '', 39 ).length; 40 const percentage = Math.round((translated / total) * 100); 41 po.percentage = percentage; 42 if (percentage > 0) { 43 // Ignore empty catalogs 44 catalogs[codeMaps[code] || code] = percentage; 45 } 46 } 47}); 48 49const regionMaps = { 50 'zh-CN': 'zh-Hans', 51 'zh-TW': 'zh-Hant', 52}; 53 54function IDN(inputCode, outputCode) { 55 let result; 56 const regionlessInputCode = 57 regionMaps[inputCode] || inputCode.replace(/-[a-z]+$/i, ''); 58 const regionlessOutputCode = 59 regionMaps[outputCode] || outputCode.replace(/-[a-z]+$/i, ''); 60 const inputCodes = 61 regionlessInputCode !== inputCode 62 ? [inputCode, regionlessInputCode] 63 : [inputCode]; 64 const outputCodes = 65 regionlessOutputCode !== outputCode 66 ? [regionlessOutputCode, outputCode] 67 : [outputCode]; 68 69 for (const inputCode of inputCodes) { 70 for (const outputCode of outputCodes) { 71 try { 72 result = new Intl.DisplayNames([inputCode], { 73 type: 'language', 74 }).of(outputCode); 75 break; 76 } catch (e) {} 77 } 78 if (result) break; 79 } 80 return result; 81} 82 83const fullCatalogs = Object.entries(catalogs) 84 // sort by key 85 .sort((a, b) => a[0].localeCompare(b[0])) 86 .map(([code, completion]) => { 87 const nativeName = IDN(code, code); 88 const name = IDN('en', code); 89 return { code, nativeName, name, completion }; 90 }); 91 92// Set listed: true if completion > PERCENTAGE_THRESHOLD 93const PERCENTAGE_THRESHOLD = 50; 94const listedCatalogs = fullCatalogs.map((catalog) => ({ 95 ...catalog, 96 // Once listed, always listed 97 // A locale may exceed percentage threshold today, but not tomorrow 98 // So it should't suddenly become unlisted 99 listed: 100 listedLocales.includes(catalog.code) || 101 catalog.completion >= PERCENTAGE_THRESHOLD, 102})); 103 104// Sort by completion 105const sortedCatalogs = [...listedCatalogs].sort( 106 (a, b) => b.completion - a.completion, 107); 108 109console.table(sortedCatalogs); 110console.log( 111 `Total listed/unlisted: ${listedCatalogs.filter((c) => c.listed).length}/${ 112 listedCatalogs.filter((c) => !c.listed).length 113 }`, 114); 115 116const path = 'src/data/catalogs.json'; 117fs.writeFileSync(path, JSON.stringify(listedCatalogs, null, 2)); 118console.log('File written:', path); 119 120const path2 = 'src/data/listed-locales.json'; 121const codes = listedCatalogs.filter((c) => c.listed).map((c) => c.code); 122if (codes.length >= listedLocales.length) { 123 fs.writeFileSync(path2, JSON.stringify(codes, null, 2)); 124 console.log('File written:', path2); 125} else { 126 console.error( 127 `Number of listed locales reduced from ${listedLocales.length} to ${codes.length}.`, 128 ); 129}