Skip to content

Refactor: locale-aware VMs, dictionary-driven views, and TopPage decomposition#303

Merged
zigzagdev merged 15 commits intochore/create-language-contextfrom
chore/refactor-language-ja
May 2, 2026
Merged

Refactor: locale-aware VMs, dictionary-driven views, and TopPage decomposition#303
zigzagdev merged 15 commits intochore/create-language-contextfrom
chore/refactor-language-ja

Conversation

@zigzagdev
Copy link
Copy Markdown
Owner

@zigzagdev zigzagdev commented May 2, 2026

Content

  • Threads Locale through the heritage VM mappers so English mode no longer falls back to Japanese strings, and adds displayName / displaySubName / displayDescription so view components can drop
    their own locale === "ja" branches.
  • Pulls every visible string in the heritage detail panel, search form, top-page header, and result list out into the useText() dictionary; adds dictionary entries for both en and ja, plus per-value lookup tables for Category (Cultural / Natural / Mixed) and Region (Africa / Asia / Europe / …).
    • Decomposes TopPage into TopPageTitleBar, HeritageList, and TopPagePagination, leaving TopPage as a thin slot-based shell with four ReactNode slots and no named Props type. Extracts the locale flag toggle into a shared <LocaleToggle /> and reuses it in both the top page and the detail layout.
    • Cleans up Props placement in .tsx files: drops export type ...Props from TopPage, HeritageSubHeader, HeritageMetadataList, and SearchResultsPage; renames useText() results from t to
      text throughout the detail components.

Locale plumbing (mappers + hooks)

  • toWorldHeritageVm / toWorldHeritageDetailVm / toHeritageSearchResultVm now take a locale argument and resolve title, subtitle, country, and the new displaySubName / displayDescription
    fields per locale.
  • use-top-page and use-world-heritage-detail read locale via useLocale() and feed it to the mappers; SearchHeritageResultsContainer does the same.
    • Renamed the previously misnamed to-world-heritage-detail-vm-test.ts to .test.ts so it actually runs in Jest, and updated assertions for the new signature.

Dictionary-driven views

  • New ui-text keys for sidebar labels, the search form, sort/reload controls, the locale toggle, app title/tagline, plus categoryLabels and regionLabels lookup tables. ja labels follow common Japanese heritage-site wording (e.g. 保有国, 分類, 遺産の面積, 文化遺産 / 自然遺産 / 複合遺産).
  • HeritageSidebar, HeritageDetailLayout (KeyExamInfo), HeritageHero, HeritageOverviewSection,HeritageSearchForm, and TopPageTitleBar now read every label, placeholder, aria-label, and value from useText(). The brand string World Heritage is intentionally left untranslated in ja.

Structural cleanup

  • New components: TopPageTitleBar, HeritageList, TopPagePagination, LocaleToggle. TopPage becomes { titleBar, header?, content, pagination? } of ReactNodes.
  • TopPageContainer now constructs each subcomponent and wires it in.
  • Test mocks for TopPageContainer retargeted at the new subcomponents.
  • Dropped exported view-Props types in tsx files; renamed ttext for useText() consumers.

Notes

  • Search results page Region/Category enum values (Asia, Cultural, …) used in the map popup and HeritageCard chip are still in English; out of scope for this PR.
  • Locale is still resolved from the lang query param (e.g. ?lang=ja); switching to a path prefix is tracked separately.

Test plan

  • npm run typecheck passes
  • npm test passes (13 suites / 65 tests)
  • Manual: open /heritages with ?lang=ja and ?lang=en, toggle via the new LocaleToggle, confirm header / search form / cards / detail panel / sidebar all switch.
  • Manual: navigate /heritages/:id, confirm title / subtitle / overview / sidebar metadata are localized, and that the brand World Heritage stays English in both locales.
    このまま貼ればそのまま使えます。base ブランチは main 想定で書いてあります (もし develop 等なら適宜)。

zigzagdev and others added 15 commits May 2, 2026 12:51
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the inline REGION_LABELS / CATEGORY_LABELS constants and pull every
visible string (chip headings, placeholders, aria-labels, the search
button) from useText. The empty option falls back to text.all; the
other options reuse the existing categoryLabels / regionLabels dicts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…onents

Pull TopPage's title row, items grid, and pagination block out into
TopPageTitleBar, HeritageList, and TopPagePagination. TopPage becomes a
thin slot-based shell taking { titleBar, header, content, pagination }
as ReactNodes; the container builds each subcomponent and wires them in.
The 13-field TopPage Props collapses to four ReactNode slots inlined
on the signature, so the named type is gone. Test mocks for TopPage and
its callers are retargeted at the new subcomponents.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pull the locale switch button (the flag toggle) out into a shared
LocaleToggle component under shared/locale and use it in both
HeritageDetailLayout and TopPageTitleBar instead of duplicating the
inline button. The detail layout no longer needs useLocale directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add appTitle and appTagline keys to en/ja ui dictionaries and read them
in TopPageTitleBar via useText, replacing the hardcoded "World Heritage"
heading and "Learn by searching..." subheading.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zigzagdev zigzagdev self-assigned this May 2, 2026
@zigzagdev zigzagdev linked an issue May 2, 2026 that may be closed by this pull request
Copy link
Copy Markdown
Owner Author

@zigzagdev zigzagdev left a comment

Choose a reason for hiding this comment

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

LGTM

@zigzagdev zigzagdev merged commit 4e696f2 into chore/create-language-context May 2, 2026
1 check passed
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.

Refactor: Introduce LanguageContext to eliminate prop drilling

1 participant