From ca65d310710addcdc7ae9d270c42d6be1d786f36 Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Fri, 12 May 2023 23:16:20 +0200 Subject: [PATCH] Ux language (#378) * ux: language from menu * feat: add extra support for languages german portuguese spanish * refactor: type improvements --- apps/client/src/AppRouter.tsx | 14 +-------- .../modals/settings-modal/AppSettings.tsx | 3 ++ .../src/features/viewers/ViewWrapper.tsx | 4 +-- .../src/translation/TranslationProvider.jsx | 29 +++++++------------ apps/client/src/translation/languages/de.ts | 13 +++++++++ apps/client/src/translation/languages/es.ts | 18 ++++++++++++ apps/client/src/translation/languages/pt.ts | 18 ++++++++++++ 7 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 apps/client/src/translation/languages/es.ts create mode 100644 apps/client/src/translation/languages/pt.ts diff --git a/apps/client/src/AppRouter.tsx b/apps/client/src/AppRouter.tsx index 7c2d88658..86194e63c 100644 --- a/apps/client/src/AppRouter.tsx +++ b/apps/client/src/AppRouter.tsx @@ -1,9 +1,8 @@ import { lazy, useEffect } from 'react'; -import { Navigate, Route, Routes, useLocation, useNavigate, useSearchParams } from 'react-router-dom'; +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import useAliases from './common/hooks-query/useAliases'; import withData from './features/viewers/ViewWrapper'; -import { useTranslation } from './translation/TranslationProvider'; const Editor = lazy(() => import('./features/editors/ProtectedEditor')); const Table = lazy(() => import('./features/table/ProtectedTable')); @@ -37,17 +36,6 @@ export default function AppRouter() { const { data } = useAliases(); const location = useLocation(); const navigate = useNavigate(); - const [searchParams] = useSearchParams(); - const { setLanguage } = useTranslation(); - - // Set output language - useEffect(() => { - const langParam = searchParams.get('lang'); - if (langParam && langParam.length === 2) { - setLanguage(searchParams.get('lang')); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [searchParams]); // navigate if is alias route useEffect(() => { diff --git a/apps/client/src/features/modals/settings-modal/AppSettings.tsx b/apps/client/src/features/modals/settings-modal/AppSettings.tsx index 1860eb816..85d94a7d8 100644 --- a/apps/client/src/features/modals/settings-modal/AppSettings.tsx +++ b/apps/client/src/features/modals/settings-modal/AppSettings.tsx @@ -106,6 +106,9 @@ export default function AppSettingsModal() { + + + (Component: ComponentType

) => { - // eslint-disable-next-line react/display-name -- its ok - return (props: P) => { + return (props: Partial

) => { // persisted app state const isMirrored = useViewOptionsStore((state) => state.mirror); diff --git a/apps/client/src/translation/TranslationProvider.jsx b/apps/client/src/translation/TranslationProvider.jsx index fe8c9308a..09d235fee 100644 --- a/apps/client/src/translation/TranslationProvider.jsx +++ b/apps/client/src/translation/TranslationProvider.jsx @@ -1,54 +1,47 @@ -import React, { createContext, useCallback, useContext, useState } from 'react'; +import React, { createContext, useCallback, useContext } from 'react'; +import useSettings from '@/common/hooks-query/useSettings'; import { langDe } from '@/translation/languages/de'; import { langEn } from '@/translation/languages/en'; +import { langEs } from '@/translation/languages/es'; import { langNo } from '@/translation/languages/no'; +import { langPt } from '@/translation/languages/pt'; import { langSv } from '@/translation/languages/sv'; const translationsList = { en: langEn, + es: langEs, de: langDe, no: langNo, + pt: langPt, sv: langSv, }; -const ALLOWED_LANGUAGES = Object.keys(translationsList); const DEFAULT_LANGUAGE = 'en'; export const TranslationContext = createContext(undefined); export const TranslationProvider = ({ children }) => { - const [language, setLanguageState] = useState('en'); + const { data } = useSettings(); const getLocalizedString = useCallback( - (key, lang = language) => { + (key, lang = data.language) => { if (key in translationsList[lang]) { return translationsList[lang][key]; } else if (lang !== DEFAULT_LANGUAGE) { return getLocalizedString(key, 'en'); } }, - [language], + [data.language], ); - const setLanguage = useCallback((language) => { - language = language.toLowerCase(); - if (ALLOWED_LANGUAGES.includes(language)) { - setLanguageState(language); - console.info(`Language set to ${language}`); - } else { - console.warn(`Language code ${language} does not exist.`); - } - }, []); - const contextValue = { getLocalizedString, - setLanguage, }; return {children}; }; export const useTranslation = () => { - const { getLocalizedString, setLanguage } = useContext(TranslationContext); - return { getLocalizedString, setLanguage }; + const { getLocalizedString } = useContext(TranslationContext); + return { getLocalizedString }; }; diff --git a/apps/client/src/translation/languages/de.ts b/apps/client/src/translation/languages/de.ts index b78156f56..65a1c3fee 100644 --- a/apps/client/src/translation/languages/de.ts +++ b/apps/client/src/translation/languages/de.ts @@ -1,5 +1,18 @@ import { TranslationObject } from '../Translation.types'; export const langDe: TranslationObject = { + 'common.end_time': 'Endzeit', + 'common.expected_finish': 'Voraussichtliches Ende', + 'common.now': 'Jetzt', + 'common.next': 'Nächste', + 'common.public_message': 'Öffentliche Nachricht', + 'common.start_time': 'Startzeit', + 'common.stage_timer': 'Bühnen-Timer', + 'common.started_at': 'Gestartet am', 'common.time_now': 'Aktuelle Zeit', + 'countdown.ended': 'Veranstaltung endete um', + 'countdown.running': 'Veranstaltung läuft', + 'countdown.select_event': 'Wählen Sie eine Veranstaltung aus, um sie zu verfolgen', + 'countdown.to_start': 'Zeit bis zum Start', + 'countdown.waiting': 'Warten auf den Veranstaltungsbeginn', }; diff --git a/apps/client/src/translation/languages/es.ts b/apps/client/src/translation/languages/es.ts new file mode 100644 index 000000000..3216855e8 --- /dev/null +++ b/apps/client/src/translation/languages/es.ts @@ -0,0 +1,18 @@ +import { TranslationObject } from '../Translation.types'; + +export const langEs: TranslationObject = { + 'common.end_time': 'Hora de finalización', + 'common.expected_finish': 'Finalización esperada', + 'common.now': 'Ahora', + 'common.next': 'Siguiente', + 'common.public_message': 'Mensaje público', + 'common.start_time': 'Hora de inicio', + 'common.stage_timer': 'Temporizador de presentador', + 'common.started_at': 'Iniciado en', + 'common.time_now': 'Hora actual', + 'countdown.ended': 'Evento finalizado a las', + 'countdown.running': 'Evento en curso', + 'countdown.select_event': 'Seleccionar un evento para seguir', + 'countdown.to_start': 'Tiempo para comenzar', + 'countdown.waiting': 'Esperando el inicio del evento', +}; diff --git a/apps/client/src/translation/languages/pt.ts b/apps/client/src/translation/languages/pt.ts new file mode 100644 index 000000000..aceeb2963 --- /dev/null +++ b/apps/client/src/translation/languages/pt.ts @@ -0,0 +1,18 @@ +import { TranslationObject } from '../Translation.types'; + +export const langPt: TranslationObject = { + 'common.end_time': 'Hora de término', + 'common.expected_finish': 'Término esperado', + 'common.now': 'Agora', + 'common.next': 'Próximo', + 'common.public_message': 'Mensagem pública', + 'common.start_time': 'Hora de início', + 'common.stage_timer': 'Temporizador do presentador', + 'common.started_at': 'Iniciado em', + 'common.time_now': 'Hora atual', + 'countdown.ended': 'Evento encerrado às', + 'countdown.running': 'Evento em andamento', + 'countdown.select_event': 'Selecione um evento para acompanhar', + 'countdown.to_start': 'Tempo para iniciar', + 'countdown.waiting': 'Aguardando o início do evento', +};