OINK 1.5.0 — Read translations side by side
OINK 1.5.0 adds an opt-in Bilingual View for multilingual sites. Readers, authors, and translators can open a page beside one of its existing translations and keep both panes aligned near the same section. The feature is off by default, so sites that do not enable it keep the exact same rendered pages and outputs as before. This documentation site is now running on OINK 1.5.0 with Bilingual View enabled across its Docs and blog pages—press B or click Open bilingual view at the top of this page to try it right now.
Bilingual View
Enable it with a single site setting:
Every Docs, Book, and blog page that has a published HTML translation on the same origin then shows Open bilingual view beside the page actions. Readers can also launch Bilingual View from the command palette or press B when keyboard navigation is enabled. The current page stays on the reading-start side while the other pane loads a translation selected from the target-language menu.
Sync Scroll matches shared visible heading IDs and interpolates smoothly
between them. Even when one translation is longer or includes an extra
subsection, both panes stay aligned section by section. Partial matches use the
available anchors and display an approximate-sync note; when two pages share no
usable headings, the reader estimates position from overall reading progress. If
heading IDs are duplicated or appear in a different order across languages,
Sync Scroll turns off automatically while leaving both panes open for
independent reading. Keep explicit {#id} anchors aligned across translations,
as described in the multilingual guide, for the
best experience.
Bilingual View loads the two existing HTML pages inside same-origin frames only when a reader opens it. Each pane keeps its own language, text direction, tabs, tables, diagrams, footnotes, and interactive components while suppressing duplicate shell navigation, search, comments, and analytics. No language-pair pages, new layouts, or extra output formats are generated at build time. Print, Markdown, and feed outputs remain unchanged.
Responsive reading and accessibility
On viewports narrower than 900px, the reader switches to a compact toolbar row
and a language switcher bar that displays one retained pane at a time. The
switcher bar also holds the target-language menu so pane titles are not
repeated. Even on short, high-zoom viewports (320 × 256 CSS pixels, roughly
400% browser zoom), at least 160px of vertical reading space remains visible
without horizontal scrolling.
Right-to-left host pages place the current page on the right (the reading-start
side) and the target translation on the left. Resizing across the 900px
breakpoint moves the target-language menu between the desktop pane header and
the mobile switcher bar without losing keyboard focus, menu state, or the
active pane. Forced-colors mode highlights the active pane with a clear border,
and the B shortcut and aria-keyshortcuts attribute are exposed only when
keyboard navigation is enabled and a translation target exists.
Language and analytics boundaries
Individual languages can opt out by setting compare: false under
languages.<lang>.params.ui. An opted-out language never displays the
Bilingual View button and is never offered as a target language from other
pages. Pages without a same-origin translation, unpublished drafts,
language-home fallbacks, and translations hosted on external domains are
excluded automatically.
Custom scripts added through hooks/head-end.html execute inside each pane
frame. Analytics snippets placed there should skip pane loads by checking
window.OinkComparePane, as shown in
Analytics and SEO. Theme-managed
analytics (services.googleAnalytics.id and params.analytics.*) skips panes
automatically; when params.ui.compare: true is active, OINK renders Google
Analytics through its own pane-aware template rather than Hugo’s built-in
google_analytics.html partial.
If your site sends a Content Security Policy, allow same-origin frames with
frame-src 'self' and make sure your server does not block same-origin framing
with X-Frame-Options: DENY or frame-ancestors 'none'. See the
deployment guide for details.
Browser navigation and history
Opening Bilingual View pushes a single browser history entry. Clicking Close, pressing Escape, or using browser Back closes the reader and restores your scroll position and focus on the host page. If an interactive component such as a diagram viewer or expanded table is open inside a pane, Escape closes that inner dialog first before closing Bilingual View.
Reloading the page while Bilingual View is open—or returning to it with browser
Forward—reopens the reader on the existing history entry rather than pushing
a duplicate record, so a single Back step always returns to regular reading.
In-page #anchor links scroll within their pane without adding history entries,
links to other pages on the site exit Bilingual View and navigate normally, and
external links open outside the frame.
Upgrade
Use Hugo Extended 0.168.0 and Go 1.27.3. Theme styles continue to compile with Hugo’s built-in LibSass.
Commit the updated go.mod and go.sum. Refresh vendored or copied theme
files separately. Keep Hugo’s LibSass deprecation warning visible and review
other diagnostics; do not enable --panicOnWarning or
HUGO_PANICONWARNING.
Existing content and configuration need no migration. The new interface labels are translated in all 32 catalogs. The upgrade guide covers validation, CSP, analytics, and rollback.
