diff --git a/interface/src/components/layout/LayoutAuthMenu.tsx b/interface/src/components/layout/LayoutAuthMenu.tsx index d34729faa..c078ae72b 100644 --- a/interface/src/components/layout/LayoutAuthMenu.tsx +++ b/interface/src/components/layout/LayoutAuthMenu.tsx @@ -95,7 +95,9 @@ const LayoutAuthMenu: FC = () => { {me.username} - {me.admin ? 'Admin User' : 'Guest User'} + + {me.admin ? LL.ADMIN() + ' ' + LL.USER() : LL.GUEST() + ' ' + LL.USER()} + diff --git a/interface/src/components/layout/LayoutMenu.tsx b/interface/src/components/layout/LayoutMenu.tsx index 4989be1c2..cff62bbf6 100644 --- a/interface/src/components/layout/LayoutMenu.tsx +++ b/interface/src/components/layout/LayoutMenu.tsx @@ -31,7 +31,7 @@ const LayoutMenu: FC = () => { )} - + {features.ntp && } {features.mqtt && } diff --git a/interface/src/components/loading/FormLoader.tsx b/interface/src/components/loading/FormLoader.tsx index 8b1baab7b..390b309b6 100644 --- a/interface/src/components/loading/FormLoader.tsx +++ b/interface/src/components/loading/FormLoader.tsx @@ -5,6 +5,8 @@ import RefreshIcon from '@mui/icons-material/Refresh'; import { MessageBox } from '..'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface FormLoaderProps { message?: string; errorMessage?: string; @@ -12,12 +14,14 @@ interface FormLoaderProps { } const FormLoader: FC = ({ errorMessage, onRetry, message = 'Loading…' }) => { + const { LL } = useI18nContext(); + if (errorMessage) { return ( {onRetry && ( )} diff --git a/interface/src/components/loading/LoadingSpinner.tsx b/interface/src/components/loading/LoadingSpinner.tsx index eaeccf0ad..5baf6ecf8 100644 --- a/interface/src/components/loading/LoadingSpinner.tsx +++ b/interface/src/components/loading/LoadingSpinner.tsx @@ -2,23 +2,29 @@ import { FC } from 'react'; import { CircularProgress, Box, Typography, Theme } from '@mui/material'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface LoadingSpinnerProps { height?: number | string; } -const LoadingSpinner: FC = ({ height = '100%' }) => ( - - ({ - margin: theme.spacing(4), - color: theme.palette.text.secondary - })} - size={100} - /> - - Loading… - - -); +const LoadingSpinner: FC = ({ height = '100%' }) => { + const { LL } = useI18nContext(); + + return ( + + ({ + margin: theme.spacing(4), + color: theme.palette.text.secondary + })} + size={100} + /> + + {LL.LOADING()}… + + + ); +}; export default LoadingSpinner; diff --git a/interface/src/framework/network/NetworkConnection.tsx b/interface/src/framework/network/NetworkConnection.tsx index b069eb45f..90ecda203 100644 --- a/interface/src/framework/network/NetworkConnection.tsx +++ b/interface/src/framework/network/NetworkConnection.tsx @@ -15,7 +15,7 @@ import { useI18nContext } from '../../i18n/i18n-react'; const NetworkConnection: FC = () => { const { LL } = useI18nContext(); - useLayoutTitle(LL.NETWORK_CONNECTION()); + useLayoutTitle(LL.NETWORK()); const { routerTab } = useRouterTab(); @@ -45,9 +45,9 @@ const NetworkConnection: FC = () => { }} > - - - + + + } /> diff --git a/interface/src/framework/network/NetworkSettingsForm.tsx b/interface/src/framework/network/NetworkSettingsForm.tsx index 3c67d4b1c..2fb1e4294 100644 --- a/interface/src/framework/network/NetworkSettingsForm.tsx +++ b/interface/src/framework/network/NetworkSettingsForm.tsx @@ -37,7 +37,11 @@ import { ValidateFieldsError } from 'async-validator'; import { validate } from '../../validators'; import { createNetworkSettingsValidator } from '../../validators/network'; +import { useI18nContext } from '../../i18n/i18n-react'; + const WiFiSettingsForm: FC = () => { + const { LL } = useI18nContext(); + const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext); const [initialized, setInitialized] = useState(false); @@ -112,7 +116,7 @@ const WiFiSettingsForm: FC = () => { { { dBm }} @@ -150,21 +154,21 @@ const WiFiSettingsForm: FC = () => { } - label="Disable WiFi Sleep Mode" + label={LL.NETWORK_DISABLE_SLEEP()} /> } - label="Use Lower WiFi Bandwidth" + label={LL.NETWORK_LOW_BAND()} /> } - label="Enable mDNS Service" + label={LL.NETWORK_USE_DNS()} /> - General + {LL.GENERAL_OPTIONS()} { } - label="Enable IPv6 support" + label={LL.NETWORK_ENABLE_IPV6()} /> } - label="Use Fixed IP address" + label={LL.NETWORK_FIXED_IP()} /> {data.static_ip_config && ( <> @@ -250,7 +254,7 @@ const WiFiSettingsForm: FC = () => { type="submit" onClick={validateAndSubmit} > - Save + {LL.SAVE()} @@ -258,7 +262,7 @@ const WiFiSettingsForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/network/NetworkStatusForm.tsx b/interface/src/framework/network/NetworkStatusForm.tsx index 986b60d14..eb99aa45b 100644 --- a/interface/src/framework/network/NetworkStatusForm.tsx +++ b/interface/src/framework/network/NetworkStatusForm.tsx @@ -14,6 +14,8 @@ import { NetworkConnectionStatus, NetworkStatus } from '../../types'; import * as NetworkApi from '../../api/network'; import { useRest } from '../../utils'; +import { useI18nContext } from '../../i18n/i18n-react'; + const isConnected = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED || status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED; @@ -35,29 +37,6 @@ const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => { } }; -const networkStatus = ({ status }: NetworkStatus) => { - switch (status) { - case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: - return 'Inactive'; - case NetworkConnectionStatus.WIFI_STATUS_IDLE: - return 'Idle'; - case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: - return 'No SSID Available'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: - return 'Connected (WiFi)'; - case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: - return 'Connected (Ethernet)'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: - return 'Connection Failed'; - case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: - return 'Connection Lost'; - case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: - return 'Disconnected'; - default: - return 'Unknown'; - } -}; - export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED; export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED; @@ -81,8 +60,33 @@ const IPs = (status: NetworkStatus) => { const NetworkStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: NetworkApi.readNetworkStatus }); + const { LL } = useI18nContext(); + const theme = useTheme(); + const networkStatus = ({ status }: NetworkStatus) => { + switch (status) { + case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: + return LL.INACTIVE(); + case NetworkConnectionStatus.WIFI_STATUS_IDLE: + return LL.IDLE(); + case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: + return 'No SSID Available'; + case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: + return LL.CONNECTED() + ' (WiFi)'; + case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: + return LL.CONNECTED() + ' (Ethernet)'; + case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: + return LL.CONNECTED() + ' ' + LL.FAILED(); + case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: + return LL.CONNECTED() + ' ' + LL.LOST(); + case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: + return LL.DISCONNECTED(); + default: + return LL.UNKNOWN(); + } + }; + const content = () => { if (!data) { return ; @@ -162,7 +166,7 @@ const NetworkStatusForm: FC = () => { @@ -170,7 +174,7 @@ const NetworkStatusForm: FC = () => { }; return ( - + {content()} ); diff --git a/interface/src/framework/network/WiFiNetworkScanner.tsx b/interface/src/framework/network/WiFiNetworkScanner.tsx index 169bc6951..328888a94 100644 --- a/interface/src/framework/network/WiFiNetworkScanner.tsx +++ b/interface/src/framework/network/WiFiNetworkScanner.tsx @@ -12,6 +12,8 @@ import { ButtonRow, FormLoader, SectionContent } from '../../components'; import WiFiNetworkSelector from './WiFiNetworkSelector'; +import { useI18nContext } from '../../i18n/i18n-react'; + const NUM_POLLS = 10; const POLLING_FREQUENCY = 500; @@ -22,6 +24,8 @@ const compareNetworks = (network1: WiFiNetwork, network2: WiFiNetwork) => { }; const WiFiNetworkScanner: FC = () => { + const { LL } = useI18nContext(); + const { enqueueSnackbar } = useSnackbar(); const pollCount = useRef(0); @@ -46,7 +50,7 @@ const WiFiNetworkScanner: FC = () => { pollCount.current = completedPollCount; setTimeout(pollNetworkList, POLLING_FREQUENCY); } else { - finishedWithError('Device did not return network list in timely manner'); + finishedWithError(LL.PROBLEM_LOADING()); } } else { const newNetworkList = response.data; @@ -55,12 +59,12 @@ const WiFiNetworkScanner: FC = () => { } } catch (error: unknown) { if (error instanceof AxiosError) { - finishedWithError('Problem listing WiFi networks ' + error.response?.data.message); + finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); } else { - finishedWithError('Problem listing WiFi networks'); + finishedWithError(LL.PROBLEM_LOADING()); } } - }, [finishedWithError]); + }, [finishedWithError, LL]); const startNetworkScan = useCallback(async () => { pollCount.current = 0; @@ -71,12 +75,12 @@ const WiFiNetworkScanner: FC = () => { setTimeout(pollNetworkList, POLLING_FREQUENCY); } catch (error: unknown) { if (error instanceof AxiosError) { - finishedWithError('Problem scanning for WiFi networks ' + error.response?.data.message); + finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message); } else { - finishedWithError('Problem scanning for WiFi networks'); + finishedWithError(LL.PROBLEM_LOADING()); } } - }, [finishedWithError, pollNetworkList]); + }, [finishedWithError, pollNetworkList, LL]); useEffect(() => { startNetworkScan(); @@ -84,13 +88,13 @@ const WiFiNetworkScanner: FC = () => { const renderNetworkScanner = () => { if (!networkList) { - return ; + return ; } return ; }; return ( - + {renderNetworkScanner()} diff --git a/interface/src/framework/network/WiFiNetworkSelector.tsx b/interface/src/framework/network/WiFiNetworkSelector.tsx index 960289ef6..b86f00efe 100644 --- a/interface/src/framework/network/WiFiNetworkSelector.tsx +++ b/interface/src/framework/network/WiFiNetworkSelector.tsx @@ -12,6 +12,8 @@ import { WiFiEncryptionType, WiFiNetwork, WiFiNetworkList } from '../../types'; import { WiFiConnectionContext } from './WiFiConnectionContext'; +import { useI18nContext } from '../../i18n/i18n-react'; + interface WiFiNetworkSelectorProps { networkList: WiFiNetworkList; } @@ -39,6 +41,8 @@ export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => { }; const WiFiNetworkSelector: FC = ({ networkList }) => { + const { LL } = useI18nContext(); + const wifiConnectionContext = useContext(WiFiConnectionContext); const renderNetwork = (network: WiFiNetwork) => { @@ -61,7 +65,7 @@ const WiFiNetworkSelector: FC = ({ networkList }) => { }; if (networkList.networks.length === 0) { - return ; + return ; } return {networkList.networks.map(renderNetwork)}; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 6666fabd2..634f8dc0a 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -2,6 +2,8 @@ import type { Translation } from '../i18n-types'; const de: Translation = { LANGUAGE: 'Sprache', + RETRY: 'DE_Retry', + LOADING: 'DE_Loading', IS_REQUIRED: 'ist nötig', SIGN_IN: 'Einloggen', SIGN_OUT: 'Ausloggen', @@ -16,7 +18,7 @@ const de: Translation = { UPLOAD_SUCCESSFUL: 'Hochladen erfolgreich', DOWNLOAD_SUCCESSFUL: 'DE_Download successful', INVALID_LOGIN: 'Ungültige Login Daten', - NETWORK_CONNECTION: 'Netzwerkverbindung', + NETWORK: 'Netzwerk', SECURITY: 'Sicherheit', ONOFF_CAP: 'AN/AUS', ONOFF: 'an/aus', @@ -51,7 +53,6 @@ const de: Translation = { CONNECTED: 'in Verbindung gebracht', TX_ISSUES: 'Tx-Probleme - versuchen Sie einen anderen Tx-Modus', DISCONNECTED: 'Getrennt', - SCANNING: 'Suche nach Geräten...', EMS_SCAN: 'Möchten Sie wirklich einen vollständigen Gerätescan des EMS-Busses starten?', EMS_BUS_STATUS: 'EMS Bus Status', ACTIVE_DEVICES: 'Aktive Geräte und Sensoren', @@ -222,8 +223,23 @@ const de: Translation = { AP_PROVIDE_TEXT_2: 'DE_when WiFi is disconnected', AP_PROVIDE_TEXT_3: 'DE_never', AP_PREFERRED_CHANNEL: 'DE_Preferred Channel', - AP_HIDE_SSID: 'DE_Hide SSID' - + AP_HIDE_SSID: 'DE_Hide SSID', + NETWORK_SCAN: 'DE_Scan WiFi Networks', + IDLE: 'DE_Idle', + LOST: 'DE_Lost', + SCANNING: 'DE_Scanning', + SCAN_AGAIN: 'DE_Scan again', + NETWORK_SCANNER: 'DE_Network Scanner', + NETWORK_NO_WIFI: 'DE_No WiFi networks found', + NETWORK_BLANK_SSID: 'DE_leave blank to disable WiFi', + POWER: 'DE_Power', + NETWORK_DISABLE_SLEEP: 'DE_Disable WiFi Sleep Mode', + NETWORK_LOW_BAND: 'DE_Use Lower WiFi Bandwidth', + NETWORK_USE_DNS: 'DE_Enable mDNS Service', + NETWORK_ENABLE_IPV6: 'DE_Enable IPv6 support', + NETWORK_FIXED_IP: 'DE_Use Fixed IP address', + ADMIN: 'DE_Admin', + GUEST: 'DE_Guest' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 691e7e1d1..31738e81b 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -2,6 +2,8 @@ import type { BaseTranslation } from '../i18n-types'; const en: BaseTranslation = { LANGUAGE: 'Language', + RETRY: 'Retry', + LOADING: 'Loading', IS_REQUIRED: 'is required', SIGN_IN: 'Sign In', SIGN_OUT: 'Sign Out', @@ -16,7 +18,7 @@ const en: BaseTranslation = { UPLOAD_SUCCESSFUL: 'Upload successful', DOWNLOAD_SUCCESSFUL: 'Download successful', INVALID_LOGIN: 'Invalid login details', - NETWORK_CONNECTION: 'Network Connection', + NETWORK: 'Network', SECURITY: 'Security', ONOFF_CAP: 'ON/OFF', ONOFF: 'on/off', @@ -51,7 +53,6 @@ const en: BaseTranslation = { CONNECTED: 'Connected', TX_ISSUES: 'Tx issues - try a different Tx Mode', DISCONNECTED: 'Disconnected', - SCANNING: 'Scanning for devices...', EMS_SCAN: 'Are you sure you want to initiate a full device scan of the EMS bus?', EMS_BUS_STATUS: 'EMS Bus Status', ACTIVE_DEVICES: 'Active Devices & Sensors', @@ -222,7 +223,23 @@ const en: BaseTranslation = { AP_PROVIDE_TEXT_2: 'when WiFi is disconnected', AP_PROVIDE_TEXT_3: 'never', AP_PREFERRED_CHANNEL: 'Preferred Channel', - AP_HIDE_SSID: 'Hide SSID' + AP_HIDE_SSID: 'Hide SSID', + NETWORK_SCAN: 'Scan WiFi Networks', + IDLE: 'Idle', + LOST: 'Lost', + SCANNING: 'Scanning', + SCAN_AGAIN: 'Scan again', + NETWORK_SCANNER: 'Network Scanner', + NETWORK_NO_WIFI: 'No WiFi networks found', + NETWORK_BLANK_SSID: 'leave blank to disable WiFi', + POWER: 'Power', + NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', + NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth', + NETWORK_USE_DNS: 'Enable mDNS Service', + NETWORK_ENABLE_IPV6: 'Enable IPv6 support', + NETWORK_FIXED_IP: 'Use Fixed IP address', + ADMIN: 'Admin', + GUEST: 'Guest' }; export default en; diff --git a/interface/src/i18n/i18n-types.ts b/interface/src/i18n/i18n-types.ts index 4ff5be147..fba35cbc9 100644 --- a/interface/src/i18n/i18n-types.ts +++ b/interface/src/i18n/i18n-types.ts @@ -18,6 +18,14 @@ type RootTranslation = { * Language */ LANGUAGE: string + /** + * Retry + */ + RETRY: string + /** + * Loading + */ + LOADING: string /** * is required */ @@ -76,9 +84,9 @@ type RootTranslation = { */ INVALID_LOGIN: string /** - * Network Connection + * Network */ - NETWORK_CONNECTION: string + NETWORK: string /** * Security */ @@ -214,10 +222,6 @@ type RootTranslation = { * Disconnected */ DISCONNECTED: string - /** - * Scanning for devices... - */ - SCANNING: string /** * Are you sure you want to initiate a full device scan of the EMS bus? */ @@ -883,6 +887,70 @@ type RootTranslation = { * Hide SSID */ AP_HIDE_SSID: string + /** + * Scan WiFi Networks + */ + NETWORK_SCAN: string + /** + * Idle + */ + IDLE: string + /** + * Lost + */ + LOST: string + /** + * Scanning + */ + SCANNING: string + /** + * Scan again + */ + SCAN_AGAIN: string + /** + * Network Scanner + */ + NETWORK_SCANNER: string + /** + * No WiFi networks found + */ + NETWORK_NO_WIFI: string + /** + * leave blank to disable WiFi + */ + NETWORK_BLANK_SSID: string + /** + * Power + */ + POWER: string + /** + * Disable WiFi Sleep Mode + */ + NETWORK_DISABLE_SLEEP: string + /** + * Use Lower WiFi Bandwidth + */ + NETWORK_LOW_BAND: string + /** + * Enable mDNS Service + */ + NETWORK_USE_DNS: string + /** + * Enable IPv6 support + */ + NETWORK_ENABLE_IPV6: string + /** + * Use Fixed IP address + */ + NETWORK_FIXED_IP: string + /** + * Admin + */ + ADMIN: string + /** + * Guest + */ + GUEST: string } export type TranslationFunctions = { @@ -890,6 +958,14 @@ export type TranslationFunctions = { * Language */ LANGUAGE: () => LocalizedString + /** + * Retry + */ + RETRY: () => LocalizedString + /** + * Loading + */ + LOADING: () => LocalizedString /** * is required */ @@ -947,9 +1023,9 @@ export type TranslationFunctions = { */ INVALID_LOGIN: () => LocalizedString /** - * Network Connection + * Network */ - NETWORK_CONNECTION: () => LocalizedString + NETWORK: () => LocalizedString /** * Security */ @@ -1082,10 +1158,6 @@ export type TranslationFunctions = { * Disconnected */ DISCONNECTED: () => LocalizedString - /** - * Scanning for devices... - */ - SCANNING: () => LocalizedString /** * Are you sure you want to initiate a full device scan of the EMS bus? */ @@ -1744,6 +1816,70 @@ export type TranslationFunctions = { * Hide SSID */ AP_HIDE_SSID: () => LocalizedString + /** + * Scan WiFi Networks + */ + NETWORK_SCAN: () => LocalizedString + /** + * Idle + */ + IDLE: () => LocalizedString + /** + * Lost + */ + LOST: () => LocalizedString + /** + * Scanning + */ + SCANNING: () => LocalizedString + /** + * Scan again + */ + SCAN_AGAIN: () => LocalizedString + /** + * Network Scanner + */ + NETWORK_SCANNER: () => LocalizedString + /** + * No WiFi networks found + */ + NETWORK_NO_WIFI: () => LocalizedString + /** + * leave blank to disable WiFi + */ + NETWORK_BLANK_SSID: () => LocalizedString + /** + * Power + */ + POWER: () => LocalizedString + /** + * Disable WiFi Sleep Mode + */ + NETWORK_DISABLE_SLEEP: () => LocalizedString + /** + * Use Lower WiFi Bandwidth + */ + NETWORK_LOW_BAND: () => LocalizedString + /** + * Enable mDNS Service + */ + NETWORK_USE_DNS: () => LocalizedString + /** + * Enable IPv6 support + */ + NETWORK_ENABLE_IPV6: () => LocalizedString + /** + * Use Fixed IP address + */ + NETWORK_FIXED_IP: () => LocalizedString + /** + * Admin + */ + ADMIN: () => LocalizedString + /** + * Guest + */ + GUEST: () => LocalizedString } export type Formatters = {} diff --git a/interface/src/project/DashboardStatus.tsx b/interface/src/project/DashboardStatus.tsx index 04a9e5f69..a4e787ab7 100644 --- a/interface/src/project/DashboardStatus.tsx +++ b/interface/src/project/DashboardStatus.tsx @@ -147,7 +147,7 @@ const DashboardStatus: FC = () => { const scan = async () => { try { await EMSESP.scanDevices(); - enqueueSnackbar(LL.SCANNING(), { variant: 'info' }); + enqueueSnackbar(LL.SCANNING() + '...', { variant: 'info' }); } catch (error: unknown) { enqueueSnackbar(extractErrorMessage(error, LL.PROBLEM_UPDATING()), { variant: 'error' }); } finally {