42 lines
1.5 KiB
Swift
42 lines
1.5 KiB
Swift
import Foundation
|
|||
|
|
import HTTPTypes
|
||
|
|
import Hummingbird
|
||
|
|
import Localization
|
||
|
|
|
||
|
|
public extension Negotiate {
|
||
|
|
|
||
|
|
// MARK: Methods
|
||
|
|
|
||
|
|
/// The language to serve a request in.
|
||
|
|
///
|
||
|
|
/// The `lang` query parameter wins as a deliberate override; failing that, a leading path segment naming a supported language pins it, so an
|
||
|
|
/// unrouted path under a language's prefix answers in that language. Anything naming no supported language is ignored, leaving the
|
||
|
|
/// `Accept-Language` header and its fallback to the default.
|
||
|
|
///
|
||
|
|
/// Called where the answer is used rather than stamped onto every request on the way past: page routes that pin their language by URL never ask.
|
||
|
|
/// - Parameter request: the request to negotiate for.
|
||
|
|
/// - Returns: the identifier of the supported language to serve.
|
||
|
|
func callAsFunction(
|
||
|
|
for request: Request
|
||
|
|
) -> String {
|
||
|
|
let requested = request.uri.queryParameters[.Parameter.language].map(String.init)
|
||
|
|
?? request.uri.path.split(separator: "/").first.map(String.init)
|
||
|
|
|
||
|
|
return callAsFunction(
|
||
|
|
requested: requested,
|
||
|
|
acceptLanguage: request.headers[.acceptLanguage]
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Constants
|
||
|
|
|
||
|
|
private extension Substring {
|
||
|
|
/// A namespace for the query parameters the negotiation reads.
|
||
|
|
enum Parameter {
|
||
|
|
/// The query parameter carrying an explicit language choice; the site's language switcher appends it to the current path.
|
||
|
|
static let language: Substring = "lang"
|
||
|
|
}
|
||
|
|
}
|