This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git
The following commit(s) were added to refs/heads/master by this push:
new 1b277128747 [fix](website) Fix benchmark entry and restore English
footer (#4360)
1b277128747 is described below
commit 1b277128747562dcd71415a5b9d7cb0fe20b17d8
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Sun Oct 18 19:55:37 2026 +0100
[fix](website) Fix benchmark entry and restore English footer (#4360)
Selecting Why Doris → Benchmarks from Chinese documentation inherited
`/zh-CN/`, although the benchmark content was English and its language
controls were hidden. Documentation and community pages also replaced
the full footer with a compact copyright notice.
Both desktop and mobile Benchmark links now open `/why-doris/benchmarks`
in the English locale. Page language controls remain available on
fallback pages and offer the existing translations. The full footer now
renders on documentation and community pages, using one shared English
configuration and `lang="en"` regardless of the page locale.
## Validation
- All 18 tests passed in `marketing-pages.test.cjs`,
`locale-registry.test.cjs`, and `doc-navigation.test.cjs`, including new
navigation and fallback-language regressions.
- Scoped TypeScript check and `git diff --check` passed.
- A small native Docusaurus fixture built successfully for English,
Chinese, and Japanese using the production components and locale
dictionaries. It covers Dev/4.x documentation, community pages, and the
benchmark page; a full documentation build was not run.
- Browser checks passed at 1440 px and 390 px across all three locales:
18 documentation/community route and viewport combinations, English
benchmark entry, English/Japanese round trips, query/fragment
preservation, refresh, fallback Chinese language controls, and English
footer content before and after hydration. No horizontal overflow, page
errors, or hydration errors occurred. Desktop and mobile screenshots
were inspected.
- The shared footer configuration preserves all existing links, logo
settings, and copyright content.
## Review conclusions
- Goal: Benchmark navigation enters English, manual page-language
switching remains available, and documentation/community pages show the
full English footer.
- Scope: Changes stay within shared navigation, language controls,
footer configuration/rendering, and regression tests.
- Information architecture: Documentation versions, localized content,
sidebars, blog, and community organization remain consistent.
- Routing: Existing page URLs and anchors are preserved. Only the
Benchmark menu destination changes; no redirects or sidebar updates are
required.
- Frontend: Desktop and mobile use the same menu data. The footer
retains existing styling and semantic theme tokens, adds an English
language attribute, and removes its post-hydration replacement.
- Coverage: Targeted tests, scoped type checking, production fixture
builds, and browser interactions cover the changed behavior. Full-site
compilation remains for CI.
- Other issues: No additional correctness, accessibility, SEO, or
maintainability issues found in the changed scope.
## Versions
- [x] dev
- [x] 4.x
- [x] 3.x
- [x] 2.1 or older (not covered by version/language sync gate)
The shared navigation and footer apply across documentation versions.
## Languages
- [x] Chinese
- [x] English
- [x] Japanese
The footer deliberately uses English in every locale; document
translations need no content changes.
## Docs Checklist
- [x] Checked by AI
- [x] Test Cases Built
- [x] Updated required version and language counterparts, or explained
why not
- [x] If only one language changed, confirmed whether source/translation
counterparts need sync
Co-authored-by: morningman <[email protected]>
---
config/footer.js | 90 +++++++++++++++++++++++
docusaurus.config.js | 89 +---------------------
scripts/i18n/__tests__/marketing-pages.test.cjs | 39 +++++++++-
src/components/home-next/NavbarNext.tsx | 3 +-
src/components/home-next/PageLanguageSwitcher.tsx | 3 +-
src/theme/Footer/index.tsx | 56 ++------------
src/theme/Footer/styles.scss | 19 -----
7 files changed, 137 insertions(+), 162 deletions(-)
diff --git a/config/footer.js b/config/footer.js
new file mode 100644
index 00000000000..59f95e98f5a
--- /dev/null
+++ b/config/footer.js
@@ -0,0 +1,90 @@
+// Shared English footer content. Render this source in every locale so theme
+// translations cannot change the global footer.
+module.exports = {
+ links: [
+ {
+ title: 'ASF',
+ items: [
+ {
+ label: 'Foundation',
+ href: 'https://www.apache.org/',
+ },
+ {
+ label: 'License',
+ href: 'https://www.apache.org/licenses/',
+ },
+ {
+ label: 'Events',
+ href: 'https://www.apache.org/events/current-event',
+ },
+ {
+ label: 'Sponsorship',
+ href: 'https://www.apache.org/foundation/sponsorship.html',
+ },
+ {
+ label: 'Privacy',
+ href:
'https://privacy.apache.org/policies/privacy-policy-public.html',
+ },
+ {
+ label: 'Security',
+ href: 'https://www.apache.org/security/',
+ },
+ {
+ label: 'Thanks',
+ href: 'https://www.apache.org/foundation/thanks.html',
+ },
+ ],
+ },
+ {
+ title: 'Resources',
+ items: [
+ {
+ label: 'Download',
+ href: '/download',
+ },
+ {
+ label: 'Brand Assets',
+ href: '/brand-assets',
+ },
+ // {
+ // label: 'Docs',
+ // href: '/docs/get-starting/quick-start',
+ // },
+ {
+ label: 'Blog',
+ href: '/blog',
+ },
+ ],
+ },
+ {
+ title: 'Community',
+ items: [
+ {
+ label: 'How to contribute',
+ href: '/community/how-to-contribute/contribute-to-doris',
+ },
+ {
+ label: 'Source code',
+ href: 'https://github.com/apache/doris/',
+ },
+ {
+ label: 'Doris team',
+ href: '/community/team',
+ },
+ {
+ label: 'Roadmap',
+ href: '/community/roadmap',
+ },
+ {
+ label: 'Improvement proposal',
+ href:
'https://cwiki.apache.org/confluence/display/DORIS/Doris+Improvement+Proposals',
+ },
+ ],
+ },
+ ],
+ logo: {
+ alt: '',
+ src: '/images/asf_logo_apache.svg',
+ },
+ copyright: `Copyright © ${new Date().getFullYear()} The Apache Software
Foundation,Licensed under the <a
href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache
License, Version 2.0</a>. Apache, Doris, Apache Doris, the Apache feather logo
and the Apache Doris logo are trademarks of The Apache Software Foundation.`,
+};
diff --git a/docusaurus.config.js b/docusaurus.config.js
index ae7c2098759..b10d238fc69 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -553,94 +553,7 @@ const config = {
navbar: {
items: [],
},
- footer: {
- links: [
- {
- title: 'ASF',
- items: [
- {
- label: 'Foundation',
- href: 'https://www.apache.org/',
- },
- {
- label: 'License',
- href: 'https://www.apache.org/licenses/',
- },
- {
- label: 'Events',
- href:
'https://www.apache.org/events/current-event',
- },
- {
- label: 'Sponsorship',
- href:
'https://www.apache.org/foundation/sponsorship.html',
- },
- {
- label: 'Privacy',
- href:
'https://privacy.apache.org/policies/privacy-policy-public.html',
- },
- {
- label: 'Security',
- href: 'https://www.apache.org/security/',
- },
- {
- label: 'Thanks',
- href:
'https://www.apache.org/foundation/thanks.html',
- },
- ],
- },
- {
- title: 'Resources',
- items: [
- {
- label: 'Download',
- href: '/download',
- },
- {
- label: 'Brand Assets',
- href: '/brand-assets',
- },
- // {
- // label: 'Docs',
- // href: '/docs/get-starting/quick-start',
- // },
- {
- label: 'Blog',
- href: '/blog',
- },
- ],
- },
- {
- title: 'Community',
- items: [
- {
- label: 'How to contribute',
- href:
'/community/how-to-contribute/contribute-to-doris',
- },
- {
- label: 'Source code',
- href: 'https://github.com/apache/doris/',
- },
- {
- label: 'Doris team',
- href: '/community/team',
- },
- {
- label: 'Roadmap',
- href: '/community/roadmap',
- },
- {
- label: 'Improvement proposal',
- href:
'https://cwiki.apache.org/confluence/display/DORIS/Doris+Improvement+Proposals',
- },
- ],
- },
- ],
- logo: {
- alt: '',
- src: '/images/asf_logo_apache.svg',
- },
- copyright: `Copyright © ${new Date().getFullYear()} The Apache
Software Foundation,Licensed under the <a
href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache
License, Version 2.0</a>. Apache, Doris, Apache Doris, the Apache feather logo
and the Apache Doris logo are trademarks of The Apache Software Foundation.`,
- },
+ footer: require('./config/footer'),
docs: {
sidebar: {
autoCollapseCategories: true,
diff --git a/scripts/i18n/__tests__/marketing-pages.test.cjs
b/scripts/i18n/__tests__/marketing-pages.test.cjs
index e2e50d9917b..543c9dc3748 100644
--- a/scripts/i18n/__tests__/marketing-pages.test.cjs
+++ b/scripts/i18n/__tests__/marketing-pages.test.cjs
@@ -23,13 +23,24 @@ function modules(locale, pathname, enabled = true) {
customFields: {defaultLocalePageLocales: ['ja'],
translatedPagePaths: enabled ? {ja: pagePaths} : {}}},
'@docusaurus/Translate': {translate: ({message}) => message},
'@docusaurus/useDocusaurusContext': () => ({i18n}),
+ '@docusaurus/useBaseUrl': source => source,
'@docusaurus/useGlobalData': () => ({}),
'@docusaurus/router': {useLocation: () => location},
- '@docusaurus/Link': ({to, autoAddBaseUrl, children, ...props}) =>
- React.createElement('a', {...props, href:
to.replace(/^pathname:\/\//, '')}, children),
+ '@docusaurus/Link': React.forwardRef(({to, href, autoAddBaseUrl =
true, children, ...props}, ref) => {
+ const target = (to || href).replace(/^pathname:\/\//, '');
+ const baseUrl = locale === 'en' ? '' : `/${locale}`;
+ const destination = autoAddBaseUrl && target.startsWith('/') &&
!target.startsWith(`${baseUrl}/`)
+ ? baseUrl + target : target;
+ return React.createElement('a', {...props, ref, href:
destination}, children);
+ }),
+ '@site/src/components/brand-theme/BrandThemeSwitcher':
{BrandThemeSwitcher: () => null},
};
function load(file) {
file = path.resolve(root, file);
+ if (!path.extname(file) || !fs.existsSync(file)) {
+ file = ['', '.ts', '.tsx', '.js', '.json'].map(extension => file +
extension)
+ .find(candidate => fs.existsSync(candidate) &&
fs.statSync(candidate).isFile());
+ }
if (cache.has(file)) return cache.get(file).exports;
const module = {exports: {}};
cache.set(file, module);
@@ -39,8 +50,8 @@ function modules(locale, pathname, enabled = true) {
const resolve = name => {
if (Object.hasOwn(imports, name)) return imports[name];
if (name.endsWith('.scss')) return {};
- if (name.startsWith('@site/')) return load(name.slice(6) + '.ts');
- if (name.startsWith('.')) return
load(path.resolve(path.dirname(file), name) + '.ts');
+ if (name.startsWith('@site/')) return load(name.slice(6));
+ if (name.startsWith('.')) return
load(path.resolve(path.dirname(file), name));
return require(name);
};
new Function('require', 'module', 'exports', outputText)(resolve,
module, module.exports);
@@ -91,6 +102,26 @@ test('page language controls preserve query/hash and mark
the active language',
}
});
+test('fallback Chinese benchmark pages still offer English and available
translations', () => {
+ const {PageLanguageSwitcher} = modules('zh-CN',
'/zh-CN/why-doris/benchmarks/')
+ ('src/components/home-next/PageLanguageSwitcher.tsx');
+ const html =
renderToStaticMarkup(React.createElement(PageLanguageSwitcher));
+ assert.match(html, /href="\/why-doris\/benchmarks\/\?from=test#tech"/);
+ assert.match(html, /href="\/ja\/why-doris\/benchmarks\/\?from=test#tech"/);
+ assert.doesNotMatch(html, /href="\/zh-CN\//);
+ assert.doesNotMatch(html, /aria-current="page"/);
+});
+
+test('desktop and mobile benchmark navigation always enters the English page',
() => {
+ for (const locale of ['en', 'zh-CN', 'ja']) {
+ const {NavbarNext} = modules(locale,
`/${locale}/docs/4.x/getting-started/what-is-apache-doris/`)
+ ('src/components/home-next/NavbarNext.tsx');
+ const html = renderToStaticMarkup(React.createElement(NavbarNext));
+ assert.equal((html.match(/href="\/why-doris\/benchmarks"/g) ??
[]).length, 2, locale);
+ assert.doesNotMatch(html, /href="\/(zh-CN|ja)\/why-doris\/benchmarks/);
+ }
+});
+
test('language controls stay absent on untranslated pages and when Japanese is
disabled', () => {
for (const [locale, pathname, enabled] of [['en', '/download/', true],
['ja', '/ja/why-doris/users/', true], ['en', '/use-cases/ai/', false]]) {
const {PageLanguageSwitcher} = modules(locale, pathname,
enabled)('src/components/home-next/PageLanguageSwitcher.tsx');
diff --git a/src/components/home-next/NavbarNext.tsx
b/src/components/home-next/NavbarNext.tsx
index 0d0c4b7e2c8..b3036304702 100644
--- a/src/components/home-next/NavbarNext.tsx
+++ b/src/components/home-next/NavbarNext.tsx
@@ -42,7 +42,8 @@ function buildNavItems(
label: translate({ id: "homepage.navbar.001", message: "Why Doris"
}),
items: [
{ label: translate({ id: "homepage.navbar.002", message:
"Doris vs. Others" }), href: '/why-doris/compare' },
- { label: translate({ id: "homepage.navbar.003", message:
"Benchmarks" }), href: '/why-doris/benchmarks' },
+ // Enter through English from every locale; the page offers
its own language controls.
+ { label: translate({ id: "homepage.navbar.003", message:
"Benchmarks" }), href: 'pathname:///why-doris/benchmarks' },
{ label: translate({ id: "homepage.navbar.004", message: "Key
Features" }), href: '/why-doris/key-features' },
{ label: translate({ id: "homepage.navbar.005", message: "User
Stories" }), href: '/why-doris/users' },
],
diff --git a/src/components/home-next/PageLanguageSwitcher.tsx
b/src/components/home-next/PageLanguageSwitcher.tsx
index 29e787c38a8..5610c7a1fcc 100644
--- a/src/components/home-next/PageLanguageSwitcher.tsx
+++ b/src/components/home-next/PageLanguageSwitcher.tsx
@@ -12,7 +12,8 @@ export function PageLanguageSwitcher(): JSX.Element | null {
const { pathname, search, hash } = useLocation();
const path = normalizePathname(pathname, locales).replace(/\/+$/, '');
const translations = locales.filter(locale => hasTranslatedPage(path,
locale));
- if (!translations.length || (currentLocale !== defaultLocale &&
!translations.includes(currentLocale))) return null;
+ // Fallback pages also need an exit to English or an available translation.
+ if (!translations.length) return null;
const languages = [defaultLocale, ...translations];
return (
diff --git a/src/theme/Footer/index.tsx b/src/theme/Footer/index.tsx
index a5059333fc2..99b1d3cbc68 100644
--- a/src/theme/Footer/index.tsx
+++ b/src/theme/Footer/index.tsx
@@ -1,11 +1,9 @@
-import React, { useState, useEffect } from 'react';
+import React from 'react';
-import { useThemeConfig } from '@docusaurus/theme-common';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import footer from '@site/config/footer';
import FooterLinks from '@theme/Footer/Links';
import FooterLogo from '@theme/Footer/Logo';
import FooterCopyright from '@theme/Footer/Copyright';
-import FooterLayout from '@theme/Footer/Layout';
import './styles.scss';
import { MailIcon } from '@site/src/components/Icons/mail';
import { GithubIcon } from '@site/src/components/Icons/github';
@@ -13,53 +11,15 @@ import { TwitterIcon } from
'@site/src/components/Icons/twitter';
import { SlackIcon } from '@site/src/components/Icons/slack';
import { buildSlackEntryUrl } from
'@site/src/components/slack-redirect/slack-attribution.logic';
import { DiscordIcon } from '@site/src/components/Icons/discord-icon';
-import { BilibiliIcon } from '@site/src/components/Icons/bilibili';
-import { WechatIcon } from '@site/src/components/Icons/wechat';
import { YoutubeIcon } from '@site/src/components/Icons/youtube';
import { LinkedinIcon } from '@site/src/components/Icons/linkedin';
import { MediumIcon } from '@site/src/components/Icons/medium';
-import Translate from '@docusaurus/Translate';
-import Link from '@docusaurus/Link';
-import { normalizePathname } from '@site/src/utils/locale';
-function Footer(): React.ReactElement | null {
- const { footer } = useThemeConfig();
- if (!footer) {
- return null;
- }
- const { copyright, links, logo, style } = footer;
- const {
- i18n: { locales },
- } = useDocusaurusContext();
-
- const [isDocsPage, setIsDocsPage] = useState(false); // docs page or
community page
- useEffect(() => {
- if (typeof window !== 'undefined') {
- const normalizedPathname = normalizePathname(location.pathname,
locales);
- const pathname = normalizedPathname.split('/')[1];
- const docsPage = pathname === 'docs' ||
normalizedPathname.startsWith('/community');
- setIsDocsPage(docsPage);
- }
- }, [locales, typeof window !== 'undefined' && location.pathname]);
-
- const ResourcesItems = (links.find(e => e.title === 'Resources')?.items ||
[]) as any[];
- const CommunityItems = (links.find(e => e.title === 'Community')?.items ||
[]) as any[];
- if (isDocsPage) {
- return (
- <div className="docs-footer flex-col lg:flex-row">
- <p className='docs-footer-p'>
- The contents of this website are © 2024{' '}
- <Link href="https://www.apache.org/">Apache Software
Foundation</Link> under the terms of the{' '}
- <Link
href="https://www.apache.org/licenses/LICENSE-2.0.html">Apache License
v2.</Link> Apache
- Doris, Doris, and the Doris logo are either registered
trademarks or trademarks of The Apache
- Software Foundation in the United States and other
countries.
- </p>
- </div>
- );
- }
+function Footer(): React.ReactElement {
+ const { copyright, links, logo } = footer;
return (
- <div className="footer pt-16 pb-10">
+ <footer className="footer pt-16 pb-10" lang="en">
<div className="container">
<div className="footer-box">
<div className="left">
@@ -68,9 +28,7 @@ function Footer(): React.ReactElement | null {
</div>
<div className="right">
<div className="footer__title">
- <Translate id="footer.follow" description="Footer
Follow">
- Join the community
- </Translate>
+ Join the community
</div>
<div className="social-list">
<div className="social">
@@ -141,7 +99,7 @@ function Footer(): React.ReactElement | null {
</div>
<FooterCopyright copyright={copyright} />
</div>
- </div>
+ </footer>
);
}
diff --git a/src/theme/Footer/styles.scss b/src/theme/Footer/styles.scss
index c4e649e97a3..e700f7e5f56 100644
--- a/src/theme/Footer/styles.scss
+++ b/src/theme/Footer/styles.scss
@@ -210,22 +210,3 @@
}
}
}
-
-.docs-footer {
- height: 3.25rem;
- background-color: #fff;
- padding: 1rem 1.5rem;
- border-top: 1px solid #EDF2FA;
- .docs-footer-p {
- text-align: center;
- color: rgba(29, 29, 29, 0.4);
- font-family: Inter;
- font-size: 9px;
- font-style: normal;
- font-weight: 400;
- line-height: 20px;
- }
- .docs-footer-p a {
- text-decoration: underline;
- }
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]