@@ -790,6 +790,11 @@ def get_language(request: Request) -> str:
790790 str
791791 The language code ("fr" or "en"). Defaults to "fr" if none matched.
792792 """
793+ # 1) Query param takes precedence for SEO-friendly alternate URLs
794+ query_lang = request .query_params .get ("lang" ) or request .query_params .get ("hl" )
795+ if query_lang in TRANSLATIONS :
796+ return query_lang
797+ # 2) Cookie value
793798 cookie_lang = request .cookies .get ("lang" )
794799 if cookie_lang in TRANSLATIONS :
795800 return cookie_lang
@@ -1013,7 +1018,15 @@ async def home(request: Request):
10131018 return templates .TemplateResponse (
10141019 name = "home.html" ,
10151020 request = request ,
1016- context = ctx (request , {"partners" : PARTNERS , "news_home" : news_items }),
1021+ context = ctx (
1022+ request ,
1023+ {
1024+ "partners" : PARTNERS ,
1025+ "news_home" : news_items ,
1026+ "meta_title" : TRANSLATIONS [lang ]["home-title" ] + " — Python Togo" ,
1027+ "meta_description" : TRANSLATIONS [lang ]["footer-about-desc" ],
1028+ },
1029+ ),
10171030 )
10181031
10191032
@@ -1036,8 +1049,17 @@ async def about(request: Request):
10361049 --------
10371050 ``GET /about``
10381051 """
1052+ lang = get_language (request )
10391053 return templates .TemplateResponse (
1040- name = "about.html" , request = request , context = ctx (request )
1054+ name = "about.html" ,
1055+ request = request ,
1056+ context = ctx (
1057+ request ,
1058+ {
1059+ "meta_title" : TRANSLATIONS [lang ]["about-title" ] + " — Python Togo" ,
1060+ "meta_description" : TRANSLATIONS [lang ]["about-blurb" ],
1061+ },
1062+ ),
10411063 )
10421064
10431065
@@ -1075,7 +1097,16 @@ async def events(request: Request):
10751097 )
10761098 items = sorted (items , key = lambda x : x ["date" ], reverse = True )
10771099 return templates .TemplateResponse (
1078- request = request , name = "events.html" , context = ctx (request , {"events" : items })
1100+ request = request ,
1101+ name = "events.html" ,
1102+ context = ctx (
1103+ request ,
1104+ {
1105+ "events" : items ,
1106+ "meta_title" : TRANSLATIONS [lang ]["events-title" ] + " — Python Togo" ,
1107+ "meta_description" : TRANSLATIONS [lang ]["events-sample-desc" ],
1108+ },
1109+ ),
10791110 )
10801111
10811112
@@ -1113,7 +1144,16 @@ async def event_detail(event_id: int, request: Request):
11131144 "description" : tr .get ("description" , "" ),
11141145 }
11151146 return templates .TemplateResponse (
1116- request = request , name = "event_detail.html" , context = ctx (request , {"item" : item })
1147+ request = request ,
1148+ name = "event_detail.html" ,
1149+ context = ctx (
1150+ request ,
1151+ {
1152+ "item" : item ,
1153+ "meta_title" : item ["title" ] + " — Python Togo" ,
1154+ "meta_description" : item ["description" ],
1155+ },
1156+ ),
11171157 )
11181158
11191159
@@ -1151,7 +1191,16 @@ async def actualities(request: Request):
11511191 }
11521192 )
11531193 return templates .TemplateResponse (
1154- request = request , name = "actualites.html" , context = ctx (request , {"news" : items })
1194+ request = request ,
1195+ name = "actualites.html" ,
1196+ context = ctx (
1197+ request ,
1198+ {
1199+ "news" : items ,
1200+ "meta_title" : TRANSLATIONS [lang ]["news-title" ] + " — Python Togo" ,
1201+ "meta_description" : TRANSLATIONS [lang ]["footer-about-desc" ],
1202+ },
1203+ ),
11551204 )
11561205
11571206
@@ -1190,7 +1239,17 @@ async def news_detail(news_id: int, request: Request):
11901239 or f"https://picsum.photos/seed/news-{ found ['id' ]} /1200/680" ,
11911240 }
11921241 return templates .TemplateResponse (
1193- request = request , name = "news_detail.html" , context = ctx (request , {"item" : item })
1242+ request = request ,
1243+ name = "news_detail.html" ,
1244+ context = ctx (
1245+ request ,
1246+ {
1247+ "item" : item ,
1248+ "meta_title" : item ["title" ] + " — Python Togo" ,
1249+ "meta_description" : item ["body" ][:160 ],
1250+ "meta_image" : item .get ("image" ),
1251+ },
1252+ ),
11941253 )
11951254
11961255
@@ -1209,10 +1268,18 @@ async def partners(request: Request):
12091268 fastapi.responses.HTMLResponse
12101269 Rendered template response.
12111270 """
1271+ lang = get_language (request )
12121272 return templates .TemplateResponse (
12131273 request = request ,
12141274 name = "partners.html" ,
1215- context = ctx (request , {"partners" : PARTNERS }),
1275+ context = ctx (
1276+ request ,
1277+ {
1278+ "partners" : PARTNERS ,
1279+ "meta_title" : TRANSLATIONS [lang ]["nav-partners" ] + " — Python Togo" ,
1280+ "meta_description" : TRANSLATIONS [lang ]["partners-intro" ],
1281+ },
1282+ ),
12161283 )
12171284
12181285
@@ -1231,8 +1298,17 @@ async def communities(request: Request):
12311298 fastapi.responses.HTMLResponse
12321299 Rendered template response.
12331300 """
1301+ lang = get_language (request )
12341302 return templates .TemplateResponse (
1235- request = request , name = "communities.html" , context = ctx (request )
1303+ request = request ,
1304+ name = "communities.html" ,
1305+ context = ctx (
1306+ request ,
1307+ {
1308+ "meta_title" : TRANSLATIONS [lang ]["nav-communities" ] + " — Python Togo" ,
1309+ "meta_description" : TRANSLATIONS [lang ]["communities-card-desc" ],
1310+ },
1311+ ),
12361312 )
12371313
12381314
@@ -1251,8 +1327,17 @@ async def join(request: Request):
12511327 fastapi.responses.HTMLResponse
12521328 Rendered template response.
12531329 """
1330+ lang = get_language (request )
12541331 return templates .TemplateResponse (
1255- request = request , name = "join.html" , context = ctx (request )
1332+ request = request ,
1333+ name = "join.html" ,
1334+ context = ctx (
1335+ request ,
1336+ {
1337+ "meta_title" : TRANSLATIONS [lang ]["join-title" ] + " — Python Togo" ,
1338+ "meta_description" : TRANSLATIONS [lang ]["join-intro" ],
1339+ },
1340+ ),
12561341 )
12571342
12581343
@@ -1271,8 +1356,17 @@ async def contact(request: Request):
12711356 fastapi.responses.HTMLResponse
12721357 Rendered template response.
12731358 """
1359+ lang = get_language (request )
12741360 return templates .TemplateResponse (
1275- request = request , name = "contact.html" , context = ctx (request )
1361+ request = request ,
1362+ name = "contact.html" ,
1363+ context = ctx (
1364+ request ,
1365+ {
1366+ "meta_title" : TRANSLATIONS [lang ]["contact-title" ] + " — Python Togo" ,
1367+ "meta_description" : TRANSLATIONS [lang ]["contact-intro" ],
1368+ },
1369+ ),
12761370 )
12771371
12781372
@@ -1291,8 +1385,17 @@ async def code_of_conduct(request: Request):
12911385 fastapi.responses.HTMLResponse
12921386 Rendered template response.
12931387 """
1388+ lang = get_language (request )
12941389 return templates .TemplateResponse (
1295- request = request , name = "code_of_conduct.html" , context = ctx (request )
1390+ request = request ,
1391+ name = "code_of_conduct.html" ,
1392+ context = ctx (
1393+ request ,
1394+ {
1395+ "meta_title" : TRANSLATIONS [lang ]["coc-title" ] + " — Python Togo" ,
1396+ "meta_description" : TRANSLATIONS [lang ]["coc-intro" ],
1397+ },
1398+ ),
12961399 )
12971400
12981401
@@ -1513,8 +1616,17 @@ async def privacy(request: Request):
15131616 fastapi.responses.HTMLResponse
15141617 Rendered template response.
15151618 """
1619+ lang = get_language (request )
15161620 return templates .TemplateResponse (
1517- request = request , name = "privacy.html" , context = ctx (request )
1621+ request = request ,
1622+ name = "privacy.html" ,
1623+ context = ctx (
1624+ request ,
1625+ {
1626+ "meta_title" : TRANSLATIONS [lang ]["privacy-title" ] + " — Python Togo" ,
1627+ "meta_description" : TRANSLATIONS [lang ]["privacy-intro" ],
1628+ },
1629+ ),
15181630 )
15191631
15201632
0 commit comments