import HTTPTypes import Hummingbird import Localization /// Resolves the visitor's preferred language and records it on the request context. /// /// 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``. /// /// 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. public struct LocalizationMiddleware { // MARK: Properties /// Negotiates the request's language from its `Accept-Language` header. private let negotiate: NegotiateLanguage // MARK: Initializers /// Creates a localization middleware. public init() { self.negotiate = .init() } } // 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( forAcceptLanguage: request.headers[.acceptLanguage] ) return try await next(request, context) } }