feat: Add per-domain localePrefix override support#2273
Conversation
|
@frankmatheron is attempting to deploy a commit to the next-intl Team on Vercel. A member of the Team first needs to authorize it. |
c0a144e to
ac54cbf
Compare
Adds optional localePrefix property to DomainConfig type, allowing domains to override the global localePrefix mode. This enables different URL prefix strategies per domain (e.g., always prefix on one domain, never prefix on another). - Add localePrefix property to DomainConfig type - Update applyPathnamePrefix to check domain override first - Add comprehensive tests for all mode combinations - Update documentation with examples
ac54cbf to
5599aac
Compare
Updates middleware to respect per-domain localePrefix overrides: - Check domain.localePrefix before falling back to global mode - Apply effective mode in routing decisions and redirects - Update alternate links generation to use domain-specific mode
5599aac to
1ae8398
Compare
Adds comprehensive test coverage for domain-specific localePrefix overrides:
- Tests for global 'as-needed' with domain overrides ('never', 'always')
- Tests for global 'always' with domain overrides ('never', 'as-needed')
- Tests for global 'never' with domain overrides ('always', 'as-needed')
- Verifies correct redirect and serve behavior for each combination
Adds test coverage for alternate links generation with domain-specific localePrefix overrides. Tests verify correct hreflang link generation for all combinations of global and domain-level modes.
feat: add Dutch locale and improve always domain test coverage
Consolidate usePathname tests (6→3), fix never-mode alternate links assertions, add query string preservation and unsupported locale tests, share browser instances across describe blocks.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
amannn
left a comment
There was a problem hiding this comment.
Hey @frankmatheron, thanks a lot for exploring this so carefully and the extensive & thoughtful PR!
Looking through all the changes, it looks like this works really well now—so green light from me to release this.
I've added a commit with some nits, mainly around docs. Hope that looks good to you.
| chromium, | ||
| expect, | ||
| test as it | ||
| } from '@playwright/test'; |
There was a problem hiding this comment.
Looks really good, thanks for making the test suite so extensive!
I'm planning to refactor the e2e test strategy a bit after this PR is merged (see #2310).
I really appreciate how clean your proposed changes are here, any chance you'd be interested in helping with that? Only if you're up for it, otherwise I can look into it.
There was a problem hiding this comment.
The e2e refactoring seems quite important for upcoming features, I'll give this a go.
Edit: At least extractor tests have been pulled into /e2e now, tests from the playground are still to be done …
localePrefix override support
Summary
Adds an optional
localePrefixproperty toDomainConfig, allowing each domain to override the globallocalePrefixmode independently. This eliminates the need for separate builds per domain when different domains require different prefix behaviors.Closes #2272.
Motivation
When using domain-based routing, all domains currently share the same
localePrefixmode. This is limiting for setups like:us.example.com) that should never show prefixesca.example.com) that should always show prefixes for clarityThe previous workaround was building the app separately per domain with different env-injected configs — costly and complex.
Usage
When
localePrefixis set on a domain, it completely replaces the global mode for that domain. Domains without the property continue using the global setting. Customprefixes(e.g./spainfores) remain global and are respected regardless of the domain-level mode.Implementation
The change touches 4 source files, all following the same pattern — resolve the effective mode via
domain?.localePrefix || globalMode:routing/types.tsx— AddslocalePrefix?: LocalePrefixModetoDomainConfig. Uses the simple string union rather than the verbose config object, since domains only override the mode, not the prefix mapping.middleware/middleware.tsx— IntroduceseffectiveLocalePrefixModethat checks the matched domain's override before falling back to the global mode. Used in 4 places: unprefixed routing check,nevermode redirect, alternate links guard, and cross-domain redirect.middleware/getAlternateLinksHeaderValue.tsx— Respects per-domain mode when deciding whether to prefix alternate link URLs.navigation/shared/utils.tsx—applyPathnamePrefixnow looks up the domain for the given locale and uses itslocalePrefixoverride when generating pathnames (affectsLink,getPathname,redirect).Tests
Unit tests (26 new tests):
middleware.test.tsx— 14 tests: 3 global modes × domain overrides (never,always,as-needed), plus fallback to global when no override is setgetAlternateLinksHeaderValue.test.tsx— 3 tests: cross-domain alternate link generation with mixed modescreateNavigation.test.tsx— 9 tests:getPathnamewith domain overrides for all 3 global modesE2E tests (29 new tests):
never.example.com,always.example.com,as-needed.example.com) each tested for: routing, redirects, query string preservation, Link href generation,usePathname, alternate links headers, and localized pathnamesBundle size impact
createNavigationgrows by ~20B (minified + brotli) due to the domain lookup inapplyPathnamePrefix. Size limits bumped accordingly:Docs
configuration.mdxlocalePrefixper domain?" FAQ from "not supported" to documenting the new feature with examples