Skip to content

WEBDEV-9219: Localize the topnav strings - #125

Merged
jbuckner merged 21 commits into
mainfrom
WEBDEV-9219-localize-topnav
Oct 8, 2026
Merged

jbuckner merged 21 commits into
mainfrom
WEBDEV-9219-localize-topnav

Conversation

@jbuckner

@jbuckner jbuckner commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #95 (WEBDEV-9038), which brings the topnav into elements. Merge that first. This targets its branch and I'll retarget to main once it lands.

The topnav is on every page and none of it was translated, including the accessible names, so a screen reader read English over Spanish content.

37 strings across 10 components now go through msg(), and every topnav component that calls msg() has @localized(), so a locale switch after first render re-renders them. A few needed more than a wrapper:

  • ia-topnav-media-menu: the top-level buttons (Texts, Video, Audio, Software, Images, Donate, More) came from a module-scope array, which would freeze the labels at import. It's a function called at render now. Wayback Machine stays unwrapped (product name).
  • ia-topnav-media-button built its tooltip as ${prefix} ${mediatype} menu. Word order differs by language, so it's one whole phrase per state with the mediatype as a placeholder.
  • ia-topnav-primary-nav's user menu tooltip was a ternary over two bare strings. Each branch is its own message.
  • ia-topnav-wayback-search's intro is one sentence with a count and a link, so it uses msg(html...) with the anchor as a placeholder.
  • "1 trillion" was a default in the module-scope defaultTopNavConfig. It's msg('1 trillion') in the wayback search's render now, used when the host passes no count. The search's own '916 billion' default is gone too.
  • dropdown-menu's "New feature: <title>" callout aria-label wasn't wrapped.

Also dropped the literal double quotes inside the mobile donate link's sr-only span. They were read out as part of the accessible name.

Checked

  • typecheck and lint clean. 861 tests pass.
  • ia-topnav-localization.test.ts sets a test-only pseudo-locale after first render and checks the media buttons, a component string, the callout label and the page count. It fails if @localized() is removed or the media menu array goes back to module scope.

Not here

  • data/menus.ts menu labels. WEBDEV-9221, stacked on this.
  • The 15 shared icon constants carry their own <title>/<desc> and are module-scope html templates. WEBDEV-9222. That's why the hamburger's closed state is localized and its opened state, which uses the shared close icon, isn't.
  • No XLIFF or translations. That's WEBDEV-9226 (WEBDEV-9226: Set up string extraction and publish locale data #129), so none of this shows Spanish yet.

WEBDEV-9219: https://webarchive.jira.com/browse/WEBDEV-9219

🤖 Generated with Claude Code

https://claude.ai/code/session_01N6GtWdx3xKytP8c8CLtpAX

jbuckner and others added 9 commits September 10, 2026 11:21
Ports ia-topnav out of the iaux monorepo as ia-topnav, with every
sub-element namespaced ia-topnav-* so it can't collide with the copies
petabox and offshoot still load. element-names.test.ts holds that line:
it checks the new names register and that all 17 generic names the old
package claims stay free, since both packages load during the migration
and a duplicate define throws rather than degrading.

Ported from the WEBDEV-9036 branch rather than iaux master, so the
uploader and biblio admin sections are here from the start. That PR
touches most of what this move carries, so porting master would have
meant doing the same work twice.

No dependencies added, two dropped. ia-wayback-search only supplied a
base class, and importing it registered the generic ia-wayback-search
tag as a side effect, so it's one flattened element now. ia-styles only
supplied the sr-only block, which is now a shared style in themes.

Per-component style modules became inline styles, which is what every
other element here does. The shared subnav fragment keeps a plain name
at the component root. The user menu and signed-out dropdown returned
exactly the base class's styles, and Lit already inherits those, so the
overrides are gone.

Three things dropped as dead: the ia-icon element, which nothing
imported or rendered and which squatted a generic name; a write-only
state field on the login button; and the redundant style overrides
above.

Two bugs came out of the move. Two tests had every assertion commented
out, so they passed while checking nothing; both are rewritten against
real behavior, taking the component from 52 tests to 94. And the
wayback search's desktop icon read a variable nothing sets, with no
fallback, so its fill resolved to invalid and painted black against the
dark nav. It follows the topnav's own icon color now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpyQxVSkZFrWxxGamCcNhY
Four assertions used `to.not.be.undefined` on a querySelector result.
querySelector returns null, so they passed whether or not the element
was found. Switching them to `to.exist` failed two tests that had never
actually run:

The wayback test looked for the search inside the web subnav, but the
subnav renders the slider and the search sits one level inside that.
The selector never matched.

The login button test clicked the toggle and expected an active class.
The button owns no open state; it reports the click and the parent sets
openMenu. Standalone it can never go active. It now checks both halves
of that contract, the event on click and the class once openMenu is set.

The dropdown-menu test also registered the base class as `dropdown-menu`
at module scope, a name element-names.test.ts asserts stays free. Both
only passed because vitest isolates each file in its own page, so
turning isolation off would have failed one of them depending on load
order. The base class is registered nowhere in the source, so the test
now mounts it under a tag inside the topnav's own namespace.

Also drops a comment that explained the icon fill by contrast with its
old package, and moves the wayback search to the getter form of styles
that every other element here uses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpyQxVSkZFrWxxGamCcNhY
The topnav's :host declares every other color knob, but this one had
gone missing, so the nested wayback search read an undefined variable
and the desktop glyph painted black. The package README still documents
it as var(--grey20), which is what it goes back to. The search keeps a
fallback to the topnav's general icon color for the case where it is
mounted on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpyQxVSkZFrWxxGamCcNhY
The fallback only fires when the search is mounted outside a topnav,
and in that case none of the topnav's greys are declared either, so a
var() fallback is as unresolved as the value it was covering for. fill
inherits, so that paints black rather than falling through. A literal
is the only fallback that actually does anything there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpyQxVSkZFrWxxGamCcNhY
…opnav

* origin/main:
  v0.3.0 (#96)
  WEBDEV-8969: Migrate radio-player into elements (#86)
  WEBDEV-8974: Migrate the radio player search handler into elements (#85)
  WEBDEV-8968: Migrate transcript-view into elements (#84)
  WEBDEV-8967: Migrate expandable-search-bar into elements (#83)
  WEBDEV-8966: Migrate scrubber-bar into elements (#82)
  WEBDEV-8965: Migrate playback-controls into elements (#80)
  WEBDEV-8964: Migrate waveform-progress into elements (#78)
  WEBDEV-8963: Migrate audio-element into elements (#77)

# Conflicts:
#	src/elements/index.ts
Vitest writes these under .vitest-attachments when a test attaches an
image, so they are run output, not source. main already ignores the
directory, but .gitignore only applies to untracked files and these had
already been committed here, so the rule never caught them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaEr5YT1xpjK5ydNZPvjwx
…opnav

* origin/main:
  1.1.1 (#118)
  WEBDEV-9132: Fix Safari image-viewer wide-layout breakpoint (#115)
  1.1.0 (#116)
  WEBDEV-9129: Exclude story files from coverage reporting (#113)
  WEBDEV-9121: Migrate histogram-date-range into elements (#112)
  WEBDEV-9130: Exclude nested dist and worktree tests from local runs (#114)
  v1.0.0 (#111)
  WEBDEV-9025: Add a CLAUDE.md covering the publish flow (#94)
  WEBDEV-9063: Typecheck in CI (#107)
  v0.4.1 (#108)
  WEBDEV-9066: Guard custom element registration against duplicate defines (#106)
  v0.4.0 (#99)
  WEBDEV-9022: Migrate the image viewer into elements (#93)
The topnav is on every page and none of it was translated. It never imported
@lit/localize, so switching to Spanish left the whole header in English,
including the accessible names, which a screen reader then reads in English
over Spanish content.

28 strings across 8 components now go through msg(). Three needed more than a
wrapper:

- ia-topnav-media-button composed its tooltip as `${prefix} ${mediatype} menu`
  from a getter returning 'Collapse' or 'Expand'. Word order around the
  mediatype differs by language, so that getter becomes a `tooltip` getter
  returning one whole phrase per state with the mediatype as a placeholder.
- ia-topnav-primary-nav's user menu tooltip was a ternary over two bare
  strings; each branch is its own message now.
- ia-topnav-wayback-search's intro is one sentence carrying both a count and a
  link, so it uses msg(html`...`) and the anchor becomes a placeholder rather
  than being split across messages.

The mobile donate link's screen reader label also had literal double quotes
inside the span, which were read out as part of the accessible name. They are
gone.

Not in here:

- data/menus.ts holds 132 menu labels, about 97 of them translatable and the
  rest collection and product names. Which is which needs a decision per
  entry, and buildTopNavMenus() is called by the host rather than at render,
  so the labels would freeze at whatever locale was active then. WEBDEV-9221.
- The 15 shared icon constants in assets/img carry their own <title> and
  <desc> accessible names and are module-scope html templates, so a msg()
  there would resolve once at import. Localizing them means converting them to
  functions and updating their 10 call sites, some outside the topnav.
  WEBDEV-9222. This is why the hamburger's closed state is localized and its
  opened state, which delegates to the shared close icon, is not.

Elements has no lit-localize.json and no @lit/localize-tools, so none of this
extracts yet. Five other components here already call msg() the same way.
Where the translations live is WEBDEV-9218.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjwDQaR3hvZ8J2PP4117W2
@jbuckner
jbuckner added this pull request to stack #126 September 30, 2026 21:00
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-08 18:35 UTC

@codecov-commenter

codecov-commenter commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.41%. Comparing base (d62dd78) to head (d9093c0).

Files with missing lines Patch % Lines
src/elements/ia-topnav/ia-topnav-media-button.ts 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #125      +/-   ##
==========================================
+ Coverage   90.31%   90.41%   +0.10%     
==========================================
  Files          94       94              
  Lines        3334     3339       +5     
  Branches      796      799       +3     
==========================================
+ Hits         3011     3019       +8     
+ Misses        138      137       -1     
+ Partials      185      183       -2     

☔ 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.

jbuckner and others added 4 commits September 30, 2026 14:59
Move only, no behaviour change. In each component the properties come
first, then lifecycles, then render, then the helpers, with styles at
the bottom. A diff review checked it at the class-member level: every
member is byte-identical to before, only its position moved, and
instance fields keep their relative order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjwDQaR3hvZ8J2PP4117W2
- Combine the small lib helpers into lib/helpers.ts with a test, and
  drop the unused makeBooleanFromString and the redundant query handler
  (the wayback search already defaults to the same one).
- Add unit tests for the keyboard navigation.
- Drop sr-only-styles. The hidden input labels become aria-labels and
  the mobile donate heart uses ia-sr-only-text.
- Inline the desktop subnav and hamburger templates into render.
- Build the menus in willUpdate so they're right on the first render.
- Default buildTopNavMenus' userid to '' rather than a placeholder and
  fix its docs.
- Tighten the tests Isa flagged and cover localLinks being set.
- Add an archive.org font size toggle to the topnav demo. It's on when
  the topnav is the element being viewed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjwDQaR3hvZ8J2PP4117W2
… WEBDEV-9219-localize-topnav

* origin/WEBDEV-9038-migrate-topnav:
  WEBDEV-9038: Address review on the topnav migration
  WEBDEV-9038: Put the topnav components' members in house order

# Conflicts:
#	src/elements/ia-topnav/ia-topnav-login-button.ts
#	src/elements/ia-topnav/ia-topnav-media-button.ts
#	src/elements/ia-topnav/ia-topnav-media-subnav.ts
#	src/elements/ia-topnav/ia-topnav-primary-nav.ts
#	src/elements/ia-topnav/ia-topnav-save-page-form.ts
#	src/elements/ia-topnav/ia-topnav-wayback-search.ts
#	src/elements/ia-topnav/ia-topnav-wayback-slider.ts
The top-level media buttons (Texts, Video, Audio, Software, Images, Donate,
More) came from a module-scope array, so their labels would resolve once at
import. They are built by a function at render now, and wrapped in msg().
Wayback Machine stays as is, it's a product name.

None of the topnav components had @Localized(), so a setLocale() after first
render left them in the old language. Every topnav component that calls msg()
has it now, including the dropdown menu base class.

Two more strings:

- The Wayback search's "1 trillion" page count was a default in the
  module-scope config. It is msg('1 trillion') in the search's render now,
  used when the host passes no count. The search's own stale '916 billion'
  default is gone, so it shows the same figure in both places.
- The dropdown's "New feature: <title>" callout aria-label was never wrapped.

A test with a test-only pseudo-locale switches the locale after first render
and checks the media buttons, a component string, the callout label and the
page count. It fails if any of the fixes is reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N6GtWdx3xKytP8c8CLtpAX
…opnav

* origin/main:
  WEBDEV-9230: Make the demo page usable for QA on a phone (#127)
  WEBDEV-9160: Update to pnpm 12 (#119)
  1.1.2 (#121)
  WEBDEV-9192: Make the radio player's waveform music zones opt-in (#120)
… WEBDEV-9219-localize-topnav

* origin/WEBDEV-9038-migrate-topnav:
  WEBDEV-9230: Make the demo page usable for QA on a phone (#127)
  WEBDEV-9160: Update to pnpm 12 (#119)
  1.1.2 (#121)
  WEBDEV-9192: Make the radio player's waveform music zones opt-in (#120)

@nsharma123 nsharma123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code and QA review of WEBDEV-9219.

Checks: all 127 topnav tests pass on the PR branch, and typecheck and lint are clean. lit-localize extract over the topnav files gives 37 messages, with placeholders kept for mediatype, screenName and link.title.

QA: the review-app steps all pass in English. The English → Spanish → English round trip on the WEBDEV-9223 demo restores English cleanly. Two topnav strings are still wrong in Spanish; see the inline comments.

The two bugs should be fixed before merge. The XLIFF placeholder note is minor.

Comment thread src/elements/ia-topnav/ia-topnav-wayback-search.ts
Comment thread src/elements/ia-topnav/ia-topnav-media-button.ts Outdated
Comment thread src/elements/ia-topnav/ia-topnav-wayback-search.ts
jbuckner and others added 4 commits October 6, 2026 15:45
…opnav

* origin/main:
  WEBDEV-9276: Add a slow-test check to CI (#141)
  WEBDEV-9249: Add a language switch to the elements demo (#135)
  WEBDEV-9226: Set up string extraction and publish locale data (#129)
  1.1.5 (#142)
  WEBDEV-9256: Give the focused-story test room for a slow lazy import (#138)
  1.1.4 (#140)
  WEBDEV-9050: Migrate the donation banner thermometer into elements (#97)
  1.1.3 (#139)
  WEBDEV-9138: Fade between modes instead of swapping (#117)
  WEBDEV-9214: Remove the package root export (#124)

# Conflicts:
#	src/elements/index.ts
… WEBDEV-9219-localize-topnav

* origin/WEBDEV-9038-migrate-topnav:
  WEBDEV-9276: Add a slow-test check to CI (#141)
  WEBDEV-9249: Add a language switch to the elements demo (#135)
  WEBDEV-9226: Set up string extraction and publish locale data (#129)
  1.1.5 (#142)
  WEBDEV-9256: Give the focused-story test room for a slow lazy import (#138)
  1.1.4 (#140)
  WEBDEV-9050: Migrate the donation banner thermometer into elements (#97)
  1.1.3 (#139)
  WEBDEV-9138: Fade between modes instead of swapping (#117)
  WEBDEV-9214: Remove the package root export (#124)
…edia tooltips

The count now reaches the Wayback search when the host supplies its own
config, and buildTopNavMenus no longer edits the shared default config.
Media button tooltips are whole phrases per menu instead of embedding the
internal mediatype key.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SaShDa2UqoyBesN4MLf9pA
The story-template applies settings to the first slotted element, which was
a wrapper div, so the Wayback pages archived input never reached ia-topnav.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SaShDa2UqoyBesN4MLf9pA
Base automatically changed from WEBDEV-9038-migrate-topnav to main October 6, 2026 23:28

@nsharma123 nsharma123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 5f544b1 and 6f2fa22, and approving.

  • All 131 topnav tests pass; typecheck and lint are clean. Extraction gives 53 messages, all whole phrases.
  • Review-app QA passes, including Apply for the Wayback count.
  • I checked Spanish with a throwaway test of the offshoot flow: host config plus count, a locale switch, then a host config swap. It passes. The WEBDEV-9223 demo is still pinned to 1.1.3-l10n-demo.2, so it needs a re-pin to show the fix.

FYI, not blocking:

  • buildTopNavMenus dropped a positional parameter. Nothing calls it outside elements today.
  • The story's Wayback input placeholder still says "916 billion".

* origin/main:
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)
@jbuckner
jbuckner merged commit b645127 into main Oct 8, 2026
6 checks passed
@jbuckner
jbuckner deleted the WEBDEV-9219-localize-topnav branch October 8, 2026 18:34
jbuckner added a commit that referenced this pull request Oct 8, 2026
* origin/main:
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
jbuckner added a commit that referenced this pull request Oct 8, 2026
* origin/main:
  1.1.6 (#145)
  WEBDEV-9329: Update the Firefox add-on link in ia-topnav (#143)
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)
  WEBDEV-9038: Migrate the topnav into elements (#95)
jbuckner added a commit that referenced this pull request Oct 8, 2026
* origin/WEBDEV-9107-migrate-reviews:
  1.1.6 (#145)
  WEBDEV-9329: Update the Firefox add-on link in ia-topnav (#143)
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)
  WEBDEV-9038: Migrate the topnav into elements (#95)
jbuckner added a commit that referenced this pull request Oct 8, 2026
* origin/WEBDEV-8840-review-service:
  1.1.6 (#145)
  WEBDEV-9329: Update the Firefox add-on link in ia-topnav (#143)
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)
  WEBDEV-9038: Migrate the topnav into elements (#95)
jbuckner added a commit that referenced this pull request Oct 8, 2026
* origin/main:
  1.1.6 (#145)
  WEBDEV-9329: Update the Firefox add-on link in ia-topnav (#143)
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
jbuckner added a commit that referenced this pull request Oct 8, 2026
… into WEBDEV-9242-localize-ia-dropdown

* origin/WEBDEV-8812-migrate-ia-dropdown:
  1.1.6 (#145)
  WEBDEV-9329: Update the Firefox add-on link in ia-topnav (#143)
  WEBDEV-9241: Add ia-wayback-search-form for the home page Wayback block (#134)
  WEBDEV-9219: Localize the topnav strings (#125)
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)
  WEBDEV-9038: Migrate the topnav into elements (#95)
  WEBDEV-9276: Add a slow-test check to CI (#141)
  WEBDEV-9249: Add a language switch to the elements demo (#135)
  WEBDEV-9226: Set up string extraction and publish locale data (#129)
  1.1.5 (#142)
  WEBDEV-9256: Give the focused-story test room for a slow lazy import (#138)
  1.1.4 (#140)
  WEBDEV-9050: Migrate the donation banner thermometer into elements (#97)
  1.1.3 (#139)
  WEBDEV-9138: Fade between modes instead of swapping (#117)
  WEBDEV-9214: Remove the package root export (#124)
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.

3 participants