( pathname: string, locales: string[] )
| 51 | * Normalizes a pathname by removing the locale prefix if present |
| 52 | */ |
| 53 | export function normalizeLocalePath( |
| 54 | pathname: string, |
| 55 | locales: string[] |
| 56 | ): { |
| 57 | pathname: string |
| 58 | detectedLocale?: string |
| 59 | } { |
| 60 | if (!locales || locales.length === 0) { |
| 61 | return { pathname } |
| 62 | } |
| 63 | |
| 64 | // The first segment will be empty, because it has a leading `/` |
| 65 | const segments = pathname.split('/', 2) |
| 66 | |
| 67 | // If there's no second segment, there's no locale |
| 68 | if (!segments[1]) { |
| 69 | return { pathname } |
| 70 | } |
| 71 | |
| 72 | // The second segment will contain the locale part if any |
| 73 | const segment = segments[1].toLowerCase() |
| 74 | |
| 75 | // Create lowercase lookup for performance |
| 76 | const lowercaseLocales = locales.map((locale) => locale.toLowerCase()) |
| 77 | const index = lowercaseLocales.indexOf(segment) |
| 78 | |
| 79 | if (index < 0) { |
| 80 | return { pathname } |
| 81 | } |
| 82 | |
| 83 | // Return the case-sensitive locale |
| 84 | const detectedLocale = locales[index] |
| 85 | |
| 86 | // Remove the `/${locale}` part of the pathname |
| 87 | const newPathname = pathname.slice(detectedLocale.length + 1) || '/' |
| 88 | |
| 89 | return { pathname: newPathname, detectedLocale } |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Parses the Accept-Language header and returns the best matching locale |
no test coverage detected