From 53d167eda5e423da6aa691329afa13b978225aa7 Mon Sep 17 00:00:00 2001 From: Reece Browne <74901996+reecebrowne@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:03:47 +0000 Subject: [PATCH] Chore/v2/translation fixes (#5011) # Description of Changes --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- frontend/package-lock.json | 65 ++---- frontend/package.json | 10 +- .../public/locales/en-GB/translation.json | 65 +++++- .../core/components/shared/AppConfigModal.tsx | 13 +- .../shared/config/configNavSections.tsx | 33 +++ .../config/configSections/HotkeysSection.tsx | 9 +- .../shared/config/configSections/Overview.tsx | 16 +- .../shared/config/configNavSections.tsx | 35 +++- .../shared/config/configNavSections.tsx | 195 +++++++++++++++++- .../configSections/AdminGeneralSection.tsx | 6 +- .../configSections/TeamDetailsSection.tsx | 2 +- 11 files changed, 369 insertions(+), 80 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 09d752a4b..86aba36a2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -70,7 +70,7 @@ }, "devDependencies": { "@eslint/js": "^9.36.0", - "@iconify-json/material-symbols": "^1.2.37", + "@iconify-json/material-symbols": "^1.2.48", "@iconify/utils": "^3.0.2", "@playwright/test": "^1.55.0", "@tauri-apps/cli": "^2.5.0", @@ -455,7 +455,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -499,7 +498,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -580,7 +578,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.4.1.tgz", "integrity": "sha512-TGpxn2CvAKRnOJWJ3bsK+dKBiCp75ehxftRUmv7wAmPomhnG5XrDfoWJungvO+zbbqAwso6PocdeXINVt3hlAw==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/engines": "1.4.1", "@embedpdf/models": "1.4.1" @@ -680,7 +677,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.4.1.tgz", "integrity": "sha512-5WLDiNMH6tACkLGGv/lJtNsDeozOhSbrh0mjD1btHun8u7Yscu/Vf8tdJRUOsd+nULivo2nQ2NFNKu0OTbVo8w==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -697,7 +693,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.4.1.tgz", "integrity": "sha512-Ng02S9SFIAi9JZS5rI+NXSnZZ1Yk9YYRw4MlN2pig49qOyivZdz0oScZaYxQPewo8ccJkLeghjdeWswOBW/6cA==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -715,7 +710,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.4.1.tgz", "integrity": "sha512-m3ZOk8JygsLxoa4cZ+0BVB5pfRWuBCg2/gPqjhoFZNKTqAFw4J6HGUrhYKg94GRYe+w1cTJl/NbTBYuU5DOrsA==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -752,7 +746,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.4.1.tgz", "integrity": "sha512-gKCdNKw6WBHBEpTc2DLBWIWOxzsNnaNbpfeY6C4f2Bum0EO+XW3Hl2oIx1uaRHjIhhnXso1J3QweqelsPwDGwg==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -787,7 +780,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.4.1.tgz", "integrity": "sha512-Y9O+matB4j4fLim5s/jn7qIi+lMC9vmDJRpJhiWe8bvD9oYLP2xfD/DdhFgAjRKcNhPoxC+j8q8QN5BMeGAv2Q==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -824,7 +816,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.4.1.tgz", "integrity": "sha512-lo5Ytk1PH0PrRKv6zKVupm4t02VGsqIrnSIeP6NO8Ujx0wfqEhj//sqIuO/EwfFVJD8lcQIP9UUo9y8baCrEog==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -900,7 +891,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.4.1.tgz", "integrity": "sha512-+TgFHKPCLTBiDYe2DdsmTS37hwQgcZ3dYIc7bE0l5cp+GVwouu1h0MTmjL+90loizeWwCiu10E/zXR6hz+CUaQ==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.4.1" }, @@ -1056,7 +1046,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1100,7 +1089,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1896,9 +1884,9 @@ } }, "node_modules/@iconify-json/material-symbols": { - "version": "1.2.44", - "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.44.tgz", - "integrity": "sha512-NAJjhswaK9FxBeIzFFsNygws7wHtmAkBWhF4YEwn1NZIMbA+LNITqhUiq6sP5mOdKQqnoritFTlQaZ47a5BgBg==", + "version": "1.2.48", + "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.48.tgz", + "integrity": "sha512-qDjqYEeNCm31tae3YbsprEklWHIoVPvqlbTuqtisNjlhHRSiXy5x+AtUq9VwjlITRU+TtqsP6jW2h+pnEUURRQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2131,7 +2119,6 @@ "resolved": "https://registry.npmjs.org/@mantine/core/-/core-8.3.6.tgz", "integrity": "sha512-paTl+0x+O/QtgMtqVJaG8maD8sfiOdgPmLOyG485FmeGZ1L3KMdEkhxZtmdGlDFsLXhmMGQ57ducT90bvhXX5A==", "license": "MIT", - "peer": true, "dependencies": { "@floating-ui/react": "^0.27.16", "clsx": "^2.1.1", @@ -2182,7 +2169,6 @@ "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.3.6.tgz", "integrity": "sha512-liHfaWXHAkLjJy+Bkr29UsCwAoDQ/a64WrM67lksx8F0qqyjR5RQH8zVlhuOjdpQnwtlUkE/YiTvbJiPcoI0bw==", "license": "MIT", - "peer": true, "peerDependencies": { "react": "^18.x || ^19.x" } @@ -2250,7 +2236,6 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "@mui/core-downloads-tracker": "^7.3.5", @@ -3183,7 +3168,6 @@ "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz", "integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.16" } @@ -3302,6 +3286,7 @@ "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz", "integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==", "license": "MIT", + "peer": true, "peerDependencies": { "acorn": "^8.9.0" } @@ -4078,7 +4063,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -4407,7 +4391,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -4418,7 +4401,6 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -4488,7 +4470,6 @@ "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.3", "@typescript-eslint/types": "8.46.3", @@ -5202,6 +5183,7 @@ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.24.tgz", "integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==", "license": "MIT", + "peer": true, "dependencies": { "@vue/shared": "3.5.24" } @@ -5211,6 +5193,7 @@ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.24.tgz", "integrity": "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==", "license": "MIT", + "peer": true, "dependencies": { "@vue/reactivity": "3.5.24", "@vue/shared": "3.5.24" @@ -5221,6 +5204,7 @@ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.24.tgz", "integrity": "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==", "license": "MIT", + "peer": true, "dependencies": { "@vue/reactivity": "3.5.24", "@vue/runtime-core": "3.5.24", @@ -5233,6 +5217,7 @@ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.24.tgz", "integrity": "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-ssr": "3.5.24", "@vue/shared": "3.5.24" @@ -5259,7 +5244,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5667,6 +5651,7 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">= 0.4" } @@ -5943,7 +5928,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -7000,8 +6984,7 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1521046.tgz", "integrity": "sha512-vhE6eymDQSKWUXwwA37NtTTVEzjtGVfDr3pRbsWEQ5onH/Snp2c+2xZHWJJawG/0hCCJLRGt4xVtEVUVILol4w==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -7396,7 +7379,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7567,7 +7549,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7734,7 +7715,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/espree": { "version": "10.4.0", @@ -7799,6 +7781,7 @@ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.2.tgz", "integrity": "sha512-DgvlIQeowRNyvLPWW4PT7Gu13WznY288Du086E751mwwbsgr29ytBiYeLzAGIo0qk3Ujob0SDk8TiSaM5WQzNg==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } @@ -8889,7 +8872,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.27.6" }, @@ -9375,6 +9357,7 @@ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "^1.0.6" } @@ -9695,7 +9678,6 @@ "integrity": "sha512-Pcfm3eZ+eO4JdZCXthW9tCDT3nF4K+9dmeZ+5X39n+Kqz0DDIABRP5CAEOHRFZk8RGuC2efksTJxrjp8EXCunQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@acemir/cssom": "^0.9.19", "@asamuzakjp/dom-selector": "^6.7.3", @@ -10282,7 +10264,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/locate-path": { "version": "6.0.0", @@ -11470,7 +11453,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -11750,7 +11732,6 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz", "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -12133,7 +12114,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -12143,7 +12123,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -13643,6 +13622,7 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">= 0.4" } @@ -13851,7 +13831,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14153,7 +14132,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14235,7 +14213,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -14440,7 +14417,6 @@ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -14592,7 +14568,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14606,7 +14581,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -15218,7 +15192,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/zod": { "version": "3.25.76", diff --git a/frontend/package.json b/frontend/package.json index d47f423c1..b11e10b4b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,12 +33,12 @@ "@mantine/dates": "^8.3.1", "@mantine/dropzone": "^8.3.1", "@mantine/hooks": "^8.3.1", - "@stripe/react-stripe-js": "^4.0.2", - "@stripe/stripe-js": "^7.9.0", - "@supabase/supabase-js": "^2.47.13", "@mui/icons-material": "^7.3.2", "@mui/material": "^7.3.2", "@reactour/tour": "^3.8.0", + "@stripe/react-stripe-js": "^4.0.2", + "@stripe/stripe-js": "^7.9.0", + "@supabase/supabase-js": "^2.47.13", "@tailwindcss/postcss": "^4.1.13", "@tanstack/react-virtual": "^3.13.12", "@tauri-apps/api": "^2.5.0", @@ -57,8 +57,8 @@ "posthog-js": "^1.268.0", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-rnd": "^10.5.2", "react-i18next": "^15.7.3", + "react-rnd": "^10.5.2", "react-router-dom": "^7.9.1", "signature_pad": "^5.0.4", "tailwindcss": "^4.1.13", @@ -117,7 +117,7 @@ }, "devDependencies": { "@eslint/js": "^9.36.0", - "@iconify-json/material-symbols": "^1.2.37", + "@iconify-json/material-symbols": "^1.2.48", "@iconify/utils": "^3.0.2", "@playwright/test": "^1.55.0", "@tauri-apps/cli": "^2.5.0", diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index dea5ff141..0e72a79c7 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -4059,7 +4059,8 @@ }, "languages": { "label": "Available Languages", - "description": "Languages that users can select from (leave empty to enable all languages)" + "description": "Languages that users can select from (leave empty to enable all languages)", + "placeholder": "Select languages" }, "customMetadata": { "label": "Custom Metadata", @@ -4084,7 +4085,9 @@ "label": "Logo Style", "description": "Set the default logo style for all users on this server. Users can override this setting in their personal preferences.", "classic": "Classic", - "modern": "Modern" + "classicAlt": "Classic logo", + "modern": "Modern", + "modernAlt": "Modern logo" }, "customPaths": { "label": "Custom Paths", @@ -4992,7 +4995,16 @@ "config": { "overview": { "title": "Application Configuration", - "description": "Current application settings and configuration details." + "description": "Current application settings and configuration details.", + "loading": "Loading configuration...", + "error": "Error", + "warning": "Configuration Warning", + "sections": { + "basic": "Basic Configuration", + "security": "Security Configuration", + "system": "System Configuration", + "integration": "Integration Configuration" + } }, "account": { "overview": { @@ -5367,6 +5379,7 @@ "description": "Manage teams and organize workspace members", "loading": "Loading teams...", "loadingDetails": "Loading team details...", + "loadError": "Failed to load team details", "createNewTeam": "Create New Team", "teamName": "Team Name", "totalMembers": "Total Members", @@ -5896,6 +5909,46 @@ } }, "settings": { + "preferences": { + "title": "Preferences" + }, + "workspace": { + "title": "Workspace", + "people": "People", + "teams": "Teams" + }, + "configuration": { + "title": "Configuration", + "systemSettings": "System Settings", + "features": "Features", + "endpoints": "Endpoints", + "database": "Database", + "advanced": "Advanced" + }, + "securityAuth": { + "title": "Security & Authentication", + "security": "Security", + "connections": "Connections" + }, + "licensingAnalytics": { + "title": "Licensing & Analytics", + "plan": "Plan", + "audit": "Audit", + "usageAnalytics": "Usage Analytics" + }, + "policiesPrivacy": { + "title": "Policies & Privacy", + "legal": "Legal", + "privacy": "Privacy" + }, + "developer": { + "title": "Developer", + "apiKeys": "API Keys" + }, + "tooltips": { + "enableLoginFirst": "Enable login mode first", + "requiresEnterprise": "Requires Enterprise license" + }, "connection": { "title": "Connection Mode", "mode": { @@ -5952,7 +6005,13 @@ "hideUnavailableConversionsDescription": "Remove disabled conversion options in the Convert tool instead of showing them greyed out." }, "hotkeys": { + "title": "Keyboard Shortcuts", + "description": "Customize keyboard shortcuts for quick tool access. Click \"Change shortcut\" and press a new key combination. Press Esc to cancel.", "errorConflict": "Shortcut already used by {{tool}}.", + "errorModifier": { + "mac": "Include ⌘ (Command), ⌥ (Option), or another modifier in your shortcut.", + "windows": "Include Ctrl, Alt, or another modifier in your shortcut." + }, "searchPlaceholder": "Search tools...", "none": "Not assigned", "customBadge": "Custom", diff --git a/frontend/src/core/components/shared/AppConfigModal.tsx b/frontend/src/core/components/shared/AppConfigModal.tsx index 5a54e20e6..2b64e60e3 100644 --- a/frontend/src/core/components/shared/AppConfigModal.tsx +++ b/frontend/src/core/components/shared/AppConfigModal.tsx @@ -2,7 +2,7 @@ import React, { useMemo, useState, useEffect, useCallback } from 'react'; import { Modal, Text, ActionIcon, Tooltip, Group } from '@mantine/core'; import { useNavigate, useLocation } from 'react-router-dom'; import LocalIcon from '@app/components/shared/LocalIcon'; -import { createConfigNavSections } from '@app/components/shared/config/configNavSections'; +import { useConfigNavSections } from '@app/components/shared/config/configNavSections'; import { NavKey, VALID_NAV_KEYS } from '@app/components/shared/config/types'; import { useAppConfig } from '@app/contexts/AppConfigContext'; import '@app/components/shared/AppConfigModal.css'; @@ -74,13 +74,10 @@ const AppConfigModalInner: React.FC = ({ opened, onClose }) const loginEnabled = config?.enableLogin ?? false; // Left navigation structure and icons - const configNavSections = useMemo(() => - createConfigNavSections( - isAdmin, - runningEE, - loginEnabled - ), - [isAdmin, runningEE, loginEnabled] + const configNavSections = useConfigNavSections( + isAdmin, + runningEE, + loginEnabled ); const activeLabel = useMemo(() => { diff --git a/frontend/src/core/components/shared/config/configNavSections.tsx b/frontend/src/core/components/shared/config/configNavSections.tsx index 36dd4dfcd..7a0bef8c0 100644 --- a/frontend/src/core/components/shared/config/configNavSections.tsx +++ b/frontend/src/core/components/shared/config/configNavSections.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import { NavKey } from '@app/components/shared/config/types'; import HotkeysSection from '@app/components/shared/config/configSections/HotkeysSection'; import GeneralSection from '@app/components/shared/config/configSections/GeneralSection'; @@ -27,11 +28,43 @@ export interface ConfigColors { headerBorder: string; } +export const useConfigNavSections = ( + _isAdmin: boolean = false, + _runningEE: boolean = false, + _loginEnabled: boolean = false +): ConfigNavSection[] => { + const { t } = useTranslation(); + + const sections: ConfigNavSection[] = [ + { + title: t('settings.preferences.title', 'Preferences'), + items: [ + { + key: 'general', + label: t('settings.general.title', 'General'), + icon: 'settings-rounded', + component: + }, + { + key: 'hotkeys', + label: t('settings.hotkeys.title', 'Keyboard Shortcuts'), + icon: 'keyboard-rounded', + component: + }, + ], + }, + ]; + + return sections; +}; + +// Deprecated: Use useConfigNavSections hook instead export const createConfigNavSections = ( _isAdmin: boolean = false, _runningEE: boolean = false, _loginEnabled: boolean = false ): ConfigNavSection[] => { + console.warn('createConfigNavSections is deprecated. Use useConfigNavSections hook instead for proper i18n support.'); const sections: ConfigNavSection[] = [ { title: 'Preferences', diff --git a/frontend/src/core/components/shared/config/configSections/HotkeysSection.tsx b/frontend/src/core/components/shared/config/configSections/HotkeysSection.tsx index 2839ccb9d..8d0774fbe 100644 --- a/frontend/src/core/components/shared/config/configSections/HotkeysSection.tsx +++ b/frontend/src/core/components/shared/config/configSections/HotkeysSection.tsx @@ -73,10 +73,7 @@ const HotkeysSection: React.FC = () => { const binding = eventToBinding(event as KeyboardEvent); if (!binding) { const osKey = isMac ? 'mac' : 'windows'; - const fallbackText = isMac - ? 'Include ⌘ (Command), ⌥ (Option), or another modifier in your shortcut.' - : 'Include Ctrl, Alt, or another modifier in your shortcut.'; - setError(t(`settings.hotkeys.errorModifier.${osKey}`, fallbackText)); + setError(t(`settings.hotkeys.errorModifier.${osKey}`)); return; } @@ -112,9 +109,9 @@ const HotkeysSection: React.FC = () => { return (
- Keyboard Shortcuts + {t('settings.hotkeys.title', 'Keyboard Shortcuts')} - Customize keyboard shortcuts for quick tool access. Click "Change shortcut" and press a new key combination. Press Esc to cancel. + {t('settings.hotkeys.description', 'Customize keyboard shortcuts for quick tool access. Click "Change shortcut" and press a new key combination. Press Esc to cancel.')}
diff --git a/frontend/src/core/components/shared/config/configSections/Overview.tsx b/frontend/src/core/components/shared/config/configSections/Overview.tsx index 4e552cec0..3bc8e84d9 100644 --- a/frontend/src/core/components/shared/config/configSections/Overview.tsx +++ b/frontend/src/core/components/shared/config/configSections/Overview.tsx @@ -1,9 +1,11 @@ import React from 'react'; import { Stack, Text, Code, Group, Badge, Alert, Loader } from '@mantine/core'; +import { useTranslation } from 'react-i18next'; import { useAppConfig } from '@app/contexts/AppConfigContext'; import { OverviewHeader } from '@app/components/shared/config/OverviewHeader'; const Overview: React.FC = () => { + const { t } = useTranslation(); const { config, loading, error } = useAppConfig(); const renderConfigSection = (title: string, data: any) => { @@ -58,14 +60,14 @@ const Overview: React.FC = () => { return ( - Loading configuration... + {t('config.overview.loading', 'Loading configuration...')} ); } if (error) { return ( - + {error} ); @@ -77,13 +79,13 @@ const Overview: React.FC = () => { {config && ( <> - {renderConfigSection('Basic Configuration', basicConfig)} - {renderConfigSection('Security Configuration', securityConfig)} - {renderConfigSection('System Configuration', systemConfig)} - {renderConfigSection('Integration Configuration', integrationConfig)} + {renderConfigSection(t('config.overview.sections.basic', 'Basic Configuration'), basicConfig)} + {renderConfigSection(t('config.overview.sections.security', 'Security Configuration'), securityConfig)} + {renderConfigSection(t('config.overview.sections.system', 'System Configuration'), systemConfig)} + {renderConfigSection(t('config.overview.sections.integration', 'Integration Configuration'), integrationConfig)} {config.error && ( - + {config.error} )} diff --git a/frontend/src/desktop/components/shared/config/configNavSections.tsx b/frontend/src/desktop/components/shared/config/configNavSections.tsx index 3582ccb99..9f8a63114 100644 --- a/frontend/src/desktop/components/shared/config/configNavSections.tsx +++ b/frontend/src/desktop/components/shared/config/configNavSections.tsx @@ -1,8 +1,39 @@ -import { createConfigNavSections as createProprietaryConfigNavSections } from '@proprietary/components/shared/config/configNavSections'; +import { useTranslation } from 'react-i18next'; +import { useConfigNavSections as useProprietaryConfigNavSections, createConfigNavSections as createProprietaryConfigNavSections } from '@proprietary/components/shared/config/configNavSections'; import { ConfigNavSection } from '@core/components/shared/config/configNavSections'; import { ConnectionSettings } from '@app/components/ConnectionSettings'; /** + * Hook version of desktop config nav sections with proper i18n support + */ +export const useConfigNavSections = ( + isAdmin: boolean = false, + runningEE: boolean = false, + loginEnabled: boolean = false +): ConfigNavSection[] => { + const { t } = useTranslation(); + + // Get the proprietary sections (includes core Preferences + admin sections) + const sections = useProprietaryConfigNavSections(isAdmin, runningEE, loginEnabled); + + // Add Connection section at the beginning (after Preferences) + sections.splice(1, 0, { + title: t('settings.connection.title', 'Connection Mode'), + items: [ + { + key: 'connectionMode', + label: t('settings.connection.title', 'Connection Mode'), + icon: 'cloud-rounded', + component: , + }, + ], + }); + + return sections; +}; + +/** + * Deprecated: Use useConfigNavSections hook instead * Desktop extension of createConfigNavSections that adds connection settings */ export const createConfigNavSections = ( @@ -10,6 +41,8 @@ export const createConfigNavSections = ( runningEE: boolean = false, loginEnabled: boolean = false ): ConfigNavSection[] => { + console.warn('createConfigNavSections is deprecated. Use useConfigNavSections hook instead for proper i18n support.'); + // Get the proprietary sections (includes core Preferences + admin sections) const sections = createProprietaryConfigNavSections(isAdmin, runningEE, loginEnabled); diff --git a/frontend/src/proprietary/components/shared/config/configNavSections.tsx b/frontend/src/proprietary/components/shared/config/configNavSections.tsx index 27e02bd89..6a64e5fbc 100644 --- a/frontend/src/proprietary/components/shared/config/configNavSections.tsx +++ b/frontend/src/proprietary/components/shared/config/configNavSections.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { createConfigNavSections as createCoreConfigNavSections, ConfigNavSection } from '@core/components/shared/config/configNavSections'; +import { useTranslation } from 'react-i18next'; +import { useConfigNavSections as useCoreConfigNavSections, createConfigNavSections as createCoreConfigNavSections, ConfigNavSection } from '@core/components/shared/config/configNavSections'; import PeopleSection from '@app/components/shared/config/configSections/PeopleSection'; import TeamsSection from '@app/components/shared/config/configSections/TeamsSection'; import AdminGeneralSection from '@app/components/shared/config/configSections/AdminGeneralSection'; @@ -17,6 +18,196 @@ import AdminUsageSection from '@app/components/shared/config/configSections/Admi import ApiKeys from '@app/components/shared/config/configSections/ApiKeys'; /** + * Hook version of proprietary config nav sections with proper i18n support + */ +export const useConfigNavSections = ( + isAdmin: boolean = false, + runningEE: boolean = false, + loginEnabled: boolean = false +): ConfigNavSection[] => { + const { t } = useTranslation(); + + // Get the core sections (just Preferences) + const sections = useCoreConfigNavSections(isAdmin, runningEE, loginEnabled); + + // Add Admin sections if user is admin OR if login is disabled (but mark as disabled) + if (isAdmin || !loginEnabled) { + const requiresLogin = !loginEnabled; + const enableLoginTooltip = t('settings.tooltips.enableLoginFirst', 'Enable login mode first'); + const requiresEnterpriseTooltip = t('settings.tooltips.requiresEnterprise', 'Requires Enterprise license'); + + // Workspace + sections.push({ + title: t('settings.workspace.title', 'Workspace'), + items: [ + { + key: 'people', + label: t('settings.workspace.people', 'People'), + icon: 'group-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'teams', + label: t('settings.workspace.teams', 'Teams'), + icon: 'groups-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + ], + }); + + // Configuration + sections.push({ + title: t('settings.configuration.title', 'Configuration'), + items: [ + { + key: 'adminGeneral', + label: t('settings.configuration.systemSettings', 'System Settings'), + icon: 'settings-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminFeatures', + label: t('settings.configuration.features', 'Features'), + icon: 'extension-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminEndpoints', + label: t('settings.configuration.endpoints', 'Endpoints'), + icon: 'api-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminDatabase', + label: t('settings.configuration.database', 'Database'), + icon: 'storage-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminAdvanced', + label: t('settings.configuration.advanced', 'Advanced'), + icon: 'tune-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + ], + }); + + // Security & Authentication + sections.push({ + title: t('settings.securityAuth.title', 'Security & Authentication'), + items: [ + { + key: 'adminSecurity', + label: t('settings.securityAuth.security', 'Security'), + icon: 'shield-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminConnections', + label: t('settings.securityAuth.connections', 'Connections'), + icon: 'link-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + ], + }); + + // Licensing & Analytics + sections.push({ + title: t('settings.licensingAnalytics.title', 'Licensing & Analytics'), + items: [ + { + key: 'adminPlan', + label: t('settings.licensingAnalytics.plan', 'Plan'), + icon: 'star-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminAudit', + label: t('settings.licensingAnalytics.audit', 'Audit'), + icon: 'fact-check-rounded', + component: , + disabled: !runningEE || requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : requiresEnterpriseTooltip + }, + { + key: 'adminUsage', + label: t('settings.licensingAnalytics.usageAnalytics', 'Usage Analytics'), + icon: 'analytics-rounded', + component: , + disabled: !runningEE || requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : requiresEnterpriseTooltip + }, + ], + }); + + // Policies & Privacy + sections.push({ + title: t('settings.policiesPrivacy.title', 'Policies & Privacy'), + items: [ + { + key: 'adminLegal', + label: t('settings.policiesPrivacy.legal', 'Legal'), + icon: 'gavel-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + { + key: 'adminPrivacy', + label: t('settings.policiesPrivacy.privacy', 'Privacy'), + icon: 'visibility-rounded', + component: , + disabled: requiresLogin, + disabledTooltip: requiresLogin ? enableLoginTooltip : undefined + }, + ], + }); + } + + // Add Developer section if login is enabled + if (loginEnabled) { + const developerSection: ConfigNavSection = { + title: t('settings.developer.title', 'Developer'), + items: [ + { + key: 'api-keys', + label: t('settings.developer.apiKeys', 'API Keys'), + icon: 'key-rounded', + component: + }, + ], + }; + + // Add Developer section after Preferences (or Workspace if it exists) + const insertIndex = isAdmin ? 2 : 1; + sections.splice(insertIndex, 0, developerSection); + } + + return sections; +}; + +/** + * Deprecated: Use useConfigNavSections hook instead * Proprietary extension of createConfigNavSections that adds all admin and workspace sections */ export const createConfigNavSections = ( @@ -24,6 +215,8 @@ export const createConfigNavSections = ( runningEE: boolean = false, loginEnabled: boolean = false ): ConfigNavSection[] => { + console.warn('createConfigNavSections is deprecated. Use useConfigNavSections hook instead for proper i18n support.'); + // Get the core sections (just Preferences) const sections = createCoreConfigNavSections(isAdmin, runningEE, loginEnabled); diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx index 14eda5f9e..0d71d4cac 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx @@ -336,7 +336,7 @@ export default function AdminGeneralSection() {
Classic logo {t('admin.settings.general.logoStyle.classic', 'Classic')} @@ -349,7 +349,7 @@ export default function AdminGeneralSection() {
Modern logo {t('admin.settings.general.logoStyle.modern', 'Modern')} @@ -385,7 +385,7 @@ export default function AdminGeneralSection() { ]} searchable clearable - placeholder="Select languages" + placeholder={t('admin.settings.general.languages.placeholder', 'Select languages')} comboboxProps={{ zIndex: 1400 }} disabled={!loginEnabled} /> diff --git a/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx index bab77723e..8a61e7be5 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/TeamDetailsSection.tsx @@ -72,7 +72,7 @@ export default function TeamDetailsSection({ teamId, onBack }: TeamDetailsSectio }); } catch (error) { console.error('Failed to fetch team details:', error); - alert({ alertType: 'error', title: 'Failed to load team details' }); + alert({ alertType: 'error', title: t('workspace.teams.loadError', 'Failed to load team details') }); onBack(); } finally { setLoading(false);