2026-07-23 01:04:37 +00:00
import Foundation
2026-06-29 23:08:36 +00:00
import HTTPTypes
import Hummingbird
import Localization
/// Resolves the visitor's preferred language and records it on the request context.
///
2026-07-30 06:33:57 +00:00
/// Placed ahead of the localized responders in the middleware chain, it reads the request's `Accept-Language` header, negotiates the best supported
/// match (falling back to the default language), and stores it on the context's ``LocalizedRequestContext/language``.
2026-06-29 23:08:36 +00:00
///
2026-07-30 06:33:57 +00:00
/// The request is otherwise passed through untouched — the URL and routing are not affected — so each page is served at its existing path and varies its
/// content by header.
2026-06-29 23:08:36 +00:00
public struct LocalizationMiddleware < Context : LocalizedRequestContext > {
// MARK: Properties
/// Negotiates the request's language from its `Accept-Language` header.
2026-07-03 03:48:25 +00:00
private let negotiate : Negotiate
2026-06-29 23:08:36 +00:00
// MARK: Initializers
2026-07-23 01:04:37 +00:00
/// Creates a localization middleware that negotiates against the given bundle's String Catalog languages.
/// - Parameter bundle: the bundle whose String Catalog names the supported languages.
public init (
bundle : Bundle
) {
self . negotiate = . init ( bundle : bundle )
2026-06-29 23:08:36 +00:00
}
}
// MARK: - RouterMiddleware
extension LocalizationMiddleware : RouterMiddleware {
// MARK: Functions
/// Negotiates the request's language and records it on the context before passing it down.
/// - Parameters:
/// - request: the incoming request.
/// - context: the context the request is resolved against.
/// - next: the next responder in the middleware chain.
/// - Returns: the downstream response.
/// - Throws: any error thrown downstream.
public func handle (
_ request : Request ,
context : Context ,
next : ( Request , Context ) async throws -> Response
) async throws -> Response {
var context = context
context . language = negotiate (
2026-07-03 03:48:25 +00:00
acceptLanguage : request . headers [. acceptLanguage ]
2026-06-29 23:08:36 +00:00
)
return try await next ( request , context )
}
}