@@ -11,6 +11,7 @@ export interface ModernI18nContextValue {
1111 entryName ?: string ;
1212 languages ?: string [ ] ;
1313 localePathRedirect ?: boolean ;
14+ ignoreRedirectRoutes ?: string [ ] | ( ( pathname : string ) => boolean ) ;
1415 // Callback to update language in context
1516 updateLanguage ?: ( newLang : string ) => void ;
1617}
@@ -41,6 +42,44 @@ export interface UseModernI18nReturn {
4142 isLanguageSupported : ( lang : string ) => boolean ;
4243}
4344
45+ /**
46+ * Check if the given pathname should ignore automatic locale redirect
47+ */
48+ const shouldIgnoreRedirect = (
49+ pathname : string ,
50+ languages : string [ ] ,
51+ ignoreRedirectRoutes ?: string [ ] | ( ( pathname : string ) => boolean ) ,
52+ ) : boolean => {
53+ if ( ! ignoreRedirectRoutes ) {
54+ return false ;
55+ }
56+
57+ // Remove language prefix if present (e.g., /en/api -> /api)
58+ const segments = pathname . split ( '/' ) . filter ( Boolean ) ;
59+ let pathWithoutLang = pathname ;
60+ if ( segments . length > 0 && languages . includes ( segments [ 0 ] ) ) {
61+ // Remove language prefix
62+ pathWithoutLang = `/${ segments . slice ( 1 ) . join ( '/' ) } ` ;
63+ }
64+
65+ // Normalize path (ensure it starts with /)
66+ const normalizedPath = pathWithoutLang . startsWith ( '/' )
67+ ? pathWithoutLang
68+ : `/${ pathWithoutLang } ` ;
69+
70+ if ( typeof ignoreRedirectRoutes === 'function' ) {
71+ return ignoreRedirectRoutes ( normalizedPath ) ;
72+ }
73+
74+ // Check if pathname matches any of the ignore patterns
75+ return ignoreRedirectRoutes . some ( pattern => {
76+ // Support both exact match and prefix match
77+ return (
78+ normalizedPath === pattern || normalizedPath . startsWith ( `${ pattern } /` )
79+ ) ;
80+ } ) ;
81+ } ;
82+
4483// Safe hook wrapper to handle cases where router context is not available
4584const useRouterHooks = ( ) => {
4685 try {
@@ -91,6 +130,7 @@ export const useModernI18n = (): UseModernI18nReturn => {
91130 i18nInstance,
92131 languages,
93132 localePathRedirect,
133+ ignoreRedirectRoutes,
94134 updateLanguage,
95135 } = context ;
96136
@@ -143,33 +183,55 @@ export const useModernI18n = (): UseModernI18nReturn => {
143183 const entryPath = getEntryPath ( ) ;
144184 const relativePath = currentPath . replace ( entryPath , '' ) ;
145185
146- // Build new path with updated language
147- const newPath = buildLocalizedUrl (
148- relativePath ,
149- newLang ,
150- languages || [ ] ,
151- ) ;
152- const newUrl = entryPath + newPath + location . search + location . hash ;
186+ // Check if this route should ignore automatic redirect
187+ if (
188+ ! shouldIgnoreRedirect (
189+ relativePath ,
190+ languages || [ ] ,
191+ ignoreRedirectRoutes ,
192+ )
193+ ) {
194+ // Build new path with updated language
195+ const newPath = buildLocalizedUrl (
196+ relativePath ,
197+ newLang ,
198+ languages || [ ] ,
199+ ) ;
200+ const newUrl =
201+ entryPath + newPath + location . search + location . hash ;
153202
154- // Navigate to new URL
155- navigate ( newUrl , { replace : true } ) ;
203+ // Navigate to new URL
204+ await navigate ( newUrl , { replace : true } ) ;
205+ }
156206 } else if ( localePathRedirect && isBrowser ( ) && ! hasRouter ) {
157207 // Fallback: use window.history API when router is not available
158208 const currentPath = window . location . pathname ;
159209 const entryPath = getEntryPath ( ) ;
160210 const relativePath = currentPath . replace ( entryPath , '' ) ;
161211
162- // Build new path with updated language
163- const newPath = buildLocalizedUrl (
164- relativePath ,
165- newLang ,
166- languages || [ ] ,
167- ) ;
168- const newUrl =
169- entryPath + newPath + window . location . search + window . location . hash ;
170-
171- // Use history API to navigate without page reload
172- window . history . pushState ( null , '' , newUrl ) ;
212+ // Check if this route should ignore automatic redirect
213+ if (
214+ ! shouldIgnoreRedirect (
215+ relativePath ,
216+ languages || [ ] ,
217+ ignoreRedirectRoutes ,
218+ )
219+ ) {
220+ // Build new path with updated language
221+ const newPath = buildLocalizedUrl (
222+ relativePath ,
223+ newLang ,
224+ languages || [ ] ,
225+ ) ;
226+ const newUrl =
227+ entryPath +
228+ newPath +
229+ window . location . search +
230+ window . location . hash ;
231+
232+ // Use history API to navigate without page reload
233+ window . history . pushState ( null , '' , newUrl ) ;
234+ }
173235 }
174236
175237 // Update language state after URL update
@@ -185,6 +247,7 @@ export const useModernI18n = (): UseModernI18nReturn => {
185247 i18nInstance ,
186248 updateLanguage ,
187249 localePathRedirect ,
250+ ignoreRedirectRoutes ,
188251 languages ,
189252 hasRouter ,
190253 navigate ,
0 commit comments