|
1 |
| -import { DomainData, Manifest, RoutesManifest } from "../types"; |
| 1 | +import { Manifest, Request, RoutesManifest } from "../types"; |
2 | 2 | import { IncomingMessage } from "http";
|
| 3 | +import { parse } from "cookie"; |
3 | 4 |
|
4 | 5 | export const findDomainLocale = (
|
5 | 6 | req: IncomingMessage,
|
6 | 7 | manifest: RoutesManifest
|
7 | 8 | ): string | null => {
|
8 |
| - const domains = |
9 |
| - manifest.i18n && manifest.i18n.domains ? manifest.i18n.domains : null; |
| 9 | + const domains = manifest.i18n?.domains; |
10 | 10 | if (domains) {
|
11 | 11 | const hostHeaders = req.headers.host?.split(",");
|
12 | 12 | if (hostHeaders && hostHeaders.length > 0) {
|
13 | 13 | const host = hostHeaders[0];
|
14 |
| - const matchedDomain = domains.find( |
15 |
| - (d): DomainData | boolean => d.domain === host |
16 |
| - ); |
| 14 | + const matchedDomain = domains.find((d) => d.domain === host); |
17 | 15 |
|
18 | 16 | if (matchedDomain) {
|
19 | 17 | return matchedDomain.defaultLocale;
|
@@ -87,7 +85,7 @@ export const getAcceptLanguageLocale = async (
|
87 | 85 | routesManifest: RoutesManifest
|
88 | 86 | ) => {
|
89 | 87 | if (routesManifest.i18n) {
|
90 |
| - const defaultLocale = routesManifest.i18n.defaultLocale; |
| 88 | + const defaultLocale = routesManifest.i18n.defaultLocale?.toLowerCase(); |
91 | 89 | const locales = new Set(
|
92 | 90 | routesManifest.i18n.locales.map((locale) => locale.toLowerCase())
|
93 | 91 | );
|
@@ -128,3 +126,85 @@ export function getLocalePrefixFromUri(
|
128 | 126 |
|
129 | 127 | return "";
|
130 | 128 | }
|
| 129 | + |
| 130 | +/** |
| 131 | + * Get a redirect to the locale-specific domain. Returns undefined if no redirect found. |
| 132 | + * @param req |
| 133 | + * @param routesManifest |
| 134 | + */ |
| 135 | +export async function getLocaleDomainRedirect( |
| 136 | + req: Request, |
| 137 | + routesManifest: RoutesManifest |
| 138 | +): Promise<string | undefined> { |
| 139 | + // Redirect to correct domain based on user's language |
| 140 | + const domains = routesManifest.i18n?.domains; |
| 141 | + const hostHeaders = req.headers.host; |
| 142 | + if (domains && hostHeaders && hostHeaders.length > 0) { |
| 143 | + const host = hostHeaders[0].value.split(":")[0]; |
| 144 | + const languageHeader = req.headers["accept-language"]; |
| 145 | + const acceptLanguage = languageHeader && languageHeader[0]?.value; |
| 146 | + |
| 147 | + const headerCookies = req.headers.cookie |
| 148 | + ? req.headers.cookie[0]?.value |
| 149 | + : undefined; |
| 150 | + // Use cookies first, otherwise use the accept-language header |
| 151 | + let acceptLanguages: string[] = []; |
| 152 | + let nextLocale; |
| 153 | + if (headerCookies) { |
| 154 | + const cookies = parse(headerCookies); |
| 155 | + nextLocale = cookies["NEXT_LOCALE"]; |
| 156 | + } |
| 157 | + |
| 158 | + if (nextLocale) { |
| 159 | + acceptLanguages = [nextLocale.toLowerCase()]; |
| 160 | + } else { |
| 161 | + const Accept = await import("@hapi/accept"); |
| 162 | + acceptLanguages = Accept.languages(acceptLanguage).map((lang) => |
| 163 | + lang.toLowerCase() |
| 164 | + ); |
| 165 | + } |
| 166 | + |
| 167 | + // Try to find the right domain to redirect to if needed |
| 168 | + // First check current domain can support any preferred language, if so do not redirect |
| 169 | + const currentDomainData = domains.find( |
| 170 | + (domainData) => domainData.domain === host |
| 171 | + ); |
| 172 | + |
| 173 | + if (currentDomainData) { |
| 174 | + for (const language of acceptLanguages) { |
| 175 | + if ( |
| 176 | + currentDomainData.defaultLocale?.toLowerCase() === language || |
| 177 | + currentDomainData.locales |
| 178 | + ?.map((locale) => locale.toLowerCase()) |
| 179 | + .includes(language) |
| 180 | + ) { |
| 181 | + return undefined; |
| 182 | + } |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + // Try to find domain whose default locale matched preferred language in order |
| 187 | + for (const language of acceptLanguages) { |
| 188 | + for (const domainData of domains) { |
| 189 | + if (domainData.defaultLocale.toLowerCase() === language) { |
| 190 | + return `${domainData.domain}${req.uri}`; |
| 191 | + } |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | + // Try to find domain whose supported locales matches preferred language in order |
| 196 | + for (const language of acceptLanguages) { |
| 197 | + for (const domainData of domains) { |
| 198 | + if ( |
| 199 | + domainData.locales |
| 200 | + ?.map((locale) => locale.toLowerCase()) |
| 201 | + .includes(language) |
| 202 | + ) { |
| 203 | + return `${domainData.domain}${req.uri}`; |
| 204 | + } |
| 205 | + } |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + return undefined; |
| 210 | +} |
0 commit comments