diff --git a/scripts/catalogs.js b/scripts/catalogs.js new file mode 100644 index 00000000..e93fcba5 --- /dev/null +++ b/scripts/catalogs.js @@ -0,0 +1,60 @@ +import fs from 'node:fs'; + +// Dependency from Lingui, not listed in package.json +import PO from 'pofile'; + +const DEFAULT_LANG = 'en'; +const IGNORE_LANGS = [DEFAULT_LANG, 'pseudo-LOCALE']; + +const files = fs.readdirSync('src/locales'); +const catalogs = {}; + +const enCatalog = files.find((file) => file.endsWith('en.po')); +const enContent = fs.readFileSync(`src/locales/${enCatalog}`, 'utf8'); +const enPo = PO.parse(enContent); +const total = enPo.items.length; +console.log('Total strings:', total); + +files.forEach((file) => { + if (file.endsWith('.po')) { + const code = file.replace(/\.po$/, ''); + if (IGNORE_LANGS.includes(code)) return; + const content = fs.readFileSync(`src/locales/${file}`, 'utf8'); + const po = PO.parse(content); + const { items } = po; + // Percentage of translated strings + const translated = items.filter( + (item) => item.msgstr !== '' && item.msgstr[0] !== '', + ).length; + const percentage = Math.round((translated / total) * 100); + po.percentage = percentage; + if (percentage > 0) { + // Ignore empty catalogs + catalogs[code] = percentage; + } + } +}); + +// Sort by percentage +const sortedCatalogs = Object.entries(catalogs) + .sort((a, b) => b[1] - a[1]) + .map(([code, percentage]) => { + const name = new Intl.DisplayNames(['en'], { type: 'language' }).of(code); + return { code, name, percentage }; + }); + +console.table(sortedCatalogs); + +const path = 'src/data/catalogs.json'; +fs.writeFileSync( + path, + JSON.stringify( + Object.entries(catalogs).map(([code, percentage]) => ({ + code, + completion: percentage, + })), + null, + 2, + ), +); +console.log('File written:', path); diff --git a/src/data/catalogs.json b/src/data/catalogs.json new file mode 100644 index 00000000..0d92b28d --- /dev/null +++ b/src/data/catalogs.json @@ -0,0 +1,90 @@ +[ + { + "code": "ar-SA", + "completion": 22 + }, + { + "code": "ca-ES", + "completion": 99 + }, + { + "code": "cs-CZ", + "completion": 54 + }, + { + "code": "de-DE", + "completion": 99 + }, + { + "code": "eo-UY", + "completion": 15 + }, + { + "code": "es-ES", + "completion": 100 + }, + { + "code": "eu-ES", + "completion": 100 + }, + { + "code": "fa-IR", + "completion": 51 + }, + { + "code": "fi-FI", + "completion": 100 + }, + { + "code": "fr-FR", + "completion": 92 + }, + { + "code": "gl-ES", + "completion": 100 + }, + { + "code": "he-IL", + "completion": 11 + }, + { + "code": "it-IT", + "completion": 13 + }, + { + "code": "ja-JP", + "completion": 32 + }, + { + "code": "kab-KAB", + "completion": 33 + }, + { + "code": "ko-KR", + "completion": 76 + }, + { + "code": "lt-LT", + "completion": 25 + }, + { + "code": "nl-NL", + "completion": 49 + }, + { + "code": "ru-RU", + "completion": 24 + }, + { + "code": "th-TH", + "completion": 3 + }, + { + "code": "zh-CN", + "completion": 100 + }, + { + "code": "zh-TW", + "completion": 3 + } +] \ No newline at end of file diff --git a/src/locales.js b/src/locales.js index 05ebd019..ea83cd07 100644 --- a/src/locales.js +++ b/src/locales.js @@ -1,16 +1,16 @@ +import catalogs from './data/catalogs.json'; + export const DEFAULT_LANG = 'en'; +export const CATALOGS = catalogs; + +// Get locales that's >= X% translated +const PERCENTAGE_THRESHOLD = 50; const locales = [ DEFAULT_LANG, - 'zh-CN', // Chinese (Simplified) - 'eu-ES', // Basque - 'es-ES', // Spanish - 'fi-FI', // Finnish - 'gl-ES', // Galician - 'de-DE', // German - 'ca-ES', // Catalan - 'fr-FR', // French - 'ko-KR', // Korean + ...catalogs + .filter(({ completion }) => completion >= PERCENTAGE_THRESHOLD) + .map(({ code }) => code), ]; if (import.meta.env.DEV) { locales.push('pseudo-LOCALE');