This is an automated email from the ASF dual-hosted git repository.
lidongdai pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/seatunnel-website.git
The following commit(s) were added to refs/heads/main by this push:
new 29663d185fa6 [Fix] Fix Google Translate functionality for non-default
languages (#429)
29663d185fa6 is described below
commit 29663d185fa6edbaccec41e4d4f69dd36bbfa2ee
Author: zoo-code <[email protected]>
AuthorDate: Sun Feb 15 10:06:17 2026 +0900
[Fix] Fix Google Translate functionality for non-default languages (#429)
---
docusaurus.config.js | 7 +
src/css/custom.css | 32 +++++
src/pages/home/index.jsx | 6 +-
src/theme/Logo/index.js | 60 +++++++++
src/theme/Navbar/Logo/index.js | 11 ++
.../NavbarItem/LocaleDropdownNavbarItem/index.js | 142 +++++++++++++++------
static/js/google_translate_init.js | 3 +-
7 files changed, 219 insertions(+), 42 deletions(-)
diff --git a/docusaurus.config.js b/docusaurus.config.js
index cf3aea8743da..94c2fabcf0e8 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -119,6 +119,13 @@ const config = {
`,
},
],
+ scripts: [
+ '/js/google_translate_init.js', // Load synchronously first
+ {
+ src:
'https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit',
+ async: true,
+ },
+ ],
presets: [
[
"classic",
diff --git a/src/css/custom.css b/src/css/custom.css
index 2d0a692bc4e3..1d61e357b5ae 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -66,4 +66,36 @@ html {
html[data-theme='dark'] img {
filter: brightness(.8) contrast(1.2)
+}
+
+/* Hide Google Translate banner and fix body positioning */
+.goog-te-banner-frame {
+ display: none !important;
+}
+
+body {
+ top: 0 !important;
+}
+
+.skiptranslate {
+ display: none !important;
+}
+
+body > .skiptranslate {
+ display: none !important;
+}
+
+/* Hide Google Translate branding at the bottom */
+#goog-gt-tt, .goog-te-balloon-frame {
+ display: none !important;
+}
+
+/* Ensure page isn't pushed down by Google Translate */
+html body {
+ position: static !important;
+}
+
+/* Prevent Google Translate from translating specific elements */
+.notranslate {
+ translate: no;
}
\ No newline at end of file
diff --git a/src/pages/home/index.jsx b/src/pages/home/index.jsx
index 86ed765fc0e1..3160b79a613d 100644
--- a/src/pages/home/index.jsx
+++ b/src/pages/home/index.jsx
@@ -74,7 +74,7 @@ export default function () {
<div className="block">
<div className="banner text_center">
- <h1 className="main_title"><span
className="apache">Apache</span> <span
+ <h1 className="main_title notranslate"
translate="no"><span className="apache">Apache</span> <span
className="seatunnel">SeaTunnel</span>
</h1>
@@ -86,14 +86,14 @@ export default function () {
<a href={systemConfiguration.github.projectUrl}
target="_blank"
className="corner_button link_btn blue"
onMouseOver={() => changeFlag(1)} onMouseOut={() => changeFlag(2)}>
<img className="button_icon github1"
src={useBaseUrl('/home/icons/github' + flag + '.svg')} alt="github"/>
- <span>GitHub</span>
+ <span className="notranslate">GitHub</span>
</a>
<a href="https://s.apache.org/seatunnel-slack"
target="_blank"
className="corner_button link_btn blue"
>
<img className="button_icon"
src={useBaseUrl('/home/icons/slack.svg')} alt="slack"/>
- <span>Slack</span>
+ <span className="notranslate">Slack</span>
</a>
</div>
</div>
diff --git a/src/theme/Logo/index.js b/src/theme/Logo/index.js
new file mode 100644
index 000000000000..06c4f57e9760
--- /dev/null
+++ b/src/theme/Logo/index.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import {useThemeConfig} from '@docusaurus/theme-common';
+import ThemedImage from '@theme/ThemedImage';
+function LogoThemedImage({logo, alt, imageClassName}) {
+ const sources = {
+ light: useBaseUrl(logo.src),
+ dark: useBaseUrl(logo.srcDark || logo.src),
+ };
+ const themedImage = (
+ <ThemedImage
+ className={logo.className}
+ sources={sources}
+ height={logo.height}
+ width={logo.width}
+ alt={alt}
+ style={logo.style}
+ />
+ );
+ // Is this extra div really necessary?
+ // introduced in https://github.com/facebook/docusaurus/pull/5666
+ return imageClassName ? (
+ <div className={imageClassName}>{themedImage}</div>
+ ) : (
+ themedImage
+ );
+}
+export default function Logo(props) {
+ const {
+ siteConfig: {title},
+ } = useDocusaurusContext();
+ const {
+ navbar: {title: navbarTitle, logo},
+ } = useThemeConfig();
+ const {imageClassName, titleClassName, ...propsRest} = props;
+ const logoLink = useBaseUrl(logo?.href || '/');
+ // If visible title is shown, fallback alt text should be
+ // an empty string to mark the logo as decorative.
+ const fallbackAlt = navbarTitle ? '' : title;
+ // Use logo alt text if provided (including empty string),
+ // and provide a sensible fallback otherwise.
+ const alt = logo?.alt ?? fallbackAlt;
+ return (
+ <Link
+ to={logoLink}
+ {...propsRest}
+ {...(logo?.target && {target: logo.target})}>
+ {logo && (
+ <LogoThemedImage
+ logo={logo}
+ alt={alt}
+ imageClassName={imageClassName}
+ />
+ )}
+ {navbarTitle != null && <b className={titleClassName}
translate="no">{navbarTitle}</b>}
+ </Link>
+ );
+}
diff --git a/src/theme/Navbar/Logo/index.js b/src/theme/Navbar/Logo/index.js
new file mode 100644
index 000000000000..f0fa51ffad3f
--- /dev/null
+++ b/src/theme/Navbar/Logo/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Logo from '@theme/Logo';
+export default function NavbarLogo() {
+ return (
+ <Logo
+ className="navbar__brand"
+ imageClassName="navbar__logo"
+ titleClassName="navbar__title text--truncate"
+ />
+ );
+}
diff --git a/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.js
b/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.js
index 9add6b242ccb..929d4d3c1f99 100644
--- a/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.js
+++ b/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.js
@@ -34,36 +34,85 @@ export default function LocaleDropdownNavbarItem({
const alternatePageUtils = useAlternatePageUtils();
const { search, hash } = useLocation();
- // Clear Google Translate cookie if we are on a native locale page
- React.useEffect(() => {
- if (currentLocale === 'en' || currentLocale === 'zh-CN') {
- const clearCookie = (name) => {
- document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00
UTC; path=/;';
- document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00
UTC; path=/seatunnel-website;';
- document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00
UTC; domain=.' + document.domain + '; path=/;';
- };
- clearCookie('googtrans');
- const frame = document.querySelector('.goog-te-banner-frame');
- if (frame) {
- frame.style.display = 'none';
+ // Helper function to get current Google Translate language code from
cookie
+ const getGoogleTranslateLangCode = () => {
+ if (typeof document === 'undefined') return null;
+ const cookie = document.cookie.split('; ').find(row =>
row.startsWith('googtrans='));
+ if (cookie) {
+ const match = cookie.match(/googtrans=\/[^\/]+\/([^;]+)/);
+ return match ? match[1] : null;
+ }
+ return null;
+ };
+
+ // Helper function to get language label from cookie
+ const getLanguageLabelFromCookie = () => {
+ const langCode = getGoogleTranslateLangCode();
+ if (langCode) {
+ const googleLang = GOOGLE_LANGUAGES.find(lang => lang.code ===
langCode);
+ if (googleLang) {
+ return googleLang.label;
}
}
- }, [currentLocale]);
+ return localeConfigs[currentLocale]?.label || 'English';
+ };
- // Detect if we're on a versioned documentation page
- const currentPath = typeof window !== 'undefined' ?
window.location.pathname : '';
- const versionMatch = currentPath.match(/^\/docs\/([^/]+)\//);
- const isVersionedDoc = versionMatch && versionMatch[1] !== '';
+ // State to track current language label
+ const [currentLangLabel, setCurrentLangLabel] =
React.useState(getLanguageLabelFromCookie());
+
+ // Update language label based on Google Translate cookie
+ React.useEffect(() => {
+ const updateLabel = () => {
+ setCurrentLangLabel(getLanguageLabelFromCookie());
+ };
+
+ // Initial update
+ updateLabel();
+
+ // Listen for storage events (from other tabs/windows)
+ window.addEventListener('storage', updateLabel);
+
+ return () => {
+ window.removeEventListener('storage', updateLabel);
+ };
+ }, [currentLocale, localeConfigs]);
+
+ // Hide Google Translate banner frame if present
+ React.useEffect(() => {
+ const frame = document.querySelector('.goog-te-banner-frame');
+ if (frame) {
+ frame.style.display = 'none';
+ }
+ }, []);
// Helper function to trigger Google Translate programmatically
const handleGoogleTranslate = (langCode) => {
- const select = document.querySelector('.goog-te-combo');
- if (select) {
- select.value = langCode;
- select.dispatchEvent(new Event('change'));
+ // Set Google Translate cookie
+ const cookieValue = '/en/' + langCode;
+
+ // Set cookie without domain for localhost compatibility
+ document.cookie = 'googtrans=' + cookieValue + '; path=/';
+
+ // Also set with domain if not localhost
+ if (window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
+ document.cookie = 'googtrans=' + cookieValue + '; path=/; domain='
+ window.location.hostname;
+ }
+
+ // If currently on a /zh-CN/ page, redirect to English version first
+ const currentPath = window.location.pathname;
+ if (currentPath.startsWith('/zh-CN/')) {
+ // Remove /zh-CN prefix to go to English version
+ const englishPath = currentPath.replace(/^\/zh-CN/, '') || '/';
+ window.location.href = englishPath + window.location.search +
window.location.hash;
+ } else {
+ // Reload the page to apply translation
+ window.location.reload();
}
};
+ const activeGoogleLang = getGoogleTranslateLangCode();
+ const activeClass = mobile ? 'menu__link--active' :
'dropdown__link--active';
+
const localeItems = locales.map((locale) => {
const baseTo = `pathname://${alternatePageUtils.createUrl({
locale,
@@ -71,47 +120,64 @@ export default function LocaleDropdownNavbarItem({
})}`;
const to = `${baseTo}${search}${hash}`;
+ // Native locale is only active if no Google Translate is active AND
locale matches
+ const isActive = !activeGoogleLang && locale === currentLocale;
+
return {
label: localeConfigs[locale].label,
lang: localeConfigs[locale].htmlLang,
to,
target: '_self',
autoAddBaseUrl: false,
- className:
- locale === currentLocale
- ? mobile
- ? 'menu__link--active'
- : 'dropdown__link--active'
- : '',
+ className: `notranslate ${isActive ? activeClass : ''}`.trim(),
onClick: () => {
- // Clear Google Translate cookie when switching to native
locales
- document.cookie = 'googtrans=; expires=Thu, 01 Jan 1970
00:00:00 UTC; path=/;';
+ // Clear Google Translate cookies when switching to native
locales
+ const clearCookie = (name) => {
+ document.cookie = name + '=; expires=Thu, 01 Jan 1970
00:00:00 UTC; path=/;';
+ document.cookie = name + '=; expires=Thu, 01 Jan 1970
00:00:00 UTC; path=/seatunnel-website;';
+ if (window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
+ document.cookie = name + '=; expires=Thu, 01 Jan 1970
00:00:00 UTC; domain=.' + window.location.hostname + '; path=/;';
+ }
+ };
+ clearCookie('googtrans');
+ // Update the label immediately
+ setCurrentLangLabel(localeConfigs[locale].label);
}
};
});
- const googleItems = GOOGLE_LANGUAGES.map((lang) => ({
- label: lang.label,
- to: '#',
- onClick: (e) => {
- e.preventDefault();
- handleGoogleTranslate(lang.code);
- },
- }));
+ const googleItems = GOOGLE_LANGUAGES.map((lang) => {
+ const isActive = activeGoogleLang === lang.code;
+ return {
+ label: lang.label,
+ to: '#',
+ className: `notranslate ${isActive ? activeClass : ''}`.trim(),
+ onClick: (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ // Update the label immediately
+ setCurrentLangLabel(lang.label);
+ handleGoogleTranslate(lang.code);
+ return false;
+ },
+ };
+ });
const items = [...dropdownItemsBefore, ...localeItems, ...googleItems,
...dropdownItemsAfter];
+
const dropdownLabel = mobile
? translate({
message: 'Languages',
id: 'theme.navbar.mobileLanguageDropdown.label',
description: 'The label for the mobile language switcher dropdown',
})
- : localeConfigs[currentLocale].label;
+ : currentLangLabel;
return (
<DropdownNavbarItem
{...props}
mobile={mobile}
+ className="notranslate"
label={
<>
<div id="google_translate_element" style={{ visibility:
'hidden', height: 0, overflow: 'hidden', position: 'absolute' }} />
diff --git a/static/js/google_translate_init.js
b/static/js/google_translate_init.js
index 5826a162ad1d..c8b41ed4f63a 100644
--- a/static/js/google_translate_init.js
+++ b/static/js/google_translate_init.js
@@ -3,7 +3,8 @@ function googleTranslateElementInit() {
{
pageLanguage: "en",
// Only languages NOT provided by native Docusaurus i18n
- includedLanguages: "zh-CN,ja,ko,fr,es,ru,de",
+ // en and zh-CN are handled by Docusaurus natively
+ includedLanguages: "ja,ko,fr,es,ru,de",
autoDisplay: false,
},
"google_translate_element"