Skip to content

fix(docs): the language switch keeps the page the reader is on - #590

Merged
hyanmandian merged 1 commit into
mainfrom
claude/docs-language-switch
Sep 22, 2026
Merged

hyanmandian merged 1 commit into
mainfrom
claude/docs-language-switch

Conversation

@hyanmandian

@hyanmandian hyanmandian commented Sep 22, 2026

Copy link
Copy Markdown
Member

What

Switching the language on the documentation site sent the reader to a home page: docs/_navbar.md
links to / and /pt-br/, and those are the only two URLs the navbar ever had. The switch now
keeps the page on screen: /utilities and /pt-br/utilities stand for each other, and the query
string and the anchor go along, so a reader who followed a deep link keeps their place.

A small docsify plugin in docs/index.html, in the shape of the ones already there, rewrites the
two links on every route change (hook.doneEach).

Shape, and why

  • The links are rewritten, the navbar is not replaced. _navbar.md stays the source of the
    labels, their order and their language names; only each href changes. A link is recognised by
    the href the Markdown gives it (/ is English, /pt-br/ is Portuguese) and remembers its
    language in a data-language attribute, so it is still recognised once it points at a page, and
    any other link someone adds to the navbar later is left alone.
  • The navbar is watched. docsify requests _navbar.md on its own, and on some routes that
    request answers after doneEach and puts the Markdown's links back (reproduced below on the
    browser's back button and on /). The plugin observes the navbar and writes the links again
    from the same destinations whenever docsify re-renders it. This is why the plugin keeps the
    route it computed in a closure instead of only acting inside the hook.
  • The anchor. docsify writes its own anchors as ?id=, and a link from outside may carry a
    #; both are carried over. The history router leaves a # fragment inside route.path, so the
    path is translated without it (otherwise the fragment ended up in the href twice).
  • The active language is indicated with aria-current="page" and the active class docsify
    already styles for a navbar entry (.active :is(.app-nav a) in its core theme), so it needs no
    new CSS: the language being read shows in the theme green.

The page that does not exist in the other language

Checked rather than assumed: the two trees hold the same pages, page for page
(docs/_sidebar.md and docs/pt-br/_sidebar.md list getting-started, utilities, the four guides
and the v1-to-v2 migration; docs/ and docs/pt-br/ hold the same Markdown files). That pairing
is already asserted elsewhere: scripts/site.ts writes an hreflang pair and a sitemap entry for
every page on exactly this rule. So a translated route is a page that answers, and the link is
kept as is
; if it ever 404s, the sitemap and the hreflang links are wrong too, and that is a
docs bug to fix rather than something the navbar should paper over.

Two routes have no translation, and both send the reader to the other language's home:

  • The home pages, which are not versions of each other: / is the README and /pt-br/ shows
    pt-br/getting-started through alias. //pt-br/, which is also what the alias config
    requires — never /pt-br/README or a bare /pt-br. The place within the page is dropped here,
    since it is a different document.
  • A route no language has, where docsify shows its 404 view: there is nothing to translate, so
    instead of offering a second URL that is known to be missing, both links become the home pages
    and the reader has a way out.

Verification

Built the site (npm run build:docs) and served docs/ locally the way GitHub Pages does
(a static server resolving /page to page.html), then drove headless Chrome over the DevTools
protocol, clicking the real navbar links. Observed, for each step, the URL, <html lang>, the
rendered <h1> and both navbar links:

step after URL h1 English href Português href
1 load /utilities /utilities Utilities /utilities (current) /pt-br/utilities
1b click Português /pt-br/utilities Utilitários /utilities /pt-br/utilities (current)
1c click English /utilities Utilities /utilities (current) /pt-br/utilities
2 load /getting-started?id=bundle-size same Getting Started /getting-started?id=bundle-size (current) /pt-br/getting-started?id=bundle-size
2b click Português /pt-br/getting-started?id=bundle-size Introdução /getting-started?id=bundle-size /pt-br/getting-started?id=bundle-size (current)
3 load /getting-started#bundle-size same /getting-started#bundle-size (current) /pt-br/getting-started#bundle-size
3b click Português /pt-br/getting-started#bundle-size /getting-started#bundle-size /pt-br/getting-started#bundle-size (current)
4 load / / Getting Started (README) / (current) /pt-br/
4b click Português /pt-br/ Introdução / /pt-br/ (current)
4c click English / Getting Started / (current) /pt-br/
5 load /guides/schema /guides/schema Schema libraries /guides/schema (current) /pt-br/guides/schema
5b click Português /pt-br/guides/schema Bibliotecas de schema /guides/schema /pt-br/guides/schema (current)
6 load /pt-br/does-not-exist same 404 - Not Found / /pt-br/ (current)
7b Português into a pt-br page made to 404 /pt-br/utilities 404 - Not Found / /pt-br/ (current)
7c click English from that 404 / Getting Started / (current) /pt-br/
8b /utilities → Português /pt-br/utilities Utilitários /utilities /pt-br/utilities (current)
8c browser back /utilities Utilities /utilities (current) /pt-br/utilities

(current) is the link carrying aria-current="page" and the active class.

Step 7 is the case the tree does not actually have: the local server was told to answer 404 for
/pt-br/utilities.md while the English page stayed, which is what a page missing from the other
tree would look like. The link is kept and the reader lands on docsify's 404 view (documented
choice above), and the navbar there offers both home pages, which is how 7c gets back.

Nothing else moved: on /utilities the sidebar still has its 178 links with "Utilities" marked
aria-current and active, and a search for CPF still returns its 39 results with CPF first.
The canonical/hreflang hook is untouched (this plugin only reads vm.route), npm run build:site
regenerates the page shells from the edited index.html with no other diff, and the generated
files stay out of the repository as .gitignore and CONTRIBUTING require.

Before the change, on the same build from main: /utilities, /getting-started?id=bundle-size
and /getting-started#bundle-size all showed ["/", "/pt-br/"] in the navbar, which is the bug.

Open points

  • A raw #fragment URL (/getting-started#bundle-size, step 3) renders the page shell instead of
    the page: docsify's history router keeps the fragment in the route path and fetches
    getting-started#bundle-size.md, which the browser sends as /getting-started. This is what
    main does too (verified on the same build without the plugin) and is left alone here; the
    navbar link is at least correct now. docsify's own anchors (?id=, step 2) are unaffected.
  • The anchor is carried over as written. Headings are translated, so ?id=bundle-size has no twin
    in pt-br/getting-started (?id=tamanho-do-bundle is the Portuguese one): the reader lands on
    the right page at the top, which is what docsify does with an id it cannot find.
  • On the 404 view of a /pt-br/... URL the Portuguese link is the one marked as current, since
    that is the tree the URL is in, while the metadata hook leaves <html lang> alone for a page
    that does not exist. Cosmetic, and only on the 404 view.
  • Chrome was driven over the DevTools protocol because the Claude-in-Chrome extension did not
    answer in this session. Screenshots of the English and Portuguese navbars were taken locally
    (en-utilities.png, pt-utilities.png); GitHub has no way to attach them from the CLI.
  • CI: every check passes except Tree-shaking report, which fails before it reaches this
    change. That job checks the base commit out into base/ inside the head tree and then runs
    npm run build; tsconfig.json excludes docs, which does not match base/docs, so the build
    type-checks base/docs/snippets/document-field/_templates/*.ts, the templates that are not
    valid TypeScript on their own. Every error in the log is in that folder, which this branch does
    not touch, and npm run build passes here. fix(build): the document field templates stop breaking the package build #588 is the fix for it (it renames the templates to
    .tmpl); this job goes green on a re-run once that lands.

`_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.
@hyanmandian

Copy link
Copy Markdown
Member Author

@coderabbitai review

@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
brazilian-utils Ready Ready Preview Sep 22, 2026 5:01am UTC

@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: c4dec1f1-2b47-4f90-ada0-92a6b8d86240

📥 Commits

Reviewing files that changed from the base of the PR and between bdd4e26 and 1cd1698.

📒 Files selected for processing (1)
  • docs/index.html

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

Docsify now synchronizes English and Portuguese navbar links with the current route. It preserves query strings and anchors, applies language-specific fallbacks, updates active link state, and reapplies changes after navbar mutations.

Changes

Language-aware navbar routing

Layer / File(s) Summary
Navbar route synchronization
docs/index.html
The Docsify plugin derives language-specific routes, preserves query strings and anchors, applies homepage fallbacks, updates href, active classes, and aria-current, and observes navbar rerenders.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: claude

Merge Risk: ⚪ Minimal · up to 1cd16

This documentation-only change improves language navigation while preserving route context, and no actionable production risk is currently identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preserving the reader's current documentation page when switching languages.
✨ Finishing Touches 💡 1
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pkg-pr-new

pkg-pr-new Bot commented Sep 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@brazilian-utils/brazilian-utils@590

commit: 1cd1698

@codecov

codecov Bot commented Sep 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (bdd4e26) to head (1cd1698).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #590   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          186       186           
  Lines         2069      2069           
  Branches       613       613           
=========================================
  Hits          2069      2069           
Flag Coverage Δ
node 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hyanmandian
hyanmandian merged commit ce2df9c into main Sep 22, 2026
29 of 30 checks passed

This branch was successfully deployed

1 active deployment
Preview 1cd16987 Deployed Sep 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant