diff --git a/src/frame/middleware/index.ts b/src/frame/middleware/index.ts index 46d5c3263c0a..cc470946f46d 100644 --- a/src/frame/middleware/index.ts +++ b/src/frame/middleware/index.ts @@ -21,7 +21,7 @@ import detectLanguage from '@/languages/middleware/detect-language' import reloadTree from './reload-tree' import context from './context/context' import shortVersions from '@/versions/middleware/short-versions.js' -import languageCodeRedirects from '@/redirects/middleware/language-code-redirects.js' +import languageCodeRedirects from '@/redirects/middleware/language-code-redirects' import handleRedirects from '@/redirects/middleware/handle-redirects' import findPage from './find-page.js' import blockRobots from './block-robots.js' diff --git a/src/languages/lib/languages.d.ts b/src/languages/lib/languages.d.ts new file mode 100644 index 000000000000..6129a4ac88b2 --- /dev/null +++ b/src/languages/lib/languages.d.ts @@ -0,0 +1,23 @@ +type Language = { + name: string + nativeName?: string + code: string + hreflang: string + redirectPatterns?: RegExp[] + dir: string +} +type Languages = { + [code: string]: Language +} + +export const allLanguageKeys: string[] + +export const languageKeys: string[] + +export const languagePrefixPathRegex: RegExp + +export declare function pathLanguagePrefixed(path: string): boolean + +const languages: Languages + +export default languages diff --git a/src/redirects/middleware/language-code-redirects.js b/src/redirects/middleware/language-code-redirects.ts similarity index 62% rename from src/redirects/middleware/language-code-redirects.js rename to src/redirects/middleware/language-code-redirects.ts index d1150b2669d7..1b64ef769855 100644 --- a/src/redirects/middleware/language-code-redirects.js +++ b/src/redirects/middleware/language-code-redirects.ts @@ -1,5 +1,8 @@ -import languages from '#src/languages/lib/languages.js' -import { defaultCacheControl } from '#src/frame/middleware/cache-control.js' +import type { NextFunction, Response } from 'express' + +import languages from '@/languages/lib/languages.js' +import { defaultCacheControl } from '@/frame/middleware/cache-control.js' +import { ExtendedRequest } from '@/types' const redirectPatterns = Object.values(languages) .map((language) => language.redirectPatterns || []) @@ -16,14 +19,18 @@ const allRedirectPatterns = Object.values(languages) .map((language) => (language.redirectPatterns || []).map((redirectPattern) => [language.code, redirectPattern]), ) - .flat() + .flat() as [string, RegExp][] // Seems TypeScript didn't understand the .flat() // This middleware handles redirects for mistyped language codes // // Examples: // /jp* -> /ja* // /zh-TW* -> /zh* -export default function languageCodeRedirects(req, res, next) { +export default function languageCodeRedirects( + req: ExtendedRequest, + res: Response, + next: NextFunction, +) { // Only in the unlikely event that the `req.path` starts with one of these // prefixes do we bother looking up what the redirect should be. if (req.path.startsWith('/_next/static')) return next() @@ -32,10 +39,13 @@ export default function languageCodeRedirects(req, res, next) { // This loop is almost never ever used so it doesn't have to be // particularly smart or fast. - const [code, pattern] = allRedirectPatterns.find(([, pattern]) => pattern.test(req.path)) - if (code && pattern) { - defaultCacheControl(res) - return res.redirect(301, req.path.replace(pattern, `/${code}`)) + const matched = allRedirectPatterns.find(([, pattern]) => pattern.test(req.path)) + if (matched) { + const [code, pattern] = matched + if (code && pattern) { + defaultCacheControl(res) + return res.redirect(301, req.path.replace(pattern, `/${code}`)) + } } return next() }