From 5b6d82797ec1bc72263d4b4a93732b5612f4fa9b Mon Sep 17 00:00:00 2001 From: Reece Browne Date: Thu, 14 Aug 2025 19:02:54 +0100 Subject: [PATCH] Refactor translation keys and enhance i18n configuration --- .claude/settings.local.json | 3 +- .../public/locales/en-GB/translation.json | 18 ++++-------- frontend/public/locales/en/translation.json | 29 ------------------- .../src/components/shared/LandingPage.tsx | 4 +-- frontend/src/hooks/useToolManagement.tsx | 10 +++++-- frontend/src/i18n.ts | 8 +++++ 6 files changed, 25 insertions(+), 47 deletions(-) delete mode 100644 frontend/public/locales/en/translation.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8032f1d50..8a0c92367 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,8 @@ "Bash(npm test)", "Bash(npm test:*)", "Bash(ls:*)", - "Bash(npx tsc:*)" + "Bash(npx tsc:*)", + "Bash(sed:*)" ], "deny": [] } diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 247162df3..bbda8a387 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -380,14 +380,6 @@ "title": "Remove", "desc": "Delete unwanted pages from your PDF document." }, - "addPassword": { - "title": "Add Password", - "desc": "Encrypt your PDF document with a password." - }, - "changePermissions": { - "title": "Change Permissions", - "desc": "Change document restrictions and permissions." - }, "removePassword": { "title": "Remove Password", "desc": "Remove password protection from your PDF document." @@ -396,10 +388,6 @@ "title": "Compress", "desc": "Compress PDFs to reduce their file size." }, - "sanitize": { - "title": "Sanitise", - "desc": "Remove potentially harmful elements from PDF files." - }, "unlockPDFForms": { "title": "Unlock PDF Forms", "desc": "Remove read-only property of form fields in a PDF document." @@ -1748,6 +1736,8 @@ "approximateSize": "Approximate size" }, "sanitize": { + "title": "Sanitise", + "desc": "Remove potentially harmful elements from PDF files.", "submit": "Sanitise PDF", "completed": "Sanitisation completed successfully", "error.generic": "Sanitisation failed", @@ -1780,6 +1770,8 @@ } }, "addPassword": { + "title": "Add Password", + "desc": "Encrypt your PDF document with a password.", "completed": "Password protection applied", "submit": "Encrypt", "filenamePrefix": "encrypted", @@ -1838,6 +1830,8 @@ } }, "changePermissions": { + "title": "Change Permissions", + "desc": "Change document restrictions and permissions.", "completed": "Permissions changed", "submit": "Change Permissions", "error": { diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json deleted file mode 100644 index 8dc3e4f90..000000000 --- a/frontend/public/locales/en/translation.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "convert": { - "selectSourceFormat": "Select source file format", - "selectTargetFormat": "Select target file format", - "selectFirst": "Select a source format first", - "imageOptions": "Image Options:", - "emailOptions": "Email Options:", - "colorType": "Color Type", - "dpi": "DPI", - "singleOrMultiple": "Output", - "emailNote": "Email attachments and embedded images will be included" - }, - "common": { - "color": "Color", - "grayscale": "Grayscale", - "blackWhite": "Black & White", - "single": "Single Image", - "multiple": "Multiple Images" - }, - "groups": { - "document": "Document", - "spreadsheet": "Spreadsheet", - "presentation": "Presentation", - "image": "Image", - "web": "Web", - "text": "Text", - "email": "Email" - } -} \ No newline at end of file diff --git a/frontend/src/components/shared/LandingPage.tsx b/frontend/src/components/shared/LandingPage.tsx index 40b765547..99ecab279 100644 --- a/frontend/src/components/shared/LandingPage.tsx +++ b/frontend/src/components/shared/LandingPage.tsx @@ -116,7 +116,7 @@ const LandingPage = () => { > - {t('fileUpload.addFiles', 'Add Files')} + {t('fileUpload.uploadFiles', 'Upload Files')} @@ -137,7 +137,7 @@ const LandingPage = () => { className="text-[var(--accent-interactive)]" style={{ fontSize: '.8rem' }} > - {t('fileUpload.dragFilesInOrClick', 'Drag files in or click "Add Files" to browse')} + {t('fileUpload.dropFilesHere', 'Drop files here or click to upload')} diff --git a/frontend/src/hooks/useToolManagement.tsx b/frontend/src/hooks/useToolManagement.tsx index 75b656e34..3e50202a4 100644 --- a/frontend/src/hooks/useToolManagement.tsx +++ b/frontend/src/hooks/useToolManagement.tsx @@ -118,7 +118,7 @@ interface ToolManagementResult { } export const useToolManagement = (): ToolManagementResult => { - const { t } = useTranslation(); + const { t, ready } = useTranslation(); const [selectedToolKey, setSelectedToolKey] = useState(null); const [toolSelectedFileIds, setToolSelectedFileIds] = useState([]); @@ -136,18 +136,22 @@ export const useToolManagement = (): ToolManagementResult => { }, [endpointsLoading, endpointStatus]); const toolRegistry: ToolRegistry = useMemo(() => { + if (!ready) { + return {}; + } + const availableTools: ToolRegistry = {}; Object.keys(toolDefinitions).forEach(toolKey => { if (isToolAvailable(toolKey)) { const toolDef = toolDefinitions[toolKey]; availableTools[toolKey] = { ...toolDef, - name: t(`home.${toolKey}.title`, toolKey.charAt(0).toUpperCase() + toolKey.slice(1)) + name: t(`${toolKey}.title`, toolKey.charAt(0).toUpperCase() + toolKey.slice(1)) }; } }); return availableTools; - }, [t, isToolAvailable]); + }, [t, isToolAvailable, ready]); useEffect(() => { if (!endpointsLoading && selectedToolKey && !toolRegistry[selectedToolKey]) { diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index a33a29929..c8d7c4798 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -57,6 +57,8 @@ i18n .use(initReactI18next) .init({ fallbackLng: 'en-GB', + supportedLngs: Object.keys(supportedLanguages), + nonExplicitSupportedLngs: false, debug: process.env.NODE_ENV === 'development', interpolation: { @@ -77,6 +79,12 @@ i18n }, }); +// Map base language codes to specific locales +i18n.services.languageUtils.formatLanguageCode = (lng) => { + if (lng === 'en') return 'en-GB'; + return lng; +}; + // Set document direction based on language i18n.on('languageChanged', (lng) => { const isRTL = rtlLanguages.includes(lng);