From 1cd1698727fa8c93b10a9c97339d954410614927 Mon Sep 17 00:00:00 2001 From: Hyan Mandian <5044101+hyanmandian@users.noreply.github.com> Date: Tue, 22 Sep 2026 02:00:23 -0300 Subject: [PATCH] fix(docs): the language switch keeps the page the reader is on `_navbar.md` links to `/` and `/pt-br/`, so switching the language from anywhere in the site dropped the reader on a home page and made them find their way back. The navbar now points each of its two links at the page on screen in that language, on every route change: `/utilities` and `/pt-br/utilities` stand for each other, and the query string and the anchor go along, so a reader following a deep link keeps their place. The link of the language being read carries `aria-current` and the class docsify already styles as the active navbar entry. Both trees hold the same pages, page for page, which is what `scripts/site.ts` already asserts in every hreflang link and in the sitemap, so a translated route is a page that answers. The home pages are the exception, since they are not translations of each other (`/` is the README and `/pt-br/` shows pt-br/getting-started through `alias`), and so is a route no language has: both send the reader to the other language's home instead of to a URL known to be missing. The links are rewritten in place rather than written as markup, so `_navbar.md` stays the source of the labels and their order; docsify answers its own navbar request after the hook on some routes, so the navbar is watched and written again whenever it comes back from the Markdown. --- docs/index.html | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/index.html b/docs/index.html index 296c5375..97faf885 100644 --- a/docs/index.html +++ b/docs/index.html @@ -315,6 +315,71 @@ show(); }); }, + // The two language links of the navbar, pointed at the page on screen: switching the + // language keeps the route, its query string and its anchor (/utilities becomes + // /pt-br/utilities and back), instead of sending the reader to a home page. `_navbar.md` + // stays the source of the labels and of their order, and the link of the language being + // read is marked the way docsify marks an active navbar entry; only the `href` changes, + // so the navbar is still what the Markdown says. + // Every page exists in both languages (the `_sidebar.md` of each lists the same pages, + // and `scripts/site.ts` pairs them one by one in the hreflang links and in the sitemap), + // so the translated route is a page that answers. The two exceptions go to the other + // language's home: the home pages, which are not translations of each other (`/` is the + // README and `/pt-br/` shows pt-br/getting-started through `alias`), and a route no + // language has, where docsify shows its 404 view and there is nothing to translate. + function (hook, vm) { + var HOME = { 'en': '/', 'pt-br': '/pt-br/' }; + // Where each link points for the page on screen, and which language that page is in. + var destination = { 'en': HOME['en'], 'pt-br': HOME['pt-br'] }; + var reading = 'en'; + var watched = []; + // The language a navbar link switches to, from the href `_navbar.md` gives it, kept on + // the element so the link is still recognised once its href points at a page. + function languageOf(link) { + var href = link.getAttribute('href'); + return link.dataset.language || (href === HOME['pt-br'] ? 'pt-br' : href === HOME['en'] ? 'en' : ''); + } + // The same route in a language, the home pages standing in for each other. + function translate(path, language) { + var english = path.replace(/^\/pt-br(?=\/|$)/, '') || '/'; + return english === '/' ? HOME[language] : language === 'pt-br' ? '/pt-br' + english : english; + } + function rewrite() { + var links = document.querySelectorAll('.app-nav a[href], .app-nav-merged a[href]'); + [].forEach.call(links, function (link) { + var language = languageOf(link); + if (!language) return; + link.dataset.language = language; + link.setAttribute('href', destination[language]); + if (language === reading) link.setAttribute('aria-current', 'page'); + else link.removeAttribute('aria-current'); + (link.closest('li') || link).classList.toggle('active', language === reading); + }); + } + hook.doneEach(function () { + // docsify's history router leaves an anchor written as `#` in the path and reads one + // of its own from `?id=`; the page keeps both as the reader has them, and the route + // is translated without the fragment. + var path = ((vm.route && vm.route.path) || '/').replace(/#.*$/, ''); + var missing = !!(vm.route && vm.route.response && vm.route.response.ok === false); + reading = /^\/pt-br(\/|$)/.test(path) ? 'pt-br' : 'en'; + // A home page has no counterpart to carry the place in the page to. + var within = missing || translate(path, reading) === HOME[reading] ? '' : location.search + location.hash; + Object.keys(HOME).forEach(function (language) { + destination[language] = missing ? HOME[language] : translate(path, language) + within; + }); + rewrite(); + // docsify renders the navbar from its own request, which on some routes answers after + // this hook and puts the Markdown's links back; the navbar is written again whenever + // that happens, from the same destinations. Watching what the links say, rather than + // holding the navbar's markup, leaves `_navbar.md` in charge of it. + [].forEach.call(document.querySelectorAll('.app-nav, .app-nav-merged'), function (nav) { + if (watched.indexOf(nav) !== -1) return; + watched.push(nav); + new MutationObserver(rewrite).observe(nav, { childList: true, subtree: true }); + }); + }); + }, // Per-page metadata for search engines and link previews: the title, description, // canonical URL, language and hreflang pair of the page being shown, from its front // matter and route. The generated copies of this shell carry the same values statically