Skip to content

Bind withSay to a catalogue in React and Carbon - #107

Merged
k0d13 merged 3 commits into
mainfrom
withsay
Sep 6, 2026
Merged

Bind withSay to a catalogue in React and Carbon#107
k0d13 merged 3 commits into
mainfrom
withsay

Conversation

@k0d13

@k0d13 k0d13 commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Both React and Carbon now bind their withSay to a catalogue, and the examples export their catalogue by name.

@saykit/react (major)

<SayScope> is gone, replaced by createWithSay(catalogue) plus setSay/getSay.

A scope-shaped API cannot work on the App Router: Next renders a page segment before the layout above it, so a layout that establishes the view has not run yet when the page reads it. That is what broke pnpm build in the Next.js example, with 'getSay' must be called below a 'SayScope' while prerendering /en. A scope also forced an extra component split, since the component reading the view had to sit below the one opening it.

Every route segment that renders messages now wraps itself:

// i18n.ts
export const withSay = createWithSay(catalogue);

// app/[locale]/page.tsx
export default withSay(Page, (props) => props.params.then((params) => params.locale));

The view lives in React's per-request cache(), so a concurrent request rendering another locale reads its own. setSay is exported for a caller that already has a view, and warns once per request in development if a second locale takes over.

Next.js example also switched to Next's global LayoutProps/PageProps instead of hand-declared types, dropped a redundant catalogue.match in favour of getSay().locale, and moved the storefront's currency formatting into the ICU message with <Say.Number style="::currency/EUR" />.

@saykit/carbon (major)

withSay is no longer exported on its own. createWithSay(catalogue) returns one bound to the catalogue, so a command takes only its properties mapping:

// i18n.ts
export const withSay = createWithSay(catalogue);

// commands/pick.ts
export class PickCommand extends withSay(Command) {
  constructor() {
    super((say) => ({ name: say`pick`, description: say`What we are reading.` }));
  }
}

The derived-class cache moved inside the binding, so it is per catalogue. The component and modal overload is unchanged, it never took a catalogue. SayPlugin(catalogue) still does, it backs interaction.say and guild.say.

Examples

Every example's i18n.ts now uses export const catalogue instead of a default export, with importers and docs updated to match.

Checks

pnpm check passes across all 19 packages, 750 tests pass, and the Next.js example prerenders /en, /fr and /pl again.

Summary by CodeRabbit

  • New Features

    • Added createWithSay(catalogue) to create reusable, catalogue-bound withSay wrappers.
    • Added setSay(view) for establishing a server-side translation view.
    • Carbon commands no longer require catalogues in their constructors.
  • Bug Fixes

    • Updated the Next.js example to format free-delivery thresholds as EUR currency values.
    • Browser-extension translations now follow the browser’s selected UI language.
  • Documentation

    • Updated guides, examples, and API references for the new server and Carbon integration patterns.

@changeset-bot

changeset-bot Bot commented Sep 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 07d25a8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@saykit/carbon Minor
@saykit/react Minor
@saykit/config Minor
@saykit/format-json Minor
@saykit/format-po Minor
saykit Minor
babel-plugin-saykit Minor
unplugin-saykit Minor
@saykit/transform-js Minor
@saykit/transform-jsx Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Sep 6, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
saykit Ready Ready Preview Sep 6, 2026 6:35am UTC

@github-actions github-actions Bot added examples Updates or additions to example apps tests Modifications, additions, or fixes related to testing package: react Related to @saykit/react package: carbon Related to @saykit/carbon website Updates to the documentation website labels Sep 6, 2026
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 035db55d-742c-4f9a-a122-b1c2c1e4b7f3

📥 Commits

Reviewing files that changed from the base of the PR and between d876745 and 07d25a8.

📒 Files selected for processing (44)
  • .changeset/lucky-pans-fold.md
  • .changeset/witty-moons-shave.md
  • README.md
  • examples/browser-extension/src/i18n.ts
  • examples/browser-extension/src/popup.ts
  • examples/carbon/README.md
  • examples/carbon/src/commands/announce.ts
  • examples/carbon/src/commands/join.ts
  • examples/carbon/src/commands/leaderboard.ts
  • examples/carbon/src/commands/pick.ts
  • examples/carbon/src/i18n.ts
  • examples/carbon/src/index.ts
  • examples/custom-formatter/src/i18n.ts
  • examples/custom-formatter/src/main.ts
  • examples/expo/src/i18n.ts
  • examples/nextjs/README.md
  • examples/nextjs/src/app/[locale]/layout.tsx
  • examples/nextjs/src/app/[locale]/page.tsx
  • examples/nextjs/src/i18n.ts
  • examples/nextjs/src/locales/en.po
  • examples/nextjs/src/locales/fr.po
  • examples/nextjs/src/locales/pl.po
  • examples/react/src/i18n.ts
  • examples/tanstack-start/README.md
  • examples/tanstack-start/src/i18n.ts
  • examples/tanstack-start/src/routes/{-$locale}/route.tsx
  • examples/vanilla/src/i18n.ts
  • examples/vanilla/src/main.ts
  • packages/integration-carbon/README.md
  • packages/integration-carbon/src/mixers/with-say.test.ts
  • packages/integration-carbon/src/mixers/with-say.ts
  • packages/integration-react/README.md
  • packages/integration-react/src/runtime/client.server.ts
  • packages/integration-react/src/runtime/client.ts
  • packages/integration-react/src/runtime/server.test.tsx
  • packages/integration-react/src/runtime/server.ts
  • website/content/core-concepts/runtime.mdx
  • website/content/getting-started/installation.mdx
  • website/content/getting-started/quickstart.mdx
  • website/content/guides/dynamic-loading.mdx
  • website/content/integrations/carbon.mdx
  • website/content/integrations/react.mdx
  • website/content/reference/api/carbon.mdx
  • website/content/reference/api/react.mdx

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The PR replaces SayScope with createWithSay and setSay for React server views. It binds Carbon withSay wrappers to catalogues, removes catalogue constructor arguments, changes catalogue exports to named exports, and updates examples and documentation.

Changes

React server view API

Layer / File(s) Summary
React server view API
packages/integration-react/src/runtime/*, website/content/integrations/react.mdx, website/content/reference/api/react.mdx
The server runtime adds createWithSay and setSay, removes SayScope, and updates tests and documentation for request-established views.

Carbon catalogue binding

Layer / File(s) Summary
Carbon catalogue binding
packages/integration-carbon/*, examples/carbon/*, website/content/integrations/carbon.mdx, website/content/reference/api/carbon.mdx
Carbon binds withSay to a catalogue. Commands now receive only the properties mapping. Tests, examples, and API references use the new construction pattern.

Next.js route integration

Layer / File(s) Summary
Next.js route integration
examples/nextjs/*, README.md
The Next.js layout and page use withSay. The layout reads the established view with getSay, and translations format thresholds as EUR values.

Named catalogue exports

Layer / File(s) Summary
Named catalogue exports
examples/*/src/i18n.ts, examples/*/src/main.ts, website/content/core-concepts/*, website/content/getting-started/*, website/content/guides/*
Catalogue modules use named exports instead of default exports. Consumers and documentation use matching named imports.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 07d25

No actionable correctness, security, data-integrity, or availability risk remains for merge.

Sequence Diagram(s)

sequenceDiagram
  participant RouteSegment
  participant withSay
  participant Catalogue
  participant ReactCache
  participant ServerComponent
  RouteSegment->>withSay: resolve locale
  withSay->>Catalogue: match and load view
  withSay->>ReactCache: establish view
  withSay->>ServerComponent: render component
  ServerComponent->>ReactCache: read view with getSay
Loading

Poem

A rabbit binds the view with care
A named catalogue now hops there
Carbon commands need less to pass
React finds views through request cache
Scope fades into a cleaner way
The carrots compile green today

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 25 files. (19 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: binding withSay to a catalogue in both React and Carbon.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 25 files. (19 skipped: 19 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch withsay

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces React’s server-side SayScope API and Carbon’s unbound withSay API with catalogue-bound wrappers, then migrates examples and documentation.

  • Adds createWithSay, setSay, and request-scoped view establishment to the React integration.
  • Adds catalogue-bound createWithSay and per-binding class caching to the Carbon integration.
  • Updates examples, translations, documentation, and catalogue exports for the new APIs.

Confidence Score: 5/5

The PR appears safe to merge; no concrete correctness, security, or repository-rule violations remain.

The new APIs are applied consistently, changed importers and documentation are migrated, and the investigated request-state, typing, caching, and release-versioning concerns do not establish failures within the documented contracts.

Reviews (1): Last reviewed commit: "Bind Carbon's withSay to a catalogue wit..." | Re-trigger Greptile

@k0d13
k0d13 merged commit 43f8f1a into main Sep 6, 2026
17 checks passed
@k0d13
k0d13 deleted the withsay branch September 6, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

examples Updates or additions to example apps package: carbon Related to @saykit/carbon package: react Related to @saykit/react tests Modifications, additions, or fixes related to testing website Updates to the documentation website

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant