UNPKG

next-intl

Version:

Internationalization (i18n) for Next.js

92 lines (87 loc) 3.53 kB
import { normalizeTrailingSlash } from '../shared/utils.js'; import { getHost, getNormalizedPathname, getLocalePrefixes, isLocaleSupportedOnDomain, applyBasePath, formatTemplatePathname } from './utils.js'; /** * See https://developers.google.com/search/docs/specialty/international/localized-versions */ function getAlternateLinksHeaderValue({ internalTemplateName, localizedPathnames, request, resolvedLocale, routing }) { const normalizedUrl = request.nextUrl.clone(); const host = getHost(request.headers); if (host) { normalizedUrl.port = ''; normalizedUrl.host = host; } normalizedUrl.protocol = request.headers.get('x-forwarded-proto') ?? normalizedUrl.protocol; normalizedUrl.pathname = getNormalizedPathname(normalizedUrl.pathname, routing.locales, routing.localePrefix); function getAlternateEntry(url, locale) { url.pathname = normalizeTrailingSlash(url.pathname); if (request.nextUrl.basePath) { url = new URL(url); url.pathname = applyBasePath(url.pathname, request.nextUrl.basePath); } return `<${url.toString()}>; rel="alternate"; hreflang="${locale}"`; } function getLocalizedPathname(pathname, locale) { if (localizedPathnames && typeof localizedPathnames === 'object') { const sourceTemplate = localizedPathnames[resolvedLocale]; return formatTemplatePathname(pathname, sourceTemplate ?? internalTemplateName, localizedPathnames[locale] ?? internalTemplateName); } else { return pathname; } } const links = getLocalePrefixes(routing.locales, routing.localePrefix, false).flatMap(([locale, prefix]) => { function prefixPathname(pathname) { if (pathname === '/') { return prefix; } else { return prefix + pathname; } } let url; if (routing.domains) { const domainConfigs = routing.domains.filter(cur => isLocaleSupportedOnDomain(locale, cur)); return domainConfigs.map(domainConfig => { url = new URL(normalizedUrl); url.port = ''; url.host = domainConfig.domain; // Important: Use `normalizedUrl` here, as `url` potentially uses // a `basePath` that automatically gets applied to the pathname url.pathname = getLocalizedPathname(normalizedUrl.pathname, locale); if (locale !== domainConfig.defaultLocale || routing.localePrefix.mode === 'always') { url.pathname = prefixPathname(url.pathname); } return getAlternateEntry(url, locale); }); } else { let pathname; if (localizedPathnames && typeof localizedPathnames === 'object') { pathname = getLocalizedPathname(normalizedUrl.pathname, locale); } else { pathname = normalizedUrl.pathname; } if (locale !== routing.defaultLocale || routing.localePrefix.mode === 'always') { pathname = prefixPathname(pathname); } url = new URL(pathname, normalizedUrl); } return getAlternateEntry(url, locale); }); // Add x-default entry const shouldAddXDefault = // For domain-based routing there is no reasonable x-default !routing.domains || routing.domains.length === 0; if (shouldAddXDefault) { const localizedPathname = getLocalizedPathname(normalizedUrl.pathname, routing.defaultLocale); if (localizedPathname) { const url = new URL(localizedPathname, normalizedUrl); links.push(getAlternateEntry(url, 'x-default')); } } return links.join(', '); } export { getAlternateLinksHeaderValue as default };