diff --git a/client/src/app.tsx b/client/src/app.tsx index fe90556..d037446 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Outlet, useParams } from "react-router-dom"; +import { Outlet, useParams, useSearchParams } from "react-router-dom"; import { useEffect, useState } from 'react'; import '@fontsource/roboto/300.css'; @@ -11,13 +11,14 @@ import './css/reset.css'; import './css/app.css'; import { PageContext, PreferencesContext} from './components/infoview/context'; import UsePreferences from "./state/hooks/use_preferences" -import i18n from './i18n'; import { Navigation } from './components/navigation'; import { useSelector } from 'react-redux'; import { changeTypewriterMode, selectOpenedIntro, selectTypewriterMode } from './state/progress'; import { useAppDispatch } from './hooks'; import { Popup, PopupContext } from './components/popup/popup'; import { useGetGameInfoQuery } from './state/api'; +import lean4gameConfig from './config.json' +import { useTranslation } from 'react-i18next'; export const GameIdContext = React.createContext<{ gameId: string, @@ -25,6 +26,7 @@ export const GameIdContext = React.createContext<{ levelId: number|null}>({gameId: null, worldId: null, levelId: null}); function App() { + let { t, i18n } = useTranslation() const params = useParams() const gameId = (params.owner && params.repo) ? "g/" + params.owner + "/" + params.repo : null @@ -41,16 +43,39 @@ function App() { const [page, setPage] = useState(0) const [popupContent, setPopupContent] = useState(null) const gameInfo = useGetGameInfoQuery({game: gameId}) - + const [searchParams, setSearchParams] = useSearchParams() const openedIntro = useSelector(selectOpenedIntro(gameId)) + // mobile only: game intro should only be shown once and skipped afterwards useEffect(() => { if (openedIntro && !worldId && page == 0) { setPage(1) } }, [openedIntro]) + // option to pass language as `?lang=de` in the URL + useEffect(() => { + let urlLang = searchParams.get("lang") + let availableLangs = gameInfo.data?.tile?.languages + if (gameId) { + if (availableLangs?.includes(urlLang)) { + setLanguage(urlLang) + // Delete the search param as we processed it. + searchParams.delete('lang') + setSearchParams(searchParams) + } + } else { + if (urlLang in lean4gameConfig.newLanguages) { + setLanguage(urlLang) + // Delete the search param as we processed it. + searchParams.delete('lang') + setSearchParams(searchParams) + } + } + }, [gameId, gameInfo.data?.tile?.languages]) + + // set the correct language useEffect(() => { let availableLangs = gameInfo.data?.tile?.languages if (gameId && availableLangs?.length > 0 && !(availableLangs.includes(language))) { diff --git a/client/src/components/navigation.tsx b/client/src/components/navigation.tsx index 752d558..e7df5b3 100644 --- a/client/src/components/navigation.tsx +++ b/client/src/components/navigation.tsx @@ -214,7 +214,7 @@ function MobileNavigationLevel () { /** The skeleton of the navigation which is the same across all layouts. */ export function Navigation () { - const { t } = useTranslation() + const { t, i18n } = useTranslation() const { gameId, worldId } = useContext(GameIdContext) const { mobile, language, setLanguage } = useContext(PreferencesContext) const { setPopupContent } = useContext(PopupContext) @@ -249,7 +249,7 @@ export function Navigation () { {(!gameId || gameInfo.data?.tile?.languages.length > 1) && // Language button only visible if the game exists in `>1` languages } + iconElement={langNavOpen ? null : } icon={langNavOpen ? faXmark : null} title={langNavOpen ? t('close language menu') : t('open language menu')} onClick={toggleLangNav} diff --git a/doc/client.md b/doc/client.md new file mode 100644 index 0000000..bcf1e3d --- /dev/null +++ b/doc/client.md @@ -0,0 +1,9 @@ +# Client + +This document describes features of the frontent/client side. + + +## URL + +You can add `?lang=de` at the end of the URL to specify the language that should be set. This +will change the user's preferred language to the one specified.