diff --git a/src/gui/src/UI/UIWindowLogin.js b/src/gui/src/UI/UIWindowLogin.js index 48d5b63e1..170d1f3f5 100644 --- a/src/gui/src/UI/UIWindowLogin.js +++ b/src/gui/src/UI/UIWindowLogin.js @@ -568,7 +568,7 @@ async function UIWindowLogin (options) { } h2fa += ''; h2fa += '
'; - h2fa += `
${i18n('verifying') || 'Verifying...'}
`; + h2fa += `
${i18n('verifying')}
`; h2fa += ``; h2fa += ''; @@ -859,7 +859,7 @@ async function UIWindowLogin (options) { // Basic validation if ( ! email_username ) { - $(el_window).find('.login-error-msg').html(i18n('email_or_username_required') || 'Email or username is required'); + $(el_window).find('.login-error-msg').html(i18n('login_email_username_required')); $(el_window).find('.login-error-msg').fadeIn(); return false; } diff --git a/src/gui/src/i18n/i18nKeys.test.js b/src/gui/src/i18n/i18nKeys.test.js new file mode 100644 index 000000000..2a41315e0 --- /dev/null +++ b/src/gui/src/i18n/i18nKeys.test.js @@ -0,0 +1,26 @@ +import { readdirSync, readFileSync } from 'node:fs'; +import { dirname, join, relative } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, it } from 'vitest'; +import en from './translations/en.js'; + +const guiSrc = join(dirname(fileURLToPath(import.meta.url)), '..'); + +const sourceFiles = dir => readdirSync(dir, { withFileTypes: true }).flatMap(entry => { + const path = join(dir, entry.name); + if ( entry.isDirectory() ) return sourceFiles(path); + return path.endsWith('.js') && !path.endsWith('.test.js') ? [path] : []; +}); + +describe('i18n keys', () => { + // A key missing from en.js renders as the raw key, in every locale. + it('every literal i18n() key in the GUI exists in en.js', () => { + const missing = []; + for ( const file of sourceFiles(guiSrc) ) { + for ( const [, key] of readFileSync(file, 'utf8').matchAll(/\bi18n\(\s*['"]([\w.-]+)['"]/g) ) { + if ( ! Object.hasOwn(en.dictionary, key) ) missing.push(`${relative(guiSrc, file)}: ${key}`); + } + } + expect(missing).toEqual([]); + }); +}); diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js index 00d73efd5..b27bf6e8b 100644 --- a/src/gui/src/i18n/translations/en.js +++ b/src/gui/src/i18n/translations/en.js @@ -108,6 +108,7 @@ const en = { confirm_delete_multiple_items: 'Are you sure you want to permanently delete these items?', confirm_delete_single_item: 'Do you want to permanently delete this item?', confirm_open_apps_log_out: 'You have open apps. Are you sure you want to log out?', + confirm_password_required: 'Please confirm your password.', confirm_new_password: 'Confirm New Password', confirm_delete_user: 'Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone.', confirm_delete_user_title: 'Delete Account?', @@ -169,6 +170,7 @@ const en = { disassociate_dir: 'Disassociate Directory', disk_storage: 'Disk Storage', documents: 'Documents', + done: 'Done', dont_allow: 'Don\'t Allow', download: 'Download', confirm_download_file_to_desktop: 'Are you sure you want to download %% to your Desktop?', @@ -755,6 +757,7 @@ const en = { username: 'Username', username_changed: 'Username updated successfully.', username_required: 'Username is required.', + verifying: 'Verifying...', versions: 'Versions', videos: 'Videos', visibility: 'Visibility',