From 64beb4d0762894d8ceb1dff26c2291dbd68249b5 Mon Sep 17 00:00:00 2001 From: James Brunton Date: Mon, 22 Sep 2025 11:50:49 +0100 Subject: [PATCH] Disable language selection for everything other than English GB (#4467) # Description of Changes For the first release of V2, we'll not have any reasonable translations for anything other than English GB, so with that in mind, this PR disables language selection for anything other than English GB, with a tooltip saying the other languages are coming soon. I also split the JSX up a little bit while I was at it to make it easier to manage. --------- Co-authored-by: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com> --- .../public/locales/en-GB/translation.json | 1 + .../components/shared/LanguageSelector.tsx | 356 +++++++++++------- 2 files changed, 217 insertions(+), 140 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 7cf93a10e..0049825cb 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -104,6 +104,7 @@ "green": "Green", "blue": "Blue", "custom": "Custom...", + "comingSoon": "Coming soon", "WorkInProgess": "Work in progress, May not work or be buggy, Please report any problems!", "poweredBy": "Powered by", "yes": "Yes", diff --git a/frontend/src/components/shared/LanguageSelector.tsx b/frontend/src/components/shared/LanguageSelector.tsx index f2fddf212..3cf8b3b11 100644 --- a/frontend/src/components/shared/LanguageSelector.tsx +++ b/frontend/src/components/shared/LanguageSelector.tsx @@ -1,24 +1,161 @@ import React, { useState, useEffect } from 'react'; -import { Menu, Button, ScrollArea, ActionIcon } from '@mantine/core'; +import { Menu, Button, ScrollArea, ActionIcon, Tooltip } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { supportedLanguages } from '../../i18n'; import LocalIcon from './LocalIcon'; import styles from './LanguageSelector.module.css'; +// Types interface LanguageSelectorProps { position?: React.ComponentProps['position']; offset?: number; compact?: boolean; // icon-only trigger } -const LanguageSelector = ({ position = 'bottom-start', offset = 8, compact = false }: LanguageSelectorProps) => { +interface LanguageOption { + value: string; + label: string; +} + +interface RippleEffect { + x: number; + y: number; + key: number; +} + +// Sub-components +interface LanguageItemProps { + option: LanguageOption; + index: number; + animationTriggered: boolean; + isSelected: boolean; + onClick: (event: React.MouseEvent) => void; + rippleEffect?: RippleEffect | null; + pendingLanguage: string | null; + compact: boolean; + disabled?: boolean; +} + +const LanguageItem: React.FC = ({ + option, + index, + animationTriggered, + isSelected, + onClick, + rippleEffect, + pendingLanguage, + compact, + disabled = false +}) => { + const { t } = useTranslation(); + + const label = disabled ? ( + +

{option.label}

+
+ ) : ( +

{option.label}

+ ); + + return ( +
+ +
+ ); +}; + +const RippleStyles: React.FC = () => ( + +); + +// Main component +const LanguageSelector: React.FC = ({ position = 'bottom-start', offset = 8, compact = false }) => { const { i18n } = useTranslation(); const [opened, setOpened] = useState(false); const [animationTriggered, setAnimationTriggered] = useState(false); const [pendingLanguage, setPendingLanguage] = useState(null); - const [rippleEffect, setRippleEffect] = useState<{x: number, y: number, key: number} | null>(null); + const [rippleEffect, setRippleEffect] = useState(null); - const languageOptions = Object.entries(supportedLanguages) + const languageOptions: LanguageOption[] = Object.entries(supportedLanguages) .sort(([, nameA], [, nameB]) => nameA.localeCompare(nameB)) .map(([code, name]) => ({ value: code, @@ -65,15 +202,7 @@ const LanguageSelector = ({ position = 'bottom-start', offset = 8, compact = fal return ( <> - + - - {compact ? ( - + {compact ? ( + - - - ) : ( - - )} - + }} + > + + + ) : ( + + )} + - - -
- {languageOptions.map((option, index) => ( -
- -
- ))} -
-
-
+ + +
+ {languageOptions.map((option, index) => { + const isEnglishGB = option.value === 'en-GB'; // Currently only English GB has enough translations to use + const isDisabled = !isEnglishGB; + + return ( + handleLanguageChange(option.value, event)} + rippleEffect={rippleEffect} + pendingLanguage={pendingLanguage} + compact={compact} + disabled={isDisabled} + /> + ); + })} +
+
+
); }; export default LanguageSelector; +export type { LanguageSelectorProps, LanguageOption, RippleEffect };