From 25ff5bf99478b1807da7e02cf7910b69842d03bc Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Tue, 15 Jul 2025 12:56:50 +0200 Subject: [PATCH] Refactor browser extension i18n to use single file structure (#1006) --- .../src/entrypoints/background/ContextMenu.ts | 8 +- .../background/VaultMessageHandler.ts | 34 +- .../src/entrypoints/content.ts | 4 +- .../src/entrypoints/contentScript/Popup.ts | 66 ++-- .../src/entrypoints/popup/App.tsx | 12 +- .../CredentialDetails/AliasBlock.tsx | 14 +- .../LoginCredentialsBlock.tsx | 10 +- .../CredentialDetails/NotesBlock.tsx | 4 +- .../CredentialDetails/TotpBlock.tsx | 10 +- .../popup/components/EmailPreview.tsx | 20 +- .../popup/components/FormInput.tsx | 4 +- .../components/FormInputCopyToClipboard.tsx | 8 +- .../popup/components/LanguageSwitcher.tsx | 2 +- .../popup/components/Layout/BottomNav.tsx | 8 +- .../popup/components/Layout/Header.tsx | 6 +- .../popup/components/LoginServerInfo.tsx | 4 +- .../entrypoints/popup/components/Modal.tsx | 4 +- .../entrypoints/popup/hooks/useVaultMutate.ts | 12 +- .../entrypoints/popup/hooks/useVaultSync.ts | 10 +- .../entrypoints/popup/pages/AuthSettings.tsx | 14 +- .../popup/pages/CredentialAddEdit.tsx | 58 ++-- .../popup/pages/CredentialDetails.tsx | 8 +- .../popup/pages/CredentialsList.tsx | 12 +- .../entrypoints/popup/pages/EmailDetails.tsx | 28 +- .../src/entrypoints/popup/pages/Login.tsx | 57 ++-- .../src/entrypoints/popup/pages/Settings.tsx | 56 ++-- .../src/entrypoints/popup/pages/Unlock.tsx | 27 +- .../entrypoints/popup/pages/UnlockSuccess.tsx | 10 +- apps/browser-extension/src/locales/de.json | 316 ++++++++++++++++++ .../src/locales/de/auth.json | 35 -- .../src/locales/de/common.json | 39 --- .../src/locales/de/credentials.json | 79 ----- .../src/locales/de/emails.json | 18 - .../src/locales/de/settings.json | 33 -- apps/browser-extension/src/locales/en.json | 316 ++++++++++++++++++ .../src/locales/en/auth.json | 42 --- .../src/locales/en/common.json | 90 ----- .../src/locales/en/content.json | 39 --- .../src/locales/en/credentials.json | 79 ----- .../src/locales/en/emails.json | 20 -- .../src/locales/en/settings.json | 39 --- apps/browser-extension/src/locales/es.json | 316 ++++++++++++++++++ .../src/locales/es/auth.json | 35 -- .../src/locales/es/common.json | 39 --- .../src/locales/es/credentials.json | 79 ----- .../src/locales/es/emails.json | 18 - .../src/locales/es/settings.json | 33 -- apps/browser-extension/src/locales/fr.json | 316 ++++++++++++++++++ .../src/locales/fr/auth.json | 35 -- .../src/locales/fr/common.json | 39 --- .../src/locales/fr/credentials.json | 79 ----- .../src/locales/fr/emails.json | 18 - .../src/locales/fr/settings.json | 33 -- apps/browser-extension/src/locales/nl.json | 307 +++++++++++++++++ .../src/locales/nl/auth.json | 41 --- .../src/locales/nl/common.json | 90 ----- .../src/locales/nl/content.json | 31 -- .../src/locales/nl/credentials.json | 79 ----- .../src/locales/nl/emails.json | 20 -- .../src/locales/nl/settings.json | 39 --- apps/browser-extension/src/locales/uk.json | 316 ++++++++++++++++++ .../src/locales/uk/auth.json | 35 -- .../src/locales/uk/common.json | 39 --- .../src/locales/uk/credentials.json | 79 ----- .../src/locales/uk/emails.json | 18 - .../src/locales/uk/settings.json | 33 -- apps/browser-extension/src/utils/i18n.ts | 26 +- .../src/utils/i18n/StandaloneI18n.ts | 99 +----- crowdin.yml | 4 +- 69 files changed, 2164 insertions(+), 1787 deletions(-) create mode 100644 apps/browser-extension/src/locales/de.json delete mode 100644 apps/browser-extension/src/locales/de/auth.json delete mode 100644 apps/browser-extension/src/locales/de/common.json delete mode 100644 apps/browser-extension/src/locales/de/credentials.json delete mode 100644 apps/browser-extension/src/locales/de/emails.json delete mode 100644 apps/browser-extension/src/locales/de/settings.json create mode 100644 apps/browser-extension/src/locales/en.json delete mode 100644 apps/browser-extension/src/locales/en/auth.json delete mode 100644 apps/browser-extension/src/locales/en/common.json delete mode 100644 apps/browser-extension/src/locales/en/content.json delete mode 100644 apps/browser-extension/src/locales/en/credentials.json delete mode 100644 apps/browser-extension/src/locales/en/emails.json delete mode 100644 apps/browser-extension/src/locales/en/settings.json create mode 100644 apps/browser-extension/src/locales/es.json delete mode 100644 apps/browser-extension/src/locales/es/auth.json delete mode 100644 apps/browser-extension/src/locales/es/common.json delete mode 100644 apps/browser-extension/src/locales/es/credentials.json delete mode 100644 apps/browser-extension/src/locales/es/emails.json delete mode 100644 apps/browser-extension/src/locales/es/settings.json create mode 100644 apps/browser-extension/src/locales/fr.json delete mode 100644 apps/browser-extension/src/locales/fr/auth.json delete mode 100644 apps/browser-extension/src/locales/fr/common.json delete mode 100644 apps/browser-extension/src/locales/fr/credentials.json delete mode 100644 apps/browser-extension/src/locales/fr/emails.json delete mode 100644 apps/browser-extension/src/locales/fr/settings.json create mode 100644 apps/browser-extension/src/locales/nl.json delete mode 100644 apps/browser-extension/src/locales/nl/auth.json delete mode 100644 apps/browser-extension/src/locales/nl/common.json delete mode 100644 apps/browser-extension/src/locales/nl/content.json delete mode 100644 apps/browser-extension/src/locales/nl/credentials.json delete mode 100644 apps/browser-extension/src/locales/nl/emails.json delete mode 100644 apps/browser-extension/src/locales/nl/settings.json create mode 100644 apps/browser-extension/src/locales/uk.json delete mode 100644 apps/browser-extension/src/locales/uk/auth.json delete mode 100644 apps/browser-extension/src/locales/uk/common.json delete mode 100644 apps/browser-extension/src/locales/uk/credentials.json delete mode 100644 apps/browser-extension/src/locales/uk/emails.json delete mode 100644 apps/browser-extension/src/locales/uk/settings.json diff --git a/apps/browser-extension/src/entrypoints/background/ContextMenu.ts b/apps/browser-extension/src/entrypoints/background/ContextMenu.ts index 10f64a086..f92e716e8 100644 --- a/apps/browser-extension/src/entrypoints/background/ContextMenu.ts +++ b/apps/browser-extension/src/entrypoints/background/ContextMenu.ts @@ -2,7 +2,7 @@ import { type Browser } from '@wxt-dev/browser'; import { sendMessage } from 'webext-bridge/background'; import { PasswordGenerator } from '@/utils/dist/shared/password-generator'; -import { tc } from '@/utils/i18n/StandaloneI18n'; +import { t } from '@/utils/i18n/StandaloneI18n'; import { browser } from "#imports"; @@ -21,7 +21,7 @@ export async function setupContextMenus() : Promise { browser.contextMenus.create({ id: "aliasvault-activate-form", parentId: "aliasvault-root", - title: await tc('autofillWithAliasVault'), + title: await t('content.autofillWithAliasVault'), contexts: ["editable"], }); @@ -37,7 +37,7 @@ export async function setupContextMenus() : Promise { browser.contextMenus.create({ id: "aliasvault-generate-password", parentId: "aliasvault-root", - title: await tc('generateRandomPassword'), + title: await t('content.generateRandomPassword'), contexts: ["all"] }); @@ -83,7 +83,7 @@ export function handleContextMenuClick(info: Browser.contextMenus.OnClickData, t */ async function copyPasswordToClipboard(generatedPassword: string) : Promise { navigator.clipboard.writeText(generatedPassword).then(async () => { - showToast(await tc('passwordCopiedToClipboard')); + showToast(await t('content.passwordCopiedToClipboard')); }); /** diff --git a/apps/browser-extension/src/entrypoints/background/VaultMessageHandler.ts b/apps/browser-extension/src/entrypoints/background/VaultMessageHandler.ts index 87770b9f3..07dde59ed 100644 --- a/apps/browser-extension/src/entrypoints/background/VaultMessageHandler.ts +++ b/apps/browser-extension/src/entrypoints/background/VaultMessageHandler.ts @@ -3,7 +3,7 @@ import { storage } from 'wxt/utils/storage'; import type { Vault, VaultResponse, VaultPostResponse } from '@/utils/dist/shared/models/webapi'; import { EncryptionUtility } from '@/utils/EncryptionUtility'; -import { tc } from '@/utils/i18n/StandaloneI18n'; +import { t } from '@/utils/i18n/StandaloneI18n'; import { SqliteClient } from '@/utils/SqliteClient'; import { BoolResponse as messageBoolResponse } from '@/utils/types/messaging/BoolResponse'; import { CredentialsResponse as messageCredentialsResponse } from '@/utils/types/messaging/CredentialsResponse'; @@ -59,7 +59,7 @@ export async function handleCheckAuthStatus() : Promise<{ isLoggedIn: boolean, i isLoggedIn, isVaultLocked, hasPendingMigrations: false, - error: error instanceof Error ? error.message : await tc('errors.unknownError', 'common') + error: error instanceof Error ? error.message : await t('common.errors.unknownError') }; } } @@ -101,7 +101,7 @@ export async function handleStoreVault( return { success: true }; } catch (error) { console.error('Failed to store vault:', error); - return { success: false, error: await tc('errors.failedToStoreVault', 'common') }; + return { success: false, error: await t('common.errors.failedToStoreVault') }; } } @@ -114,7 +114,7 @@ export async function handleSyncVault( const statusResponse = await webApi.getStatus(); const statusError = webApi.validateStatusResponse(statusResponse); if (statusError !== null) { - return { success: false, error: await tc(statusError) }; + return { success: false, error: await t('common.errors.' + statusError) }; } const vaultRevisionNumber = await storage.getItem('session:vaultRevisionNumber') as number; @@ -148,7 +148,7 @@ export async function handleGetVault( if (!encryptedVault) { console.error('Vault not available'); - return { success: false, error: await tc('errors.vaultNotAvailable', 'common') }; + return { success: false, error: await t('common.errors.vaultNotAvailable') }; } const decryptedVault = await EncryptionUtility.symmetricDecrypt( @@ -165,7 +165,7 @@ export async function handleGetVault( }; } catch (error) { console.error('Failed to get vault:', error); - return { success: false, error: await tc('errors.failedToGetVault', 'common') }; + return { success: false, error: await t('common.errors.failedToGetVault') }; } } @@ -193,7 +193,7 @@ export async function handleGetCredentials( const derivedKey = await storage.getItem('session:derivedKey') as string; if (!derivedKey) { - return { success: false, error: await tc('errors.vaultIsLocked', 'common') }; + return { success: false, error: await t('common.errors.vaultIsLocked') }; } try { @@ -202,7 +202,7 @@ export async function handleGetCredentials( return { success: true, credentials: credentials }; } catch (error) { console.error('Error getting credentials:', error); - return { success: false, error: await tc('errors.failedToGetCredentials', 'common') }; + return { success: false, error: await t('common.errors.failedToGetCredentials') }; } } @@ -215,7 +215,7 @@ export async function handleCreateIdentity( const derivedKey = await storage.getItem('session:derivedKey') as string; if (!derivedKey) { - return { success: false, error: await tc('errors.vaultIsLocked', 'common') }; + return { success: false, error: await t('common.errors.vaultIsLocked') }; } try { @@ -230,7 +230,7 @@ export async function handleCreateIdentity( return { success: true }; } catch (error) { console.error('Failed to create identity:', error); - return { success: false, error: await tc('errors.failedToCreateIdentity', 'common') }; + return { success: false, error: await t('common.errors.failedToCreateIdentity') }; } } @@ -272,7 +272,7 @@ export function handleGetDefaultEmailDomain(): Promise { return { success: true, value: defaultEmailDomain ?? undefined }; } catch (error) { console.error('Error getting default email domain:', error); - return { success: false, error: await tc('errors.failedToGetDefaultEmailDomain', 'common') }; + return { success: false, error: await t('common.errors.failedToGetDefaultEmailDomain') }; } })(); } @@ -296,7 +296,7 @@ export async function handleGetDefaultIdentitySettings( }; } catch (error) { console.error('Error getting default identity settings:', error); - return { success: false, error: await tc('errors.failedToGetDefaultIdentitySettings', 'common') }; + return { success: false, error: await t('common.errors.failedToGetDefaultIdentitySettings') }; } } @@ -312,7 +312,7 @@ export async function handleGetPasswordSettings( return { success: true, settings: passwordSettings }; } catch (error) { console.error('Error getting password settings:', error); - return { success: false, error: await tc('errors.failedToGetPasswordSettings', 'common') }; + return { success: false, error: await t('common.errors.failedToGetPasswordSettings') }; } } @@ -343,7 +343,7 @@ export async function handleUploadVault( return { success: true, status: response.status, newRevisionNumber: response.newRevisionNumber }; } catch (error) { console.error('Failed to upload vault:', error); - return { success: false, error: await tc('errors.failedToUploadVault', 'common') }; + return { success: false, error: await t('common.errors.failedToUploadVault') }; } } @@ -354,7 +354,7 @@ export async function handleUploadVault( export async function handlePersistFormValues(data: any): Promise { const derivedKey = await storage.getItem('session:derivedKey') as string; if (!derivedKey) { - throw new Error(await tc('errors.noDerivedKeyAvailable', 'common')); + throw new Error(await t('common.errors.noDerivedKeyAvailable')); } // Always stringify the data properly @@ -442,7 +442,7 @@ async function uploadNewVaultToServer(sqliteClient: SqliteClient) : Promise { const encryptedVault = await storage.getItem('session:encryptedVault') as string; const derivedKey = await storage.getItem('session:derivedKey') as string; if (!encryptedVault || !derivedKey) { - throw new Error(await tc('errors.noVaultOrDerivedKeyFound', 'common')); + throw new Error(await t('common.errors.noVaultOrDerivedKeyFound')); } // Decrypt the vault. diff --git a/apps/browser-extension/src/entrypoints/content.ts b/apps/browser-extension/src/entrypoints/content.ts index 82172924e..84e7da305 100644 --- a/apps/browser-extension/src/entrypoints/content.ts +++ b/apps/browser-extension/src/entrypoints/content.ts @@ -5,11 +5,11 @@ import { injectIcon, popupDebounceTimeHasPassed, validateInputField } from '@/en import { isAutoShowPopupEnabled, openAutofillPopup, removeExistingPopup, createUpgradeRequiredPopup } from '@/entrypoints/contentScript/Popup'; import { FormDetector } from '@/utils/formDetector/FormDetector'; +import { t } from '@/utils/i18n/StandaloneI18n'; import { BoolResponse as messageBoolResponse } from '@/utils/types/messaging/BoolResponse'; import { defineContentScript } from '#imports'; import { createShadowRootUi } from '#imports'; -import { tc } from '@/utils/i18n/StandaloneI18n'; export default defineContentScript({ matches: [''], @@ -160,7 +160,7 @@ export default defineContentScript({ if (authStatus.hasPendingMigrations) { // Show upgrade required popup - await createUpgradeRequiredPopup(inputElement, container, await tc('vaultUpgradeRequired')); + await createUpgradeRequiredPopup(inputElement, container, await t('content.vaultUpgradeRequired')); return; } diff --git a/apps/browser-extension/src/entrypoints/contentScript/Popup.ts b/apps/browser-extension/src/entrypoints/contentScript/Popup.ts index 4518f3343..4513b3856 100644 --- a/apps/browser-extension/src/entrypoints/contentScript/Popup.ts +++ b/apps/browser-extension/src/entrypoints/contentScript/Popup.ts @@ -8,7 +8,7 @@ import { CreateIdentityGenerator } from '@/utils/dist/shared/identity-generator' import type { Credential } from '@/utils/dist/shared/models/vault'; import { CreatePasswordGenerator, PasswordGenerator } from '@/utils/dist/shared/password-generator'; import { FormDetector } from '@/utils/formDetector/FormDetector'; -import { tc } from '@/utils/i18n/StandaloneI18n'; +import { t } from '@/utils/i18n/StandaloneI18n'; import { SqliteClient } from '@/utils/SqliteClient'; import { CredentialsResponse } from '@/utils/types/messaging/CredentialsResponse'; import { IdentitySettingsResponse } from '@/utils/types/messaging/IdentitySettingsResponse'; @@ -157,13 +157,13 @@ export function removeExistingPopup(container: HTMLElement) : void { */ export async function createAutofillPopup(input: HTMLInputElement, credentials: Credential[] | undefined, rootContainer: HTMLElement) : Promise { // Get all translations first - const newText = await tc('new'); - const searchPlaceholder = await tc('searchVault'); - const hideFor1HourText = await tc('hideFor1Hour'); - const hidePermanentlyText = await tc('hidePermanently'); - const noMatchesText = await tc('noMatchesFound'); - const creatingText = await tc('creatingNewAlias'); - const failedText = await tc('failedToCreateIdentity'); + const newText = await t('content.new'); + const searchPlaceholder = await t('content.searchVault'); + const hideFor1HourText = await t('content.hideFor1Hour'); + const hidePermanentlyText = await t('content.hidePermanently'); + const noMatchesText = await t('content.noMatchesFound'); + const creatingText = await t('content.creatingNewAlias'); + const failedText = await t('content.failedToCreateIdentity'); // Disable browser's native autocomplete to avoid conflicts with AliasVault's autocomplete. input.setAttribute('autocomplete', 'false'); @@ -471,7 +471,7 @@ export async function createVaultLockedPopup(input: HTMLInputElement, rootContai // Add message const messageElement = document.createElement('div'); messageElement.className = 'av-vault-locked-message'; - messageElement.textContent = await tc('vaultLocked'); + messageElement.textContent = await t('content.vaultLocked'); container.appendChild(messageElement); // Add unlock button with SVG icon @@ -771,10 +771,10 @@ export async function createAliasCreationPopup(suggestedNames: string[], rootCon `; - const randomIdentitySubtext = await tc('randomIdentityDescription'); - const randomIdentityTitle = await tc('createRandomAlias'); - const randomIdentityTitleDropdown = await tc('randomAlias'); - const randomIdentitySubtextDropdown = await tc('randomIdentityDescriptionDropdown'); + const randomIdentitySubtext = await t('content.randomIdentityDescription'); + const randomIdentityTitle = await t('content.createRandomAlias'); + const randomIdentityTitleDropdown = await t('content.randomAlias'); + const randomIdentitySubtextDropdown = await t('content.randomIdentityDescriptionDropdown'); const manualUsernamePasswordIcon = ` @@ -782,24 +782,24 @@ export async function createAliasCreationPopup(suggestedNames: string[], rootCon `; - const manualUsernamePasswordSubtext = await tc('manualCredentialDescription'); - const manualUsernamePasswordTitle = await tc('createUsernamePassword'); - const manualUsernamePasswordTitleDropdown = await tc('usernamePassword'); - const manualUsernamePasswordSubtextDropdown = await tc('manualCredentialDescriptionDropdown'); + const manualUsernamePasswordSubtext = await t('content.manualCredentialDescription'); + const manualUsernamePasswordTitle = await t('content.createUsernamePassword'); + const manualUsernamePasswordTitleDropdown = await t('content.usernamePassword'); + const manualUsernamePasswordSubtextDropdown = await t('content.manualCredentialDescriptionDropdown'); // Get all translated strings first - const serviceNameText = await tc('serviceName'); - const enterServiceNameText = await tc('enterServiceName'); - const cancelText = await tc('cancel'); - const createAndSaveAliasText = await tc('createAndSaveAlias'); - const emailText = await tc('email'); - const enterEmailAddressText = await tc('enterEmailAddress'); - const usernameText = await tc('username'); - const enterUsernameText = await tc('enterUsername'); - const generatedPasswordText = await tc('generatedPassword'); - const generateNewPasswordText = await tc('generateNewPassword'); - const togglePasswordVisibilityText = await tc('togglePasswordVisibility'); - const createAndSaveCredentialText = await tc('createAndSaveCredential'); + const serviceNameText = await t('content.serviceName'); + const enterServiceNameText = await t('content.enterServiceName'); + const cancelText = await t('content.cancel'); + const createAndSaveAliasText = await t('content.createAndSaveAlias'); + const emailText = await t('content.email'); + const enterEmailAddressText = await t('content.enterEmailAddress'); + const usernameText = await t('content.username'); + const enterUsernameText = await t('content.enterUsername'); + const generatedPasswordText = await t('content.generatedPassword'); + const generateNewPasswordText = await t('content.generateNewPassword'); + const togglePasswordVisibilityText = await t('content.togglePasswordVisibility'); + const createAndSaveCredentialText = await t('content.createAndSaveCredential'); // Create the main content popup.innerHTML = ` @@ -1163,14 +1163,14 @@ export async function createAliasCreationPopup(suggestedNames: string[], rootCon if (!emailLabel.querySelector('.av-create-popup-error-text')) { const emailError = document.createElement('span'); emailError.className = 'av-create-popup-error-text'; - emailError.textContent = await tc('enterEmailAndOrUsername'); + emailError.textContent = await t('content.enterEmailAndOrUsername'); emailLabel.appendChild(emailError); } if (!usernameLabel.querySelector('.av-create-popup-error-text')) { const usernameError = document.createElement('span'); usernameError.className = 'av-create-popup-error-text'; - usernameError.textContent = await tc('enterEmailAndOrUsername'); + usernameError.textContent = await t('content.enterEmailAndOrUsername'); usernameLabel.appendChild(usernameError); } @@ -1525,7 +1525,7 @@ export async function createUpgradeRequiredPopup(input: HTMLInputElement, rootCo // Add upgrade button with SVG icon const button = document.createElement('button'); - button.title = await tc('openAliasVaultToUpgrade'); + button.title = await t('content.openAliasVaultToUpgrade'); button.className = 'av-upgrade-required-button'; button.innerHTML = ` @@ -1540,7 +1540,7 @@ export async function createUpgradeRequiredPopup(input: HTMLInputElement, rootCo // Add close button as a separate element positioned to the right const closeButton = document.createElement('button'); closeButton.className = 'av-button av-button-close av-upgrade-required-close'; - closeButton.title = await tc('dismissPopup'); + closeButton.title = await t('content.dismissPopup'); closeButton.innerHTML = ` diff --git a/apps/browser-extension/src/entrypoints/popup/App.tsx b/apps/browser-extension/src/entrypoints/popup/App.tsx index 46598488f..3b3346df9 100644 --- a/apps/browser-extension/src/entrypoints/popup/App.tsx +++ b/apps/browser-extension/src/entrypoints/popup/App.tsx @@ -42,7 +42,7 @@ type RouteConfig = { * App component. */ const App: React.FC = () => { - const { t } = useTranslation(['common', 'credentials', 'emails', 'settings']); + const { t } = useTranslation(); const authContext = useAuth(); const { isInitialLoading } = useLoading(); const [isLoading, setIsLoading] = useMinDurationLoading(true, 150); @@ -57,13 +57,13 @@ const App: React.FC = () => { { path: '/unlock', element: , showBackButton: false }, { path: '/unlock-success', element: , showBackButton: false }, { path: '/upgrade', element: , showBackButton: false }, - { path: '/auth-settings', element: , showBackButton: true, title: t('settings:title') }, + { path: '/auth-settings', element: , showBackButton: true, title: t('settings.title') }, { path: '/credentials', element: , showBackButton: false }, - { path: '/credentials/add', element: , showBackButton: true, title: t('credentials:addCredential') }, - { path: '/credentials/:id', element: , showBackButton: true, title: t('credentials:credentialDetails') }, - { path: '/credentials/:id/edit', element: , showBackButton: true, title: t('credentials:editCredential') }, + { path: '/credentials/add', element: , showBackButton: true, title: t('credentials.addCredential') }, + { path: '/credentials/:id', element: , showBackButton: true, title: t('credentials.credentialDetails') }, + { path: '/credentials/:id/edit', element: , showBackButton: true, title: t('credentials.editCredential') }, { path: '/emails', element: , showBackButton: false }, - { path: '/emails/:id', element: , showBackButton: true, title: t('emails:title') }, + { path: '/emails/:id', element: , showBackButton: true, title: t('emails.title') }, { path: '/settings', element: , showBackButton: false }, { path: '/logout', element: , showBackButton: false }, ]; diff --git a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/AliasBlock.tsx b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/AliasBlock.tsx index d9dfda358..b87df7dfa 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/AliasBlock.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/AliasBlock.tsx @@ -14,7 +14,7 @@ type AliasBlockProps = { * Render the alias block. */ const AliasBlock: React.FC = ({ credential }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation(); const hasFirstName = Boolean(credential.Alias?.FirstName?.trim()); const hasLastName = Boolean(credential.Alias?.LastName?.trim()); const hasNickName = Boolean(credential.Alias?.NickName?.trim()); @@ -26,39 +26,39 @@ const AliasBlock: React.FC = ({ credential }) => { return (
-

{t('alias')}

+

{t('common.alias')}

{(hasFirstName || hasLastName) && ( )} {hasFirstName && ( )} {hasLastName && ( )} {hasBirthDate && ( )} {hasNickName && ( )} diff --git a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/LoginCredentialsBlock.tsx b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/LoginCredentialsBlock.tsx index 16d84c57a..4077179ca 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/LoginCredentialsBlock.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/LoginCredentialsBlock.tsx @@ -13,7 +13,7 @@ type LoginCredentialsBlockProps = { * Render the login credentials block. */ const LoginCredentialsBlock: React.FC = ({ credential }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation(); const email = credential.Alias?.Email?.trim(); const username = credential.Username?.trim(); const password = credential.Password?.trim(); @@ -24,25 +24,25 @@ const LoginCredentialsBlock: React.FC = ({ credentia return (
-

{t('loginCredentials')}

+

{t('common.loginCredentials')}

{email && ( )} {username && ( )} {password && ( diff --git a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/NotesBlock.tsx b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/NotesBlock.tsx index 7dc8dc910..b2f5a3169 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/NotesBlock.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/CredentialDetails/NotesBlock.tsx @@ -21,7 +21,7 @@ const convertUrlsToLinks = (text: string): string => { * Render the notes block. */ const NotesBlock: React.FC = ({ notes }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation(); if (!notes) { return null; } @@ -30,7 +30,7 @@ const NotesBlock: React.FC = ({ notes }) => { return (
-

{t('notes')}

+

{t('common.notes')}

= ({ credentialId }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation(); const [totpCodes, setTotpCodes] = useState([]); const [loading, setLoading] = useState(true); const [currentCodes, setCurrentCodes] = useState>({}); @@ -140,8 +140,8 @@ const TotpBlock: React.FC = ({ credentialId }) => { if (loading) { return (

-

{t('twoFactorAuthentication')}

- {t('loadingTotpCodes')} +

{t('common.twoFactorAuthentication')}

+ {t('common.loadingTotpCodes')}
); } @@ -153,7 +153,7 @@ const TotpBlock: React.FC = ({ credentialId }) => { return (
-

{t('twoFactorAuthentication')}

+

{t('common.twoFactorAuthentication')}

{totpCodes.map(totpCode => (
diff --git a/apps/browser-extension/src/entrypoints/popup/components/Layout/Header.tsx b/apps/browser-extension/src/entrypoints/popup/components/Layout/Header.tsx index f5929ae10..05247a975 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/Layout/Header.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/Layout/Header.tsx @@ -23,7 +23,7 @@ const Header: React.FC = ({ routes = [], rightButtons }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation(); const authContext = useAuth(); const navigate = useNavigate(); const location = useLocation(); @@ -88,7 +88,7 @@ const Header: React.FC = ({ className="flex items-center hover:opacity-80 transition-opacity" > AliasVault -

{t('appName')}

+

{t('common.appName')}

{/* Hide beta badge on Safari as it's not allowed to show non-production badges */} {!import.meta.env.SAFARI && ( BETA @@ -108,7 +108,7 @@ const Header: React.FC = ({ onClick={(handleSettings)} className="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700" > - {t('settings')} + {t('common.settings')} diff --git a/apps/browser-extension/src/entrypoints/popup/components/LoginServerInfo.tsx b/apps/browser-extension/src/entrypoints/popup/components/LoginServerInfo.tsx index cbb0f8a43..572698d0a 100644 --- a/apps/browser-extension/src/entrypoints/popup/components/LoginServerInfo.tsx +++ b/apps/browser-extension/src/entrypoints/popup/components/LoginServerInfo.tsx @@ -10,7 +10,7 @@ import { useApiUrl } from '@/entrypoints/popup/utils/ApiUrlUtility'; const LoginServerInfo: React.FC = () => { const { loadApiUrl, getDisplayUrl } = useApiUrl(); const navigate = useNavigate(); - const { t } = useTranslation('auth'); + const { t } = useTranslation(); useEffect(() => { /** @@ -28,7 +28,7 @@ const LoginServerInfo: React.FC = () => { return (
- ({t('connectingTo')}{' '} + ({t('auth.connectingTo')}{' '}
@@ -226,7 +226,7 @@ const EmailDetails: React.FC = (): React.ReactElement => {