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:compile": "echo 'no i18n compile yet, all good'", | ||||
|     "i18n:pseudo": "node ./public/locales/pseudo.js", | ||||
|     "i18n:stats": "node ./scripts/cli/reportI18nStats.mjs", | ||||
|     "betterer": "betterer", | ||||
|     "betterer:merge": "betterer merge", | ||||
|     "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}\"," | ||||
| 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="" | ||||
| while read -r name value | ||||
| do | ||||
|  | @ -56,6 +63,7 @@ done <<< "$(yarn themes:usage | awk '$4 == "@grafana/theme-token-usage" {print $ | |||
| echo "Metrics: { | ||||
|   $THEME_TOKEN_USAGE | ||||
|   $BETTERER_STATS | ||||
|   $I18N_STATS | ||||
|   \"grafana.ci-code.strictErrors\": \"${ERROR_COUNT}\", | ||||
|   \"grafana.ci-code.accessibilityErrors\": \"${ACCESSIBILITY_ERRORS}\", | ||||
|   \"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