-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathlanguage-toggle.js
More file actions
143 lines (119 loc) · 4.33 KB
/
language-toggle.js
File metadata and controls
143 lines (119 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* Language Toggle Script
*
* Enables smart navigation when switching between Python and TypeScript docs.
* When a user clicks the language dropdown, this redirects them to the equivalent
* page in the target language (preserving the section hash) instead of the default
* overview page.
*
* How it works:
* 1. Click listener detects language toggle clicks and stores current URL+hash
* 2. History API interception (pushState/replaceState) and popstate/hashchange
* listeners detect when Mintlify's client-side routing changes the path
* 3. On path change, check if we're switching languages and redirect to equivalent page
*/
(function () {
"use strict";
const PYTHON_PREFIX = "/oss/python/";
const JS_PREFIX = "/oss/javascript/";
// Selector for language dropdown items (Python/TypeScript links)
const LANGUAGE_TOGGLE_SELECTOR = "[data-dropdown-item]";
let previousUrl = null;
/**
* Convert a path from one language to another
* e.g., /oss/javascript/foo → /oss/python/foo
*/
function getEquivalentPath(sourcePath, targetLang) {
const sourcePrefix = targetLang === "python" ? JS_PREFIX : PYTHON_PREFIX;
const targetPrefix = targetLang === "python" ? PYTHON_PREFIX : JS_PREFIX;
if (sourcePath.startsWith(sourcePrefix)) {
return targetPrefix + sourcePath.substring(sourcePrefix.length);
}
return null;
}
/**
* Detect which language a path belongs to
* Returns "python", "javascript", or null
*/
function getPathLanguage(path) {
if (path.startsWith(PYTHON_PREFIX)) return "python";
if (path.startsWith(JS_PREFIX)) return "javascript";
return null;
}
/**
* Store current URL (path + hash) in memory
* Only stores language-specific pages
*/
function updateCurrent() {
const lang = getPathLanguage(location.pathname);
if (lang) {
previousUrl = location.pathname + location.hash;
}
}
/**
* Check if we should redirect to an equivalent page in a different language
* This runs after every path change detected by the MutationObserver
*/
function checkRedirect() {
const currentLang = getPathLanguage(location.pathname);
if (!currentLang) return;
if (!previousUrl) {
updateCurrent();
return;
}
// Split path and hash (e.g., "/oss/python/foo#bar" → ["/oss/python/foo", "bar"])
const [prevPath, prevHash = ""] = previousUrl.split("#");
const prevLang = getPathLanguage(prevPath);
// Only redirect if we're switching between languages
if (prevLang && prevLang !== currentLang) {
const equivalentPath = getEquivalentPath(prevPath, currentLang);
if (equivalentPath && equivalentPath !== location.pathname) {
// Clear previous URL before redirect to prevent redirect loops
previousUrl = null;
// Redirect with the hash from the previous page
location.replace(equivalentPath + (prevHash ? "#" + prevHash : ""));
return;
}
}
// If no redirect needed, store current location for next navigation
updateCurrent();
}
// Store current URL when language toggle is clicked
// This captures the hash before Mintlify's client-side routing changes the page
document.addEventListener(
"click",
function (e) {
const toggle = e.target.closest(LANGUAGE_TOGGLE_SELECTOR);
if (toggle) {
updateCurrent();
}
},
true,
);
// Watch for URL changes via History API (used by Mintlify's client-side routing)
// This is more efficient than MutationObserver - only fires on actual URL changes
let lastPath = location.pathname;
function onPathChange() {
if (location.pathname !== lastPath) {
lastPath = location.pathname;
checkRedirect();
}
}
// Handle back/forward navigation
window.addEventListener("popstate", onPathChange);
// Handle hash changes (when user clicks anchor links)
window.addEventListener("hashchange", onPathChange);
// Intercept pushState/replaceState calls
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function (...args) {
originalPushState.apply(this, args);
onPathChange();
};
history.replaceState = function (...args) {
originalReplaceState.apply(this, args);
onPathChange();
};
// Run initial check in case user landed here via language toggle
checkRedirect();
})();