Ux language (#378)

* ux: language from menu

* feat: add extra support for languages

german
portuguese
spanish

* refactor: type improvements
This commit is contained in:
Carlos Valente
2023-05-12 23:16:20 +02:00
committed by GitHub
parent 305d6b6476
commit ca65d31071
7 changed files with 66 additions and 33 deletions
+1 -13
View File
@@ -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(() => {
@@ -106,6 +106,9 @@ export default function AppSettingsModal() {
<option value='en'>English</option>
<option value='de'>German</option>
<option value='no'>Norwegian</option>
<option value='pt'>Portuguese</option>
<option value='es'>Spanish</option>
<option value='sv'>Swedish</option>
</Select>
</ModalSplitInput>
<OntimeModalFooter
@@ -1,3 +1,4 @@
/* eslint-disable react/display-name */
import { ComponentType, useMemo } from 'react';
import { TitleBlock } from 'ontime-types';
import { useStore } from 'zustand';
@@ -11,8 +12,7 @@ import { useViewOptionsStore } from '../../common/stores/viewOptions';
export type TitleManager = TitleBlock & { showNow: boolean; showNext: boolean };
const withData = <P extends object>(Component: ComponentType<P>) => {
// eslint-disable-next-line react/display-name -- its ok
return (props: P) => {
return (props: Partial<P>) => {
// persisted app state
const isMirrored = useViewOptionsStore((state) => state.mirror);
@@ -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 <TranslationContext.Provider value={contextValue}>{children}</TranslationContext.Provider>;
};
export const useTranslation = () => {
const { getLocalizedString, setLanguage } = useContext(TranslationContext);
return { getLocalizedString, setLanguage };
const { getLocalizedString } = useContext(TranslationContext);
return { getLocalizedString };
};
@@ -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',
};
@@ -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',
};
@@ -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',
};