mirror of https://github.com/grafana/grafana.git
				
				
				
			I18N: Collect stats on number of untranslated strings in message catalogues (#76272)
* I18N: Collect stats on number of untranslated strings in message catalogues * eachLeaf -> eachMessage * use __dirname
This commit is contained in:
		
							parent
							
								
									a0ab1e4fd7
								
							
						
					
					
						commit
						8d9ef716fe
					
				|  | @ -49,6 +49,7 @@ | ||||||
|     "i18n:extract": "yarn run i18next -c public/locales/i18next-parser.config.js 'public/**/*.{tsx,ts}' 'packages/grafana-ui/**/*.{tsx,ts}' && yarn i18n:pseudo", |     "i18n:extract": "yarn run i18next -c public/locales/i18next-parser.config.js 'public/**/*.{tsx,ts}' 'packages/grafana-ui/**/*.{tsx,ts}' && yarn i18n:pseudo", | ||||||
|     "i18n:compile": "echo 'no i18n compile yet, all good'", |     "i18n:compile": "echo 'no i18n compile yet, all good'", | ||||||
|     "i18n:pseudo": "node ./public/locales/pseudo.js", |     "i18n:pseudo": "node ./public/locales/pseudo.js", | ||||||
|  |     "i18n:stats": "node ./scripts/cli/reportI18nStats.mjs", | ||||||
|     "betterer": "betterer", |     "betterer": "betterer", | ||||||
|     "betterer:merge": "betterer merge", |     "betterer:merge": "betterer merge", | ||||||
|     "betterer:stats": "ts-node --transpile-only --project ./scripts/cli/tsconfig.json ./scripts/cli/reportBettererStats.ts", |     "betterer:stats": "ts-node --transpile-only --project ./scripts/cli/tsconfig.json ./scripts/cli/reportBettererStats.ts", | ||||||
|  |  | ||||||
|  | @ -46,6 +46,13 @@ do | ||||||
|   BETTERER_STATS+="\"grafana.ci-code.betterer.${name}\": \"${value}\"," |   BETTERER_STATS+="\"grafana.ci-code.betterer.${name}\": \"${value}\"," | ||||||
| done <<< "$(yarn betterer:stats)" | done <<< "$(yarn betterer:stats)" | ||||||
| 
 | 
 | ||||||
|  | I18N_STATS="" | ||||||
|  | while read -r name value | ||||||
|  | do | ||||||
|  |   I18N_STATS+=$'\n  ' | ||||||
|  |   I18N_STATS+="\"grafana.ci-code.i18n.${name}\": \"${value}\"," | ||||||
|  | done <<< "$(yarn i18n:stats)" | ||||||
|  | 
 | ||||||
| THEME_TOKEN_USAGE="" | THEME_TOKEN_USAGE="" | ||||||
| while read -r name value | while read -r name value | ||||||
| do | do | ||||||
|  | @ -56,6 +63,7 @@ done <<< "$(yarn themes:usage | awk '$4 == "@grafana/theme-token-usage" {print $ | ||||||
| echo "Metrics: { | echo "Metrics: { | ||||||
|   $THEME_TOKEN_USAGE |   $THEME_TOKEN_USAGE | ||||||
|   $BETTERER_STATS |   $BETTERER_STATS | ||||||
|  |   $I18N_STATS | ||||||
|   \"grafana.ci-code.strictErrors\": \"${ERROR_COUNT}\", |   \"grafana.ci-code.strictErrors\": \"${ERROR_COUNT}\", | ||||||
|   \"grafana.ci-code.accessibilityErrors\": \"${ACCESSIBILITY_ERRORS}\", |   \"grafana.ci-code.accessibilityErrors\": \"${ACCESSIBILITY_ERRORS}\", | ||||||
|   \"grafana.ci-code.directives\": \"${DIRECTIVES}\", |   \"grafana.ci-code.directives\": \"${DIRECTIVES}\", | ||||||
|  |  | ||||||
|  | @ -0,0 +1,88 @@ | ||||||
|  | /// @ts-check
 | ||||||
|  | 
 | ||||||
|  | import { readdir, stat, readFile } from 'fs/promises'; | ||||||
|  | import path, { dirname } from 'path'; | ||||||
|  | import { fileURLToPath } from 'url'; | ||||||
|  | 
 | ||||||
|  | const LOCALES_DIR = path.resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'public', 'locales'); | ||||||
|  | 
 | ||||||
|  | const locales = await readdir(LOCALES_DIR); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @type {Array<{ language: string, untranslatedCount: number, translatedCount: number }>} | ||||||
|  |  */ | ||||||
|  | const stats = []; | ||||||
|  | 
 | ||||||
|  | for (const fileName of locales) { | ||||||
|  |   const filePath = path.join(LOCALES_DIR, fileName, 'grafana.json'); | ||||||
|  |   if (!(await exists(filePath))) { | ||||||
|  |     continue; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const messages = await readFile(filePath); | ||||||
|  |   const parsedMessages = JSON.parse(messages.toString()); | ||||||
|  | 
 | ||||||
|  |   let translatedCount = 0; | ||||||
|  |   let untranslatedCount = 0; | ||||||
|  | 
 | ||||||
|  |   eachMessage(parsedMessages, (value) => { | ||||||
|  |     if (value === '') { | ||||||
|  |       untranslatedCount += 1; | ||||||
|  |     } else { | ||||||
|  |       translatedCount += 1; | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   stats.push({ | ||||||
|  |     language: fileName, | ||||||
|  |     translatedCount, | ||||||
|  |     untranslatedCount, | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | for (const stat of stats) { | ||||||
|  |   logStat(`untranslated.${stat.language}`, stat.untranslatedCount); | ||||||
|  |   logStat(`translated.${stat.language}`, stat.translatedCount); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param {string} filePath | ||||||
|  |  */ | ||||||
|  | async function exists(filePath) { | ||||||
|  |   try { | ||||||
|  |     await stat(filePath); | ||||||
|  |     return true; | ||||||
|  |   } catch (err) { | ||||||
|  |     if (err.code === 'ENOENT' || err.code === 'ENOTDIR') { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     throw err; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param {unknown} value | ||||||
|  |  * @param {(v: string) => void} callback | ||||||
|  |  */ | ||||||
|  | function eachMessage(value, callback) { | ||||||
|  |   if (typeof value === 'object') { | ||||||
|  |     for (const key in value) { | ||||||
|  |       const element = value[key]; | ||||||
|  |       eachMessage(element, callback); | ||||||
|  |     } | ||||||
|  |   } else if (typeof value === 'string') { | ||||||
|  |     callback(value); | ||||||
|  |   } else { | ||||||
|  |     throw new Error(`Unknown value ${value} in eachMessage`); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param {string} name | ||||||
|  |  * @param {string | number} value | ||||||
|  |  */ | ||||||
|  | function logStat(name, value) { | ||||||
|  |   // Note that this output format must match the parsing in ci-frontend-metrics.sh
 | ||||||
|  |   // which expects the two values to be separated by a space
 | ||||||
|  |   console.log(`${name} ${value}`); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue