Sat, 06 Jan 2024 20:31:14 +0100
add language selection cookie - fixes #352
1.1 --- a/build.gradle.kts Fri Nov 24 00:07:36 2023 +0100 1.2 +++ b/build.gradle.kts Sat Jan 06 20:31:14 2024 +0100 1.3 @@ -5,7 +5,7 @@ 1.4 war 1.5 } 1.6 group = "de.uapcore" 1.7 -version = "1.2.1" 1.8 +version = "1.2.2" 1.9 1.10 repositories { 1.11 mavenCentral() 1.12 @@ -37,7 +37,7 @@ 1.13 arrayOf( 1.14 "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.0", 1.15 "org.glassfish.web:jakarta.servlet.jsp.jstl:3.0.1", 1.16 - "org.postgresql:postgresql:42.6.0" 1.17 + "org.postgresql:postgresql:42.7.1" 1.18 ).forEach { 1.19 if (libsAreProvided) compileOnly(it) else implementation(it) 1.20 }
2.1 --- a/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt Fri Nov 24 00:07:36 2023 +0100 2.2 +++ b/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt Sat Jan 06 20:31:14 2024 +0100 2.3 @@ -28,6 +28,7 @@ 2.4 import de.uapcore.lightpit.DataSourceProvider.Companion.SC_ATTR_NAME 2.5 import de.uapcore.lightpit.dao.DataAccessObject 2.6 import de.uapcore.lightpit.dao.createDataAccessObject 2.7 +import jakarta.servlet.http.Cookie 2.8 import jakarta.servlet.http.HttpServlet 2.9 import jakarta.servlet.http.HttpServletRequest 2.10 import jakarta.servlet.http.HttpServletResponse 2.11 @@ -35,6 +36,10 @@ 2.12 import java.util.* 2.13 2.14 abstract class AbstractServlet : HttpServlet() { 2.15 + 2.16 + companion object { 2.17 + const val LANGUAGE_COOKIE_NAME = "lpit_language" 2.18 + } 2.19 2.20 protected val logger = MyLogger() 2.21 2.22 @@ -100,22 +105,6 @@ 2.23 // the very first thing to do is to force UTF-8 2.24 req.characterEncoding = "UTF-8" 2.25 2.26 - // choose the requested language as session language (if available) or fall back to english, otherwise 2.27 - if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) { 2.28 - val availableLanguages = availableLanguages() 2.29 - val reqLocale = req.locale 2.30 - val sessionLocale = if (availableLanguages.contains(reqLocale)) reqLocale else availableLanguages.first() 2.31 - session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale) 2.32 - resp.locale = sessionLocale 2.33 - logger.debug( 2.34 - "Setting language for new session {0}: {1}", session.id, sessionLocale.displayLanguage 2.35 - ) 2.36 - } else { 2.37 - val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale 2.38 - resp.locale = sessionLocale 2.39 - logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale) 2.40 - } 2.41 - 2.42 // set some internal request attributes 2.43 val http = HttpRequest(req, resp) 2.44 val fullPath = req.servletPath + Optional.ofNullable(req.pathInfo).orElse("") 2.45 @@ -126,6 +115,29 @@ 2.46 req.setAttribute(Constants.REQ_ATTR_REFERER, it) 2.47 } 2.48 2.49 + // choose the requested language as session language (if available) 2.50 + if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) { 2.51 + // language selection stored in cookie 2.52 + val cookieLocale = cookieLanguage(http) 2.53 + 2.54 + // if no cookie, fall back to request locale a.k.a "Browser Language" 2.55 + val reqLocale = cookieLocale ?: req.locale 2.56 + 2.57 + val availableLanguages = availableLanguages() 2.58 + val sessionLocale = if (availableLanguages.contains(reqLocale)) reqLocale else availableLanguages.first() 2.59 + 2.60 + // select the language (this will also refresh the cookie max-age) 2.61 + selectLanguage(http, sessionLocale) 2.62 + 2.63 + logger.debug( 2.64 + "Setting language for new session {0}: {1}", session.id, sessionLocale.displayLanguage 2.65 + ) 2.66 + } else { 2.67 + val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale 2.68 + resp.locale = sessionLocale 2.69 + logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale) 2.70 + } 2.71 + 2.72 // if this is an error path, bypass the normal flow 2.73 if (fullPath.startsWith("/error/")) { 2.74 http.styleSheets = listOf("error") 2.75 @@ -182,4 +194,23 @@ 2.76 return locales.ifEmpty { listOf(Locale.ENGLISH) } 2.77 } 2.78 2.79 + private fun cookieLanguage(http: HttpRequest): Locale? = 2.80 + http.request.cookies?.firstOrNull { c -> c.name == LANGUAGE_COOKIE_NAME } 2.81 + ?.runCatching {Locale.forLanguageTag(this.value)}?.getOrNull() 2.82 + 2.83 + protected fun selectLanguage(http: HttpRequest, locale: Locale) { 2.84 + http.response.locale = locale 2.85 + http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale) 2.86 + // delete cookie if language selection matches request locale, otherwise set cookie 2.87 + val cookie = Cookie(LANGUAGE_COOKIE_NAME, "") 2.88 + cookie.isHttpOnly = true 2.89 + cookie.path = http.request.contextPath 2.90 + if (http.request.locale.language == locale.language) { 2.91 + cookie.maxAge = 0 2.92 + } else { 2.93 + cookie.value = locale.language 2.94 + cookie.maxAge = 2592000 // 30 days 2.95 + } 2.96 + http.response.addCookie(cookie) 2.97 + } 2.98 }
3.1 --- a/src/main/kotlin/de/uapcore/lightpit/servlet/LanguageServlet.kt Fri Nov 24 00:07:36 2023 +0100 3.2 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/LanguageServlet.kt Sat Jan 06 20:31:14 2024 +0100 3.3 @@ -58,8 +58,7 @@ 3.4 if (lang != null) { 3.5 val locale = Locale.forLanguageTag(lang) 3.6 if (!locale.language.isNullOrBlank()) { 3.7 - http.response.locale = locale 3.8 - http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale) 3.9 + super.selectLanguage(http, locale) 3.10 } 3.11 } 3.12
4.1 --- a/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf Fri Nov 24 00:07:36 2023 +0100 4.2 +++ b/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf Sat Jan 06 20:31:14 2024 +0100 4.3 @@ -24,6 +24,12 @@ 4.4 --%> 4.5 <%@ page contentType="text/html;charset=UTF-8" %> 4.6 4.7 +<h3>Version 1.2.2</h3> 4.8 + 4.9 +<ul> 4.10 + <li>Eine Ă„nderung der Sprache wird nun auch in einem Cookie gespeichert.</li> 4.11 +</ul> 4.12 + 4.13 <h3>Version 1.2.1</h3> 4.14 4.15 <ul>
5.1 --- a/src/main/webapp/WEB-INF/changelogs/changelog.jspf Fri Nov 24 00:07:36 2023 +0100 5.2 +++ b/src/main/webapp/WEB-INF/changelogs/changelog.jspf Sat Jan 06 20:31:14 2024 +0100 5.3 @@ -24,6 +24,12 @@ 5.4 --%> 5.5 <%@ page contentType="text/html;charset=UTF-8" %> 5.6 5.7 +<h3>Version 1.2.2</h3> 5.8 + 5.9 +<ul> 5.10 + <li>Active language selection is now also stored in a cookie.</li> 5.11 +</ul> 5.12 + 5.13 <h3>Version 1.2.1</h3> 5.14 5.15 <ul>