From 14e06c4555896e206a050d6eb3832f06b6790182 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 09:34:53 +0300 Subject: [PATCH 01/28] chore(dev): add entry point for starting web site in dev mode --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ef62562ff..05712e550 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "desktop:start": "pnpm run --filter desktop dev", "desktop:build": "pnpm run --filter desktop build", "desktop:start-prod": "pnpm run --filter desktop start-prod", + "website:start": "pnpm run --filter website dev", "website:build": "pnpm run --filter website build", "electron:build": "pnpm desktop:build", "electron:start": "pnpm desktop:start", From b7b1d17817b45af062cc9b47a4e5f7cb54af171c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 16:41:10 +0300 Subject: [PATCH 02/28] chore(website): add list of locales --- apps/website/src/i18n.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/website/src/i18n.ts b/apps/website/src/i18n.ts index 32bd7d09c..ecd1290c0 100644 --- a/apps/website/src/i18n.ts +++ b/apps/website/src/i18n.ts @@ -2,6 +2,23 @@ import { default as i18next } from "i18next"; import HttpApi from 'i18next-http-backend'; import { initReactI18next } from "react-i18next"; +interface Locale { + id: string; + name: string; + rtl?: boolean; +} + +export const LOCALES: Locale[] = [ + { id: "ro", name: "Română" }, + { id: "zh_TW", name: "繁體中文" }, + { id: "fr", name: "Français" }, + { id: "it", name: "Italiano" }, + { id: "ja", name: "日本語" }, + { id: "pl", name: "Polski" }, + { id: "es", name: "Español" }, + { id: "ar", name: "اَلْعَرَبِيَّةُ", rtl: true }, +]; + i18next .use(HttpApi) .use(initReactI18next); From 30480b2c2364294ab33d0ddda725da5e8300538f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 17:25:58 +0300 Subject: [PATCH 03/28] chore(website/i18n): start generating routes --- apps/website/src/index.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/website/src/index.tsx b/apps/website/src/index.tsx index 10680c4fa..595b99743 100644 --- a/apps/website/src/index.tsx +++ b/apps/website/src/index.tsx @@ -7,6 +7,7 @@ import { NotFound } from './pages/_404.jsx'; import Footer from './components/Footer.js'; import GetStarted from './pages/GetStarted/get-started.js'; import SupportUs from './pages/SupportUs/SupportUs.js'; +import { LOCALES } from './i18n'; export function App(props: {repoStargazersCount: number}) { return ( @@ -14,7 +15,7 @@ export function App(props: {repoStargazersCount: number}) {
- + @@ -35,6 +36,17 @@ export async function prerender(data) { // This ensures the GitHub API is not called on every page load in the client. const stargazersCount = await getRepoStargazersCount(); - return await ssr(); + const result = await ssr(); + console.log("Got links ", result.links); + const links: string[] = []; + for (const locale of LOCALES) { + for (const link of result.links?.values() ?? []) { + links.push(locale.id + link); + } + } + return { + ...result, + links + }; } From f4796f0f9e32e9a1635a41ff34044b3eb8811ac1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 18:18:47 +0300 Subject: [PATCH 04/28] feat(website/i18n): footer navigation --- apps/website/src/components/Footer.css | 10 +++++++++- apps/website/src/components/Footer.tsx | 20 +++++++++++++++----- apps/website/src/i18n.ts | 2 +- apps/website/src/index.tsx | 14 +------------- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/apps/website/src/components/Footer.css b/apps/website/src/components/Footer.css index 1dafed348..ed0ec973b 100644 --- a/apps/website/src/components/Footer.css +++ b/apps/website/src/components/Footer.css @@ -5,17 +5,25 @@ footer { color: var(--muted-color); font-size: 0.8em; - .content-wrapper { + .row { display: flex; justify-content: space-between; align-items: center; flex-direction: column-reverse; gap: 2em; + margin-bottom: 1em; @media (min-width: 720px) { flex-direction: row; } } + + nav.languages { + flex-grow: 1; + justify-content: center; + display: flex; + gap: 1em; + } } .social-buttons { diff --git a/apps/website/src/components/Footer.tsx b/apps/website/src/components/Footer.tsx index 04033f565..8948ca779 100644 --- a/apps/website/src/components/Footer.tsx +++ b/apps/website/src/components/Footer.tsx @@ -5,18 +5,28 @@ import githubDiscussionsIcon from "../assets/boxicons/bx-discussion.svg?raw"; import matrixIcon from "../assets/boxicons/bx-message-dots.svg?raw"; import redditIcon from "../assets/boxicons/bx-reddit.svg?raw"; import { Link } from "./Button.js"; -import { t } from "../i18n"; +import { LOCALES, t } from "../i18n"; export default function Footer() { return (
-
) diff --git a/apps/website/src/i18n.ts b/apps/website/src/i18n.ts index ecd1290c0..a3305a71c 100644 --- a/apps/website/src/i18n.ts +++ b/apps/website/src/i18n.ts @@ -17,7 +17,7 @@ export const LOCALES: Locale[] = [ { id: "pl", name: "Polski" }, { id: "es", name: "Español" }, { id: "ar", name: "اَلْعَرَبِيَّةُ", rtl: true }, -]; +].toSorted((a, b) => a.name.localeCompare(b.name)); i18next .use(HttpApi) diff --git a/apps/website/src/index.tsx b/apps/website/src/index.tsx index 595b99743..231b7326e 100644 --- a/apps/website/src/index.tsx +++ b/apps/website/src/index.tsx @@ -7,7 +7,6 @@ import { NotFound } from './pages/_404.jsx'; import Footer from './components/Footer.js'; import GetStarted from './pages/GetStarted/get-started.js'; import SupportUs from './pages/SupportUs/SupportUs.js'; -import { LOCALES } from './i18n'; export function App(props: {repoStargazersCount: number}) { return ( @@ -36,17 +35,6 @@ export async function prerender(data) { // This ensures the GitHub API is not called on every page load in the client. const stargazersCount = await getRepoStargazersCount(); - const result = await ssr(); - console.log("Got links ", result.links); - const links: string[] = []; - for (const locale of LOCALES) { - for (const link of result.links?.values() ?? []) { - links.push(locale.id + link); - } - } - return { - ...result, - links - }; + return await ssr(); } From 1a6f5a027f403b0131e1e456aa42989a1da44108 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 18:21:52 +0300 Subject: [PATCH 05/28] chore(website/i18n): add English too --- apps/website/src/i18n.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/website/src/i18n.ts b/apps/website/src/i18n.ts index a3305a71c..0d50259fe 100644 --- a/apps/website/src/i18n.ts +++ b/apps/website/src/i18n.ts @@ -9,6 +9,7 @@ interface Locale { } export const LOCALES: Locale[] = [ + { id: "en", name: "English" }, { id: "ro", name: "Română" }, { id: "zh_TW", name: "繁體中文" }, { id: "fr", name: "Français" }, From 49cf7ae1a3fdd472453596eb38fd25c5a68c52ac Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 25 Oct 2025 18:54:24 +0300 Subject: [PATCH 06/28] feat(website/i18n): render pages by locale --- apps/website/src/components/Header.tsx | 8 ++++-- apps/website/src/index.tsx | 38 ++++++++++++++++++-------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/apps/website/src/components/Header.tsx b/apps/website/src/components/Header.tsx index 07c6a2cba..198fc7f60 100644 --- a/apps/website/src/components/Header.tsx +++ b/apps/website/src/components/Header.tsx @@ -1,13 +1,14 @@ import "./Header.css"; import { Link } from "./Button.js"; import { SocialButtons, SocialButton } from "./Footer.js"; -import { useEffect, useMemo, useState } from "preact/hooks"; +import { useContext, useEffect, useMemo, useState } from "preact/hooks"; import { useLocation } from 'preact-iso'; import DownloadButton from './DownloadButton.js'; import githubIcon from "../assets/boxicons/bx-github.svg?raw"; import Icon from "./Icon.js"; import logoPath from "../assets/icon-color.svg"; import menuIcon from "../assets/boxicons/bx-menu.svg?raw"; +import { LocaleContext } from ".."; interface HeaderLink { url: string; @@ -23,6 +24,7 @@ const HEADER_LINKS: HeaderLink[] = [ export function Header(props: {repoStargazersCount: number}) { const { url } = useLocation(); + const locale = useContext(LocaleContext); const [ mobileMenuShown, setMobileMenuShown ] = useState(false); return ( @@ -48,7 +50,7 @@ export function Header(props: {repoStargazersCount: number}) {
); -} \ No newline at end of file +} diff --git a/apps/website/src/index.tsx b/apps/website/src/index.tsx index 231b7326e..df4836381 100644 --- a/apps/website/src/index.tsx +++ b/apps/website/src/index.tsx @@ -2,29 +2,45 @@ import './style.css'; import { FALLBACK_STARGAZERS_COUNT, getRepoStargazersCount } from './github-utils.js'; import { Header } from './components/Header.jsx'; import { Home } from './pages/Home/index.jsx'; -import { LocationProvider, Router, Route, hydrate, prerender as ssr } from 'preact-iso'; +import { LocationProvider, Router, Route, hydrate, prerender as ssr, useLocation } from 'preact-iso'; import { NotFound } from './pages/_404.jsx'; import Footer from './components/Footer.js'; import GetStarted from './pages/GetStarted/get-started.js'; import SupportUs from './pages/SupportUs/SupportUs.js'; +import { createContext } from 'preact'; + +export const LocaleContext = createContext('en'); export function App(props: {repoStargazersCount: number}) { return ( -
-
- - - - - - -
-