From 5b990d861bfc86d0312556c611ecba41843343af Mon Sep 17 00:00:00 2001 From: yihao Date: Wed, 14 May 2025 22:32:22 +0800 Subject: [PATCH 1/2] added router params and button to read and change language in url --- src/pages/sicp/Sicp.tsx | 36 ++++++++++++++++++++++++++++++------ src/routes/routerConfig.tsx | 2 +- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/pages/sicp/Sicp.tsx b/src/pages/sicp/Sicp.tsx index 73798b81ca..407bbc8257 100644 --- a/src/pages/sicp/Sicp.tsx +++ b/src/pages/sicp/Sicp.tsx @@ -2,6 +2,7 @@ import 'katex/dist/katex.min.css'; import { Button, Classes, NonIdealState, Spinner } from '@blueprintjs/core'; import classNames from 'classnames'; +import path from 'path'; import React, { useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useLocation, useNavigate, useParams } from 'react-router'; @@ -40,7 +41,7 @@ const Sicp: React.FC = () => { const [data, setData] = useState(<>); const [loading, setLoading] = useState(false); const [active, setActive] = useState('0'); - const { section } = useParams<{ section: string }>(); + const { lang, section } = useParams<{ lang: string; section: string }>(); const parentRef = useRef(null); const refs = useRef>({}); const navigate = useNavigate(); @@ -95,7 +96,7 @@ const Sicp: React.FC = () => { * the main application navbar. Navigate replace logic is used to allow the * user to still use the browser back button to navigate the app. */ - navigate(`/sicpjs/${readSicpSectionLocalStorage()}`, { replace: true }); + navigate(path.join('sicpjs', readSicpSectionLocalStorage()), { replace: true }); return; } @@ -106,7 +107,7 @@ const Sicp: React.FC = () => { setLoading(true); - fetch(baseUrl + section + extension) + fetch(baseUrl + lang + '/' + section + extension) .then(response => { if (!response.ok) { throw Error(response.statusText); @@ -117,7 +118,7 @@ const Sicp: React.FC = () => { try { const newData = parseArr(myJson, refs); // Might throw error setData(newData); - setSicpSectionLocalStorage(section); // Sets local storage if valid page + setSicpSectionLocalStorage(path.join(lang || 'en', section)); // Sets local storage if valid page } catch (error) { throw new ParseJsonError(error.message); } @@ -139,7 +140,7 @@ const Sicp: React.FC = () => { .finally(() => { setLoading(false); }); - }, [section, navigate]); + }, [lang, section, navigate]); // Scroll to correct position React.useEffect(() => { @@ -164,10 +165,32 @@ const Sicp: React.FC = () => { dispatch(WorkspaceActions.resetWorkspace('sicp')); dispatch(WorkspaceActions.toggleUsingSubst(false, 'sicp')); }; + + const handleLanguageToggle = () => { + const newLang = lang === 'en' ? 'zh_CN' : 'en'; + navigate(`/sicpjs/${newLang}/${section}`); + }; + const handleNavigation = (sect: string) => { - navigate('/sicpjs/' + sect); + navigate('/sicpjs/' + `${lang}/` + sect); }; + // Language toggle button with fixed position + const languageToggle = ( +
+ +
+ ); + // `section` is defined due to the navigate logic in the useEffect above const navigationButtons = (
@@ -187,6 +210,7 @@ const Sicp: React.FC = () => { > + {languageToggle} {loading ? (
{loadingComponent}
) : section === 'index' ? ( diff --git a/src/routes/routerConfig.tsx b/src/routes/routerConfig.tsx index bcf5d326fe..689fc3a9c5 100644 --- a/src/routes/routerConfig.tsx +++ b/src/routes/routerConfig.tsx @@ -49,7 +49,7 @@ const Features = () => import('../pages/featureFlags/FeatureFlags'); const commonChildrenRoutes: RouteObject[] = [ { path: 'contributors', lazy: Contributors }, { path: 'callback/github', lazy: GitHubCallback }, - { path: 'sicpjs/:section?', lazy: Sicp }, + { path: 'sicpjs/:lang/:section?', lazy: Sicp }, { path: 'features', lazy: Features } ]; From f796bda836a3320c8d7caa2fe0b639669d1d1211 Mon Sep 17 00:00:00 2001 From: coder114514 <98397499+coder114514@users.noreply.github.com> Date: Tue, 20 May 2025 20:48:13 +0800 Subject: [PATCH 2/2] put textbook lang selection into local storage instead of the url now lang in url only changes the lang in local storage and redirects to the original page --- src/features/sicp/utils/SicpUtils.ts | 12 ++++++++++ src/pages/sicp/Sicp.tsx | 36 ++++++++++++++++++++++++---- src/routes/routerConfig.tsx | 3 ++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/features/sicp/utils/SicpUtils.ts b/src/features/sicp/utils/SicpUtils.ts index cc347256b1..acbdd56117 100644 --- a/src/features/sicp/utils/SicpUtils.ts +++ b/src/features/sicp/utils/SicpUtils.ts @@ -11,3 +11,15 @@ export const readSicpSectionLocalStorage = () => { const data = readLocalStorage(SICP_CACHE_KEY, SICP_INDEX); return data; }; + +export const SICP_DEF_TB_LANG = 'en'; +export const SICP_TB_LANG_KEY = 'sicp-textbook-lang'; + +export const setSicpLangLocalStorage = (value: string) => { + setLocalStorage(SICP_TB_LANG_KEY, value); +}; + +export const readSicpLangLocalStorage = () => { + const data = readLocalStorage(SICP_TB_LANG_KEY, SICP_DEF_TB_LANG); + return data; +}; diff --git a/src/pages/sicp/Sicp.tsx b/src/pages/sicp/Sicp.tsx index 407bbc8257..4e8ccd3f30 100644 --- a/src/pages/sicp/Sicp.tsx +++ b/src/pages/sicp/Sicp.tsx @@ -15,9 +15,12 @@ import { SicpSection } from 'src/features/sicp/chatCompletion/chatCompletion'; import { parseArr, ParseJsonError } from 'src/features/sicp/parser/ParseJson'; import { getNext, getPrev } from 'src/features/sicp/TableOfContentsHelper'; import { + readSicpLangLocalStorage, readSicpSectionLocalStorage, + setSicpLangLocalStorage, setSicpSectionLocalStorage, SICP_CACHE_KEY, + SICP_DEF_TB_LANG, SICP_INDEX } from 'src/features/sicp/utils/SicpUtils'; @@ -41,7 +44,8 @@ const Sicp: React.FC = () => { const [data, setData] = useState(<>); const [loading, setLoading] = useState(false); const [active, setActive] = useState('0'); - const { lang, section } = useParams<{ lang: string; section: string }>(); + const { param_lang, section } = useParams<{ param_lang:string, section: string }>(); + const [lang, setLang] = useState(readSicpLangLocalStorage()); const parentRef = useRef(null); const refs = useRef>({}); const navigate = useNavigate(); @@ -90,6 +94,23 @@ const Sicp: React.FC = () => { // Handle loading of latest viewed section and fetch json data React.useEffect(() => { + const valid_langs = ['en', 'zh_CN']; + if (section && valid_langs.includes(section) || param_lang) { + const plang = param_lang ? param_lang : (section ? section : SICP_DEF_TB_LANG); + if (!valid_langs.includes(plang)) { + setLang(SICP_DEF_TB_LANG); + setSicpLangLocalStorage(SICP_DEF_TB_LANG); + } else { + setLang(plang); + setSicpLangLocalStorage(plang); + } + if (section && valid_langs.includes(section)) { + navigate(`/sicpjs/${SICP_INDEX}`, { replace: true }); + } else { + navigate(`/sicpjs/${section}`, { replace: true }); + } + return; + } if (!section) { /** * Handles rerouting to the latest viewed section when clicking from @@ -107,6 +128,10 @@ const Sicp: React.FC = () => { setLoading(true); + if (!valid_langs.includes(lang)) { + setLang(SICP_DEF_TB_LANG); + setSicpLangLocalStorage(SICP_DEF_TB_LANG); + } fetch(baseUrl + lang + '/' + section + extension) .then(response => { if (!response.ok) { @@ -118,7 +143,7 @@ const Sicp: React.FC = () => { try { const newData = parseArr(myJson, refs); // Might throw error setData(newData); - setSicpSectionLocalStorage(path.join(lang || 'en', section)); // Sets local storage if valid page + setSicpSectionLocalStorage(section); // Sets local storage if valid page } catch (error) { throw new ParseJsonError(error.message); } @@ -140,7 +165,7 @@ const Sicp: React.FC = () => { .finally(() => { setLoading(false); }); - }, [lang, section, navigate]); + }, [param_lang, section, lang, navigate]); // Scroll to correct position React.useEffect(() => { @@ -168,11 +193,12 @@ const Sicp: React.FC = () => { const handleLanguageToggle = () => { const newLang = lang === 'en' ? 'zh_CN' : 'en'; - navigate(`/sicpjs/${newLang}/${section}`); + setLang(newLang); + setSicpLangLocalStorage(newLang); }; const handleNavigation = (sect: string) => { - navigate('/sicpjs/' + `${lang}/` + sect); + navigate('/sicpjs/' + sect); }; // Language toggle button with fixed position diff --git a/src/routes/routerConfig.tsx b/src/routes/routerConfig.tsx index 689fc3a9c5..0441990f9f 100644 --- a/src/routes/routerConfig.tsx +++ b/src/routes/routerConfig.tsx @@ -49,7 +49,8 @@ const Features = () => import('../pages/featureFlags/FeatureFlags'); const commonChildrenRoutes: RouteObject[] = [ { path: 'contributors', lazy: Contributors }, { path: 'callback/github', lazy: GitHubCallback }, - { path: 'sicpjs/:lang/:section?', lazy: Sicp }, + { path: 'sicpjs/:section?', lazy: Sicp }, + { path: 'sicpjs/:param_lang/:section?', lazy: Sicp }, { path: 'features', lazy: Features } ];