11import type { Handle } from "@sveltejs/kit" ;
2- import { THEME_COOKIE_NAME } from "./lib/constants" ;
2+ import {
3+ DEFAULT_LOCALE ,
4+ LOCALE_COOKIE_NAME ,
5+ SUPPORTED_LOCALES ,
6+ THEME_COOKIE_NAME ,
7+ } from "./lib/constants" ;
8+
9+ type LocaleCookie = {
10+ preference ?: "auto" | "manual" ;
11+ locale ?: string ;
12+ } ;
13+
14+ function resolveSupportedLocale ( locale : string ) : string {
15+ let normalized = locale . replace ( "_" , "-" ) . trim ( ) ;
16+ let lower = normalized . toLowerCase ( ) ;
17+ let exact = SUPPORTED_LOCALES . find ( ( supported ) => supported . toLowerCase ( ) === lower ) ;
18+ if ( exact ) return exact ;
19+ let base = lower . split ( "-" ) [ 0 ] ;
20+ let baseMatch = SUPPORTED_LOCALES . find ( ( supported ) => supported . toLowerCase ( ) === base ) ;
21+ if ( baseMatch ) return baseMatch ;
22+ if ( base === "zh" ) return "zh-Hans" ;
23+ return DEFAULT_LOCALE ;
24+ }
25+
26+ function normalizeLocale ( locale : string | undefined ) : string {
27+ if ( ! locale ) return DEFAULT_LOCALE ;
28+ return resolveSupportedLocale ( locale ) ;
29+ }
30+
31+ function parseAcceptLanguage ( value : string | null ) : string | undefined {
32+ if ( ! value ) return undefined ;
33+ let candidates = value
34+ . split ( "," )
35+ . map ( ( part ) => {
36+ let [ tag , qValue ] = part . trim ( ) . split ( ";q=" ) ;
37+ let q = qValue ? Number . parseFloat ( qValue ) : 1 ;
38+ return { tag, q : Number . isNaN ( q ) ? 0 : q } ;
39+ } )
40+ . filter ( ( entry ) => entry . tag ) ;
41+ candidates . sort ( ( a , b ) => b . q - a . q ) ;
42+ return candidates [ 0 ] ?. tag ;
43+ }
344
445export const handle : Handle = async ( { event, resolve } ) => {
546 let theme = "system" ;
@@ -8,9 +49,34 @@ export const handle: Handle = async ({ event, resolve }) => {
849 theme = JSON . parse ( cookieVal ?? "" ) . preference ?? "system" ;
950 } catch { }
1051
52+ let detectedLocale = normalizeLocale (
53+ parseAcceptLanguage ( event . request . headers . get ( "accept-language" ) )
54+ ) ;
55+ let localePreference : "auto" | "manual" = "auto" ;
56+ let manualLocale : string | null = null ;
57+ let locale = detectedLocale ;
58+
59+ try {
60+ let cookieVal = event . cookies . get ( LOCALE_COOKIE_NAME ) ;
61+ let parsed = JSON . parse ( cookieVal ?? "" ) as LocaleCookie ;
62+ if ( parsed ?. locale ) {
63+ manualLocale = normalizeLocale ( parsed . locale ) ;
64+ }
65+ if ( parsed ?. preference === "manual" && manualLocale ) {
66+ localePreference = "manual" ;
67+ locale = manualLocale ;
68+ }
69+ } catch { }
70+
71+ event . locals . locale = locale ;
72+ event . locals . localePreference = localePreference ;
73+ event . locals . manualLocale = manualLocale ;
74+ event . locals . detectedLocale = detectedLocale ;
75+
1176 let response = await resolve ( event , {
1277 filterSerializedResponseHeaders : ( name ) => [ "content-type" ] . indexOf ( name ) != - 1 ,
13- transformPageChunk : ( { html } ) => html . replace ( "%theme%" , `class="${ theme } "` ) ,
78+ transformPageChunk : ( { html } ) =>
79+ html . replace ( "%theme%" , `class="${ theme } "` ) . replace ( "%lang%" , locale ) ,
1480 } ) ;
1581
1682 return response ;
0 commit comments