feat: add translation key collection utility and update test for completeness
This commit is contained in:
@@ -804,6 +804,7 @@ export function EmailViewer({
|
||||
const t = useTranslations('email_viewer');
|
||||
const tNotifications = useTranslations('notifications');
|
||||
const tCommon = useTranslations('common');
|
||||
const tSmime = useTranslations('smime');
|
||||
const tFiles = useTranslations('files');
|
||||
const externalContentPolicy = useSettingsStore((state) => state.externalContentPolicy);
|
||||
const mailAttachmentAction = useSettingsStore((state) => state.mailAttachmentAction);
|
||||
@@ -3944,8 +3945,8 @@ export function EmailViewer({
|
||||
setSmimeUnlockError(null);
|
||||
}}
|
||||
onSubmit={handleSmimeUnlockSubmit}
|
||||
title={tCommon('smime.unlock_key')}
|
||||
description={tCommon('smime.unlock_key_desc')}
|
||||
title={tSmime('unlock_key')}
|
||||
description={tSmime('unlock_key_desc')}
|
||||
error={smimeUnlockError}
|
||||
/>
|
||||
|
||||
|
||||
@@ -87,6 +87,22 @@ function extractUsedKeys(filePath: string): string[] {
|
||||
return [...new Set(keys)];
|
||||
}
|
||||
|
||||
function collectUsedKeysByFile(files: string[]): Map<string, string[]> {
|
||||
const keyToFiles = new Map<string, string[]>();
|
||||
|
||||
for (const filePath of files) {
|
||||
for (const key of extractUsedKeys(filePath)) {
|
||||
const existing = keyToFiles.get(key) ?? [];
|
||||
if (!existing.includes(filePath)) {
|
||||
existing.push(filePath);
|
||||
keyToFiles.set(key, existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keyToFiles;
|
||||
}
|
||||
|
||||
const locales = fs
|
||||
.readdirSync(localesDir)
|
||||
.filter((entry) => fs.statSync(path.join(localesDir, entry)).isDirectory());
|
||||
@@ -120,19 +136,22 @@ describe('translations completeness', () => {
|
||||
describe('translations used in source code exist in en locale', () => {
|
||||
const srcDirs = ['components', 'app', 'hooks', 'lib', 'stores', 'contexts'].map((d) => path.join(rootDir, d));
|
||||
const allFiles = srcDirs.flatMap((d) => getSourceFiles(d));
|
||||
const usedKeys = new Set<string>();
|
||||
for (const f of allFiles) {
|
||||
for (const k of extractUsedKeys(f)) {
|
||||
usedKeys.add(k);
|
||||
}
|
||||
}
|
||||
const usedKeysByFile = collectUsedKeysByFile(allFiles);
|
||||
const usedKeys = [...usedKeysByFile.keys()].sort();
|
||||
|
||||
it('all translation keys referenced in source should exist in en locale', () => {
|
||||
const missing = [...usedKeys].sort().filter((key) => resolveKey(referenceData, key) === undefined);
|
||||
const missing = usedKeys.filter((key) => resolveKey(referenceData, key) === undefined);
|
||||
const details = missing.map((key) => {
|
||||
const relativeFiles = (usedKeysByFile.get(key) ?? [])
|
||||
.map((filePath) => path.relative(rootDir, filePath))
|
||||
.sort();
|
||||
|
||||
return `${key}\n used in:\n - ${relativeFiles.join('\n - ')}`;
|
||||
});
|
||||
|
||||
expect(
|
||||
missing,
|
||||
`${missing.length} translation key(s) used in source code but missing from en locale:\n${missing.join('\n')}`,
|
||||
`${missing.length} translation key(s) used in source code but missing from en locale:\n${details.join('\n')}`,
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"lint:fix": "next lint --fix",
|
||||
"test:translations": "vitest run lib/__tests__/translations.test.ts",
|
||||
"prepare": "husky",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user