Skip to content

Proposal: To be able to easily run @valibot/i18n in Playground as well#1488

Open
ysknsid25 wants to merge 8 commits into
open-circle:mainfrom
ysknsid25:feat/playground
Open

Proposal: To be able to easily run @valibot/i18n in Playground as well#1488
ysknsid25 wants to merge 8 commits into
open-circle:mainfrom
ysknsid25:feat/playground

Conversation

@ysknsid25

@ysknsid25 ysknsid25 commented May 30, 2026

Copy link
Copy Markdown
Contributor

resolves: #1487

2026-06-03.0.38.40.mov

Summary by cubic

Make @valibot/i18n work in the Playground by shipping self-contained per-language ESM bundles and wiring them into the iframe import map. Users can import translations like @valibot/i18n/de in snippets with type safety.

  • New Features

    • Add build.playground in @valibot/i18n to emit one self-contained ESM bundle per language; auto-discovers languages from src (skips en/types) and keeps valibot external.
    • Serve bundles from website/public and map them in the iframe import map as @valibot/i18n/<lang>; derive languages via globbing, add defensive mapping to ignore unexpected files, and avoid ?url to prevent Vite rewrites/double-loading valibot.
    • Add @valibot/i18n to the website workspace and declare @valibot/i18n modules in Monaco for type safety.
    • Add CORS headers for local dev (Vite) and production (Vercel), long-term cache for .mjs assets (including /playground/i18n/*), and update Vercel build to run the i18n playground build and use the website build.vercel script.
  • Migration

    • Before running the Playground locally, build translations: pnpm -F @valibot/i18n build.playground (see website/README.md).

Written for commit 105a81a. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

@ysknsid25 is attempting to deploy a commit to the Open Circle Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR enables i18n language translations to function within the Valibot playground. It adds a build script that emits ESM bundles for each non-default locale, registers @valibot/i18n as a website workspace devDependency and documents the build step, injects discovered language bundles into the playground iframe import map, adds Monaco editor ambient module declarations for i18n imports, and configures dev-server CORS and Vercel caching/headers for .mjs assets.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Proposal: To be able to easily run @valibot/i18n in Playground as well' directly describes the main objective of the PR: enabling @valibot/i18n functionality in the Playground.
Linked Issues check ✅ Passed The PR fully addresses issue #1487 by implementing all four proposed objectives: building per-language ESM bundles, wiring them into the iframe import map, adding Monaco declarations for type safety, and integrating @valibot/i18n into the website workspace.
Out of Scope Changes check ✅ Passed All changes are directly aligned with enabling @valibot/i18n in the Playground; no out-of-scope modifications were introduced beyond the stated objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed The pull request description clearly explains the changes: making @valibot/i18n work in the Playground by shipping per-language ESM bundles and wiring them into the iframe import map.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Signed-off-by: ysknsid25 <kengo071225@gmail.com>
@ysknsid25 ysknsid25 marked this pull request as ready for review June 1, 2026 12:04
Copilot AI review requested due to automatic review settings June 1, 2026 12:04
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Jun 1, 2026

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds @valibot/i18n support to the website playground by generating and serving per-language playground bundles and wiring them into the iframe import map (including local-dev and Vercel build adjustments).

Changes:

  • Generate self-contained per-language i18n ESM bundles for the playground and include them in Vercel builds.
  • Extend the playground iframe import map to expose @valibot/i18n/<lang> URLs and add Monaco editor typings for i18n imports.
  • Adjust local dev server headers and documentation to support loading cross-origin modules in the sandboxed iframe.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
website/vite.config.ts Adds dev-server CORS header to allow sandboxed iframe module loading locally.
website/vercel.json Builds i18n playground bundles during deploy and adds long-term caching for emitted .mjs assets.
website/src/routes/playground/index.tsx Imports i18n bundle URLs and serializes them into the iframe import map.
website/src/components/CodeEditor.tsx Adds Monaco TypeScript module declarations for @valibot/i18n imports.
website/package.json Adds @valibot/i18n workspace dependency.
website/README.md Documents required i18n playground build step before starting the website.
packages/i18n/scripts/build-playground.ts New script emitting one ESM bundle per language for the playground.
packages/i18n/package.json Adds build.playground script entry.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/i18n/scripts/build-playground.ts
Comment thread packages/i18n/scripts/build-playground.ts
Comment thread website/src/routes/playground/index.tsx Outdated
Comment thread website/vite.config.ts
Comment thread website/vercel.json Outdated
Comment thread website/src/components/CodeEditor.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
website/src/routes/playground/index.tsx (1)

36-67: 🏗️ Heavy lift

Avoid maintaining locale lists in two places; generate/import from a single manifest.

The locale catalog is duplicated here and in packages/i18n/scripts/build-playground.ts, which increases drift risk (missing import-map entries or dead bundles). Consider generating a manifest during i18n build and consuming it here.

Also applies to: 72-111

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/src/routes/playground/index.tsx` around lines 36 - 67, The current
hardcoded locale imports (e.g., i18nAr, i18nZhCN, etc.) duplicate the locale
list maintained in packages/i18n/scripts/build-playground.ts, causing drift;
instead generate a single manifest during the i18n build and consume it here:
update build-playground.ts to emit a JSON or JS manifest of available playground
locales (paths and keys) and replace the static imports in
website/src/routes/playground/index.tsx with a dynamic import loop that reads
that manifest and imports each entry (or uses import(url) at runtime), ensuring
the unique symbols like the imported locale identifiers (i18nAr, i18nDe,
i18nZh-TW) are derived from the manifest so the list is maintained in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/i18n/scripts/build-playground.ts`:
- Around line 3-34: Imports in build-playground.ts use extensionless local ESM
paths (e.g., ar, az, zhCN, zhTW) which violates the rule requiring .ts
extensions; update every local import statement (imports named ar, az, ca, cs,
de, el, es, fa, fi, fr, hu, id, it, ja, ko, kr, mn, nb, nl, pl, pt, ro, ru, sk,
sl, sv, tr, uk, uz, vi, zhCN, zhTW) to include the .ts file extension (e.g.,
import ar from '../src/ar.ts') so the module loader and ESLint rule are
satisfied.

In `@website/vercel.json`:
- Around line 89-97: The Vercel route rule for "/assets/(.*).mjs" only sets
Cache-Control, causing CORS failures for module fetches; update the headers
array for the "/assets/(.*).mjs" rule in website/vercel.json to include an
"Access-Control-Allow-Origin" header (use the same value used for the
"/assets/(.*)-index.min.mjs" rule, e.g., "*") alongside the existing
Cache-Control entry so .mjs module requests are allowed cross-origin.

---

Nitpick comments:
In `@website/src/routes/playground/index.tsx`:
- Around line 36-67: The current hardcoded locale imports (e.g., i18nAr,
i18nZhCN, etc.) duplicate the locale list maintained in
packages/i18n/scripts/build-playground.ts, causing drift; instead generate a
single manifest during the i18n build and consume it here: update
build-playground.ts to emit a JSON or JS manifest of available playground
locales (paths and keys) and replace the static imports in
website/src/routes/playground/index.tsx with a dynamic import loop that reads
that manifest and imports each entry (or uses import(url) at runtime), ensuring
the unique symbols like the imported locale identifiers (i18nAr, i18nDe,
i18nZh-TW) are derived from the manifest so the list is maintained in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 31d1fdf8-edaa-452d-93aa-3d1f2d52a27c

📥 Commits

Reviewing files that changed from the base of the PR and between fa43437 and 610942d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • packages/i18n/package.json
  • packages/i18n/scripts/build-playground.ts
  • website/README.md
  • website/package.json
  • website/src/components/CodeEditor.tsx
  • website/src/routes/playground/index.tsx
  • website/vercel.json
  • website/vite.config.ts

Comment thread packages/i18n/scripts/build-playground.ts Outdated
Comment thread website/vercel.json

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 9 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread website/vercel.json
Comment thread website/vercel.json Outdated
ysknsid25 added 3 commits June 1, 2026 21:36
…bing

Signed-off-by: ysknsid25 <kengo071225@gmail.com>
Signed-off-by: ysknsid25 <kengo071225@gmail.com>
Signed-off-by: ysknsid25 <kengo071225@gmail.com>
@vercel

vercel Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deployment failed with the following error:

The `vercel.json` schema validation failed with the following message: `buildCommand` should NOT be longer than 256 characters

Learn More: https://vercel.com/docs/concepts/projects/project-configuration

@vercel

vercel Bot commented Jun 1, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
valibot Error Error Jun 1, 2026 12:45pm

Request Review

Signed-off-by: ysknsid25 <kengo071225@gmail.com>
@ysknsid25 ysknsid25 marked this pull request as draft June 2, 2026 15:22
…nd update playground routing

Signed-off-by: ysknsid25 <kengo071225@gmail.com>
@ysknsid25 ysknsid25 marked this pull request as ready for review June 2, 2026 15:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
website/src/routes/playground/index.tsx (2)

374-378: ⚡ Quick win

Prefer interface over type for object shapes.

Per coding guidelines, object shapes should use interface instead of type in TypeScript files.

♻️ Apply guideline
-type EditorButtonsProps = {
+interface EditorButtonsProps {
   class: string;
   model: Signal<NoSerialize<monaco.editor.ITextModel>>;
   executeCode$: QRL<() => void>;
-};
+}

As per coding guidelines: "Prefer interface over type for defining object shapes in TypeScript"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/src/routes/playground/index.tsx` around lines 374 - 378, Replace the
type alias EditorButtonsProps with an interface declaration to follow the coding
guideline: change `type EditorButtonsProps = { ... }` to `interface
EditorButtonsProps { class: string; model:
Signal<NoSerialize<monaco.editor.ITextModel>>; executeCode$: QRL<() => void>;
}`, preserving the exact property names and types (including `class`, `model`
and `executeCode$`) and leaving other usage sites unchanged.

89-94: ⚡ Quick win

Prefer interface over type for object shapes.

Per coding guidelines, object shapes should use interface instead of type in TypeScript files.

♻️ Apply guideline
-type LogLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';
+type LogLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';

-type MessageEventData = {
+interface MessageEventData {
   type: 'log';
   log: [LogLevel, string];
-};
+}

As per coding guidelines: "Prefer interface over type for defining object shapes in TypeScript"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/src/routes/playground/index.tsx` around lines 89 - 94, Replace the
object-shape type alias MessageEventData with an interface: change "type
MessageEventData = { type: 'log'; log: [LogLevel, string]; }" to an equivalent
"interface MessageEventData { type: 'log'; log: [LogLevel, string]; }" while
leaving the LogLevel union alias as-is; update any imports/uses that expect
MessageEventData if needed to reference the interface name.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/src/routes/playground/index.tsx`:
- Line 69: The current mapping uses path.match(/\/src\/(.+)\.ts$/)![1] which
assumes the regex always matches and can crash if it doesn't; modify the
transformation to handle a null match: call path.match(...) into a local
variable (e.g., matchResult), check if matchResult is truthy, and only extract
matchResult[1] when present—either filter out non-matching paths before mapping
or return a safe fallback/throw a controlled error; update the code at the map
call site (the arrow function using path.match) to perform this null check
instead of using the non-null assertion.

---

Nitpick comments:
In `@website/src/routes/playground/index.tsx`:
- Around line 374-378: Replace the type alias EditorButtonsProps with an
interface declaration to follow the coding guideline: change `type
EditorButtonsProps = { ... }` to `interface EditorButtonsProps { class: string;
model: Signal<NoSerialize<monaco.editor.ITextModel>>; executeCode$: QRL<() =>
void>; }`, preserving the exact property names and types (including `class`,
`model` and `executeCode$`) and leaving other usage sites unchanged.
- Around line 89-94: Replace the object-shape type alias MessageEventData with
an interface: change "type MessageEventData = { type: 'log'; log: [LogLevel,
string]; }" to an equivalent "interface MessageEventData { type: 'log'; log:
[LogLevel, string]; }" while leaving the LogLevel union alias as-is; update any
imports/uses that expect MessageEventData if needed to reference the interface
name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 52c7372f-5ff9-4cdd-b43c-79abc65e2532

📥 Commits

Reviewing files that changed from the base of the PR and between 60ee3f4 and ce92f60.

📒 Files selected for processing (4)
  • packages/i18n/scripts/build-playground.ts
  • website/.gitignore
  • website/src/routes/playground/index.tsx
  • website/vercel.json
✅ Files skipped from review due to trivial changes (1)
  • website/.gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/vercel.json

Comment thread website/src/routes/playground/index.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 10 files

Re-trigger cubic

…s from unexpected glob results

Signed-off-by: ysknsid25 <kengo071225@gmail.com>
@fabian-hiller

Copy link
Copy Markdown
Member

Thank you for this PR! How big is the index.mjs file? I am curious about the bundle size impact on our website. But I think we load it lazily only when executing the playground. So probably not too important. I am also curious if it make sense to only load the language the user actually imported.

@ysknsid25

Copy link
Copy Markdown
Contributor Author

Thank you for feedback, @fabian-hiller

How big is the index.mjs file?

This is each index.mjs file size.

lang size (KB)
ar 15.5
az 11.4
ca 11.6
cs 12.2
de 11.4
el 12.6
es 11.8
fa 13.8
fi 11.8
fr 10.9
hu 11.4
id 11.6
it 11.3
ja 13.4
ko 14.2
kr 14.2
mn 12.6
nb 10.9
nl 11.4
pl 12.1
pt 11.5
ro 12.0
ru 14.7
sk 11.8
sl 11.6
sv 10.9
tr 11.5
uk 14.9
uz 11.8
vi 13.1
zh-CN 11.8
zh-TW 11.7
total (32 langs) 393.6

As you understand, Each index.mjs is not part of the website JS bundle. The files are served
as static assets from public/playground/i18n/<lang>/index.mjs and fetched directly by the playground iframe.

I am also curious if it make sense to only load the language the user actually imported.

Based on the following points, I believe we should only load the languages ​​that users actually import. The fundamental idea is that this is a 'Playground,' and it's best to start minimally.

  • Currently, i18 doesn't use any languages ​​other than English, but in the years since Playground was created, no one other than me has requested this. This indicates that very few people are actually trying to view messages in languages ​​other than English in Playground. Therefore, the demand for making all languages ​​available from the start is likely low.
  • Basically, users only need to see how their native language is displayed.
    • As a Japanese person, it's rare for me to check Korean.
    • Even with internationalization support, it's not necessary to check all languages; typically, it's limited to a few languages ​​with a large user base, such as English and Chinese, and the service provider's native language.

Based on the above, I believe we should only load the languages ​​that users actually import.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: To be able to easily run @valibot/i18n in Playground as well

3 participants