Skip to content

Conversation

@kazupon
Copy link
Member

@kazupon kazupon commented Nov 16, 2025

Description

Linked Issues

resolve #28

Additional context

Summary by CodeRabbit

  • New Features

    • Async locale detection with on-demand (lazy) message loading and parallel loading support; route handlers and translation retrieval now support async resolution.
  • Documentation

    • Examples updated to demonstrate asynchronous locale detection, lazy loading, and awaiting translations.
  • Tests

    • Expanded & reorganized integration and e2e tests to cover async and parallel loading; minor test title updates and fixture additions.
  • Chores

    • Added locale fixtures and updated workspace package catalog entries.

@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Walkthrough

Adds async locale-detector support to Hono: makes useTranslation asynchronous, wires a detector into Hono context (i18nLocaleDetector), enables on-demand and parallel message loading, updates examples/playgrounds/docs, adjusts tests, and updates some package dependency entries to catalog placeholders.

Changes

Cohort / File(s) Summary
Workspace / Dependencies
packages/h3/package.json, packages/hono/package.json, pnpm-workspace.yaml
Replaced concrete @intlify/core version specs with catalog: placeholders and added @intlify/core ^11.1.12 to pnpm workspace catalog.
Hono integration source
packages/hono/src/index.ts
Added i18nLocaleDetector to Hono context, changed locale-detector signature to accept CoreContext, store/clear detector on context, made useTranslation async (returns a Promise), integrated parseTranslateArgs, and updated translation call wiring.
Hono tests & types
packages/hono/src/index.test.ts, packages/hono/src/index.test-d.ts
Converted tests to async, updated mock context to expose i18nLocaleDetector, switched a type-test assertion to toExtend, and changed assertions to await/reject where appropriate.
Integration tests (h3/hono)
packages/h3/spec/integration.spec.ts, packages/hono/spec/integration.spec.ts
Renamed/refactored integration tests; added Hono tests for basic detection, async on-demand loading, and parallel loading scenarios; updated test titles and flows to use async detection.
Fixtures
packages/hono/spec/fixtures/en.json, packages/hono/spec/fixtures/ja.json
Added English and Japanese locale fixture files used by integration tests.
Playgrounds & README
packages/hono/playground/basic/index.ts, packages/hono/playground/global-schema/index.ts, packages/hono/playground/local-schema/index.ts, packages/hono/README.md
Updated route handlers to async, changed useTranslation(...) calls to await useTranslation(...), and expanded README with async locale-detector and lazy loading examples.
e2e & config
packages/hono/spec/e2e.spec.ts, vitest.e2e.config.ts
Updated expected stdout in e2e test ("h3" → "hono") and set fileParallelism: false in Vitest e2e config to run tests serially.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Middleware
    participant Detector as Locale Detector
    participant Loader as Resource Loader
    participant Route as Route Handler
    participant Translator as useTranslation

    Note over Client,Translator: Async locale detection + on-demand loading flow

    Client->>Middleware: HTTP request
    Middleware->>Detector: detectLocale(ctx) (async)
    Detector->>Loader: load messages if missing (async)
    Loader-->>Detector: messages
    Detector-->>Middleware: detected locale
    Middleware->>Middleware: set ctx.i18nLocaleDetector
    Middleware-->>Client: continue to route

    Client->>Route: invoke route handler (async)
    Route->>Translator: await useTranslation(ctx)
    Translator->>Detector: call detector from ctx (once)
    Detector-->>Translator: locale
    Translator->>Translator: set i18n.locale, parse args
    Translator-->>Route: translation function
    Route-->>Client: response with translated text
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files needing focused review:
    • packages/hono/src/index.ts (async useTranslation, detector binding/clearing, parseTranslateArgs integration)
    • packages/hono/spec/integration.spec.ts (async and parallel loading test correctness and race conditions)
    • Test mocks and context augmentation (packages/hono/src/index.test.ts, packages/hono/src/index.test-d.ts) to ensure correct typings and behavior.

Possibly related PRs

Poem

🐰 I hopped through code at break of day,

Awaiting locales along the way.
Detectors peek, loaders hum,
Translations bloom — the rabbits come! 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(hono): support async locale detector' directly and concisely describes the main change, which is adding support for asynchronous locale detection in the Hono integration.
Linked Issues check ✅ Passed The PR successfully implements async locale detector support for Hono by backporting the implementation from @intlify/h3 PR #19, addressing all requirements in issue #28.
Out of Scope Changes check ✅ Passed All changes are in scope: async locale detector implementation in hono package, supporting test fixtures, documentation updates, dependency catalog changes, and vitest config for serial test execution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/support-async

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 386ad82 and b2f278d.

📒 Files selected for processing (3)
  • packages/hono/README.md (4 hunks)
  • packages/hono/spec/e2e.spec.ts (1 hunks)
  • vitest.e2e.config.ts (1 hunks)
🔇 Additional comments (7)
packages/hono/spec/e2e.spec.ts (1)

57-57: LGTM! Test expectation correctly updated.

The expected output now correctly references "hono" instead of "h3", aligning with the package being tested.

vitest.e2e.config.ts (1)

8-10: LGTM! Good practice for e2e tests.

Disabling parallel execution for e2e tests is appropriate, especially given the async locale detection and resource loading scenarios introduced in this PR. This helps ensure deterministic test execution.

packages/hono/README.md (5)

104-106: LGTM! Documentation correctly demonstrates async usage.

The basic translation example is properly updated to reflect the async API changes, with the handler marked as async and useTranslation being awaited.


144-150: LGTM! Helpful technical clarification.

The NOTE correctly clarifies that synchronous functions returning promises are not supported and that async function syntax must be used. This is important guidance for users implementing custom locale detectors.


151-188: LGTM! Comprehensive async locale detection example.

The example clearly demonstrates the lazy loading pattern with async locale detection, including:

  • Resource loader functions
  • Accessing the i18n context to check existing messages
  • Properly awaiting resource loading before adding to i18n.messages

This is valuable documentation for users implementing custom async locale detectors.


285-290: LGTM! Type-safe async example is correct.

The example properly demonstrates using useTranslation with a type parameter for resource key completion, while also showing the required async/await pattern.


321-322: LGTM! Global schema example updated correctly.

The example properly demonstrates the async usage pattern with the global resource schema approach, where the type parameter is not needed thanks to the declare module extension.


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.

@kazupon kazupon added feature Includes new features Hono labels Nov 16, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 16, 2025

Open in StackBlitz

npm i https://pkg.pr.new/@intlify/h3@35
npm i https://pkg.pr.new/@intlify/hono@35

commit: b2f278d

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 301f76c and f704f71.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • packages/h3/package.json (1 hunks)
  • packages/h3/spec/integration.spec.ts (3 hunks)
  • packages/hono/README.md (4 hunks)
  • packages/hono/package.json (1 hunks)
  • packages/hono/playground/basic/index.ts (1 hunks)
  • packages/hono/playground/global-schema/index.ts (1 hunks)
  • packages/hono/playground/local-schema/index.ts (1 hunks)
  • packages/hono/spec/fixtures/en.json (1 hunks)
  • packages/hono/spec/fixtures/ja.json (1 hunks)
  • packages/hono/spec/integration.spec.ts (3 hunks)
  • packages/hono/src/index.test-d.ts (1 hunks)
  • packages/hono/src/index.test.ts (3 hunks)
  • packages/hono/src/index.ts (5 hunks)
  • pnpm-workspace.yaml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/hono/src/index.ts (1)
packages/h3/src/index.ts (1)
  • detectLocaleFromAcceptLanguageHeader (244-245)
packages/hono/spec/integration.spec.ts (1)
packages/hono/src/index.ts (3)
  • defineI18nMiddleware (126-167)
  • CoreContext (36-36)
  • DefineLocaleMessage (89-89)
🔇 Additional comments (23)
packages/h3/spec/integration.spec.ts (1)

56-56: LGTM! Improved test titles.

The test titles are now more descriptive and clearly communicate what each test validates: basic detection, async loading, and parallel async loading scenarios.

Also applies to: 91-91, 154-154

packages/hono/playground/local-schema/index.ts (1)

21-27: LGTM! Correctly implements async translation pattern.

The route handler has been properly updated to async/await the useTranslation call, aligning with the PR's objective to support async locale detection.

packages/hono/playground/basic/index.ts (1)

23-24: LGTM! Consistent async implementation.

The async/await pattern is correctly applied, consistent with other playground examples in this PR.

packages/hono/playground/global-schema/index.ts (1)

30-31: LGTM! Async pattern with global schema.

The async/await pattern is correctly applied while maintaining the global schema type safety approach.

packages/hono/README.md (3)

104-108: LGTM! Documentation updated for async API.

The basic usage example correctly demonstrates the new async/await pattern for useTranslation.


151-188: Excellent documentation for async locale detection.

This new section provides a comprehensive and practical example demonstrating:

  • Async locale detector signature with CoreContext parameter
  • Resource lazy loading pattern
  • Proper type imports and usage

This addresses the core feature of the PR and will help users understand how to implement async locale detection.


285-293: LGTM! All examples consistently updated.

The type-safe resources and global schema examples have been properly updated to use the async/await pattern, maintaining consistency throughout the documentation.

Also applies to: 321-326

packages/hono/spec/fixtures/ja.json (1)

1-3: LGTM! Valid translation fixture.

The Japanese translation fixture is correctly formatted and will support async loading test scenarios.

packages/h3/package.json (1)

66-66: Catalog configuration is properly defined.

The verification confirms that @intlify/core is correctly defined in the pnpm workspace catalog with version ^11.1.12. The change to use "@intlify/core": "catalog:" in the package.json is valid and consistent with the catalog configuration.

packages/hono/src/index.test-d.ts (1)

19-19: No issues found. This is a deprecation update.

toMatchTypeOf has been deprecated since expect-type v1.2.0 and the recommended replacement is toExtend. .toExtend is identical to .toMatchTypeOf, so this change is a straightforward API update with no change to the actual type relationship being tested. The middleware type continues to extend MiddlewareHandler as before.

packages/hono/spec/fixtures/en.json (1)

1-3: LGTM!

The fixture file is correctly formatted and provides the necessary test data for English locale translations.

packages/hono/package.json (1)

65-65: LGTM!

The switch to catalog-based dependency resolution is consistent with the monorepo approach and aligns with the workspace catalog entry.

packages/hono/src/index.test.ts (2)

43-79: LGTM!

The test has been correctly updated to handle async translation:

  • Test is now async and awaits useTranslation
  • Mock context properly provides both i18n and i18nLocaleDetector
  • Locale detector binding logic is correct

81-94: LGTM!

The error handling test is correctly updated to async pattern with rejects.toThrowError.

packages/hono/spec/integration.spec.ts (2)

34-36: LGTM!

The route handler correctly uses async/await pattern with useTranslation.


48-80: LGTM!

The basic detection test correctly demonstrates synchronous locale detection with the new async translation API.

packages/hono/src/index.ts (6)

12-17: Note: External typo in imported constant.

Line 15 imports NOT_REOSLVED which appears to be a typo in the @intlify/core library (should be NOT_RESOLVED). Since this is an internal function from the external library, there's nothing to fix here, but it's worth noting.


58-58: LGTM!

The addition of i18nLocaleDetector to the context variable map correctly exposes the locale detector for use in useTranslation.


147-153: LGTM!

The updated getLocaleDetector correctly binds both ctx and i18n parameters to the locale detector function, enabling access to the i18n context for async locale loading scenarios.


155-166: LGTM!

The middleware correctly:

  • Creates and stores the locale detector in context
  • Sets the detector as a function on i18n.locale for later evaluation
  • Cleans up context on exit

347-367: LGTM!

The async implementation correctly:

  • Returns a Promise for the translation function
  • Retrieves the locale detector from context with proper error handling
  • Awaits the detector call, which handles both sync and async detectors transparently
  • Sets the resolved locale on the i18n context

369-384: Verify _translate signature from @intlify/core to confirm arg2 duplication pattern.

The pattern extracts arg2 directly from the original args array while also passing parsed options from parseTranslateArgs. This creates potential duplication—if arg2 is a number (plural), string (default), or object (named), it may be passed twice: as raw arg2 and again within parsed options. Without access to the _translate function signature from @intlify/core, I cannot confirm whether this duplication is intentional or if it correctly handles all overloads (plural, defaultMsg, list, named).

The pattern is consistently used in both packages/hono/src/index.ts (line 370-371) and packages/h3/src/index.ts (line 421-422), suggesting it may be the intended design, but manual verification against the external library's API is required.

pnpm-workspace.yaml (1)

6-6: ---

@intlify/core ^11.1.12 version is valid, but parseTranslateArgs is not an async locale-detection feature.

@intlify/core v11.1.12 exists, confirming the catalog entry is valid. However, parseTranslateArgs is a synchronous helper for parsing translation arguments and is not an async locale-detection mechanism. Async locale detection is provided by higher-level tooling (e.g., Nuxt/i18n's locale detector hooks) and those detector APIs are typically synchronous. If your implementation requires async locale detection, ensure it's handled via appropriate detector hooks or application-level async message loading, not through parseTranslateArgs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/hono/spec/integration.spec.ts (3)

47-80: Good basic custom detector; consider also asserting the fallback path

The custom detector correctly pulls locale from the query string and falls back to defaultLocale on error. Currently the spec only exercises the happy path (/?locale=ja); if you want fuller coverage of the detector’s behavior, consider adding a second assertion (or a small extra test) for the fallback case when locale is missing or invalid.


82-135: Async loading test may not actually exercise the dynamic loader

In this spec you define a messages loader map and only load when !i18n.messages[locale], but you also pass both en and ja messages into defineI18nMiddleware, so i18n.messages[locale] is likely already populated and the loader branch may never run. If the intent is to validate async message loading as well as async locale detection, consider either:

  • Seeding only the default locale (e.g., just en) in messages and relying on the loader for ja, or
  • Instrumenting the loader with vi.fn() and asserting it was called.

That would make the test’s name (“detect with async loading”) more tightly aligned with what it actually verifies.


137-194: Parallel async loading test looks solid; you can avoid the @ts-ignore with a small rewrite

The parallel test nicely exercises concurrent async detection and dynamic loading across en/ja requests. To keep types clean and remove the @ts-ignore, you can rewrite the Promise.all as an async mapper:

-    const resList = await Promise.all(
-      ['en', 'ja'].map(locale =>
-        app
-          .request(`/?locale=${locale}`)
-          // @ts-ignore
-          .then(res => res.json())
-      )
-    )
+    const resList = await Promise.all(
+      ['en', 'ja'].map(async locale => {
+        const res = await app.request(`/?locale=${locale}`)
+        return res.json()
+      })
+    )

Behavior stays the same, but the types line up without suppressing the checker.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f704f71 and 386ad82.

📒 Files selected for processing (1)
  • packages/hono/spec/integration.spec.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/hono/spec/integration.spec.ts (1)
packages/hono/src/index.ts (3)
  • defineI18nMiddleware (126-167)
  • CoreContext (36-36)
  • DefineLocaleMessage (89-89)
🔇 Additional comments (2)
packages/hono/spec/integration.spec.ts (2)

2-12: Imports updated correctly for async detection tests

The added vitest helpers and CoreContext / DefineLocaleMessage types match how they’re used later in the async locale detector specs; nothing concerning here.


34-36: Async useTranslation usage is consistent with the new API

Switching the route handler to async and awaiting useTranslation(c) before calling t('hello', …) aligns with an async translation acquisition model and keeps the test behavior clear.

@kazupon kazupon merged commit 1147a57 into main Nov 16, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Includes new features Hono

Projects

None yet

Development

Successfully merging this pull request may close these issues.

async locale detector

2 participants