From b6be5c8c31aa281e3ab151e0f99e70158ba87953 Mon Sep 17 00:00:00 2001 From: Claude Brisson Date: Sun, 26 Nov 2023 07:30:28 +0100 Subject: [PATCH] Review languages and locales; fix start/end dates and timings formats --- api-webapp/pom.xml | 6 ++ .../jeudego/pairgoth/view/TranslationTool.kt | 13 +++++ .../jeudego/pairgoth/web/LanguageFilter.kt | 48 ++++++++------- .../main/webapp/WEB-INF/layouts/standard.html | 1 + view-webapp/src/main/webapp/WEB-INF/tools.xml | 2 +- .../locales/{ar-tn.js => ar-TN.js} | 0 view-webapp/src/main/webapp/tour.html | 58 ++++++++++++------- 7 files changed, 84 insertions(+), 44 deletions(-) rename view-webapp/src/main/webapp/lib/datepicker-1.3.4/locales/{ar-tn.js => ar-TN.js} (100%) diff --git a/api-webapp/pom.xml b/api-webapp/pom.xml index 4d46cab..8281356 100644 --- a/api-webapp/pom.xml +++ b/api-webapp/pom.xml @@ -144,6 +144,12 @@ jakarta.mail 1.6.7 + + + org.apache.commons + commons-lang3 + 3.12.0 + org.pac4j diff --git a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/view/TranslationTool.kt b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/view/TranslationTool.kt index e3937d9..2c0fd63 100644 --- a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/view/TranslationTool.kt +++ b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/view/TranslationTool.kt @@ -21,6 +21,14 @@ class TranslationTool { }.let { Pair(iso, it) } } + val defaultCountry = Translator.providedLanguages.associate { iso -> + when (iso) { + "en" -> "gb" + "zh" -> "cn" + else -> iso + }.let { Pair(iso, it) } + } + fun url(request: HttpServletRequest, lang: String): String { val out = StringBuilder() out.append(request.requestURL.replaceFirst(Regex("://"), "://$lang/")) @@ -29,7 +37,12 @@ class TranslationTool { return out.toString() } + fun datepickerLocale(language: String, locale: String) = + if (datepickerLocales.contains(locale)) locale + else language + companion object { + val datepickerLocales = setOf("ar-DZ", "ar", "ar-TN", "az", "bg", "bm", "bn", "br", "bs", "ca", "cs", "cy", "da", "de", "el", "en-AU", "en-CA", "en-GB", "en-IE", "en-NZ", "en-ZA", "eo", "es", "et", "eu", "fa", "fi", "fo", "fr-CH", "fr", "gl", "he", "hi", "hr", "hu", "hy", "id", "is", "it-CH", "it", "ja", "ka", "kk", "km", "ko", "lt", "lv", "me", "mk", "mn", "mr", "ms", "nl-BE", "nl", "no", "oc", "pl", "pt-BR", "pt", "ro", "ru", "si", "sk", "sl", "sq", "sr", "sr-latn", "sv", "sw", "ta", "tg", "th", "tk", "tr", "uk", "uz-cyrl", "uz-latn", "vi", "zh-CN", "zh-TW") val translator = ThreadLocal() } } \ No newline at end of file diff --git a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/LanguageFilter.kt b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/LanguageFilter.kt index 80abcef..2581309 100644 --- a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/LanguageFilter.kt +++ b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/LanguageFilter.kt @@ -2,8 +2,10 @@ package org.jeudego.pairgoth.web import org.jeudego.pairgoth.util.Translator import org.jeudego.pairgoth.util.Translator.Companion.defaultLanguage +import org.jeudego.pairgoth.util.Translator.Companion.defaultLocale import org.jeudego.pairgoth.util.Translator.Companion.providedLanguages import org.jeudego.pairgoth.view.TranslationTool +import java.util.* import javax.servlet.Filter import javax.servlet.FilterChain import javax.servlet.FilterConfig @@ -29,52 +31,56 @@ class LanguageFilter : Filter { return } + val match = langPattern.matchEntire(uri) + val askedLanguage = match?.groupValues?.get(1) + val target = match?.groupValues?.get(2) ?: uri + val reqLang = request.getAttribute("lang") as String? if (reqLang != null) { + // this is a forwarded request, language and locale should already have been set TranslationTool.translator.set(Translator.getTranslator(reqLang)) chain.doFilter(request, response) } else { - val match = langPattern.matchEntire(uri) - val lang = match?.groupValues?.get(1) - val target = match?.groupValues?.get(2) ?: uri - - if (lang != null && providedLanguages.contains(lang)) { + val (preferredLanguage, preferredLocale) = parseLanguageHeader(request) + if (askedLanguage != null && providedLanguages.contains(askedLanguage)) { // the target URI contains a language we provide - request.setAttribute("lang", lang) + request.setAttribute("lang", askedLanguage) + request.setAttribute("loc", + if (askedLanguage == preferredLanguage) preferredLocale + else askedLanguage + ) request.setAttribute("target", target) filterConfig!!.servletContext.getRequestDispatcher(target).forward(request, response) } else { // the request must be redirected - val preferredLanguage = getPreferredLanguage(request) - val destination = if (lang != null) target else uri + val destination = if (askedLanguage != null) target else uri response.sendRedirect("/${preferredLanguage}${destination}") } } } - private fun getPreferredLanguage(request: HttpServletRequest): String { - var lang = request.session.getAttribute("lang") as String? - if (lang == null) { - parseLanguageHeader(request) - lang = request.session.getAttribute("lang") as String? - } - return lang ?: defaultLanguage - } - - private fun parseLanguageHeader(request: HttpServletRequest) { + /** + * Returns Pair(language, locale) + */ + private fun parseLanguageHeader(request: HttpServletRequest): Pair { langHeaderParser.findAll(request.getHeader("Accept-Language") ?: "").filter { providedLanguages.contains(it.groupValues[1]) }.sortedByDescending { it.groupValues[3].toDoubleOrNull() ?: 1.0 - }.firstOrNull()?.let { - it.groupValues[1] + }.firstOrNull()?.let { match -> + val lang = match.groupValues[1].let { if (it == "*") defaultLanguage else it } + val variant = match.groupValues.getOrNull(2)?.lowercase(Locale.ROOT) + // by convention, the variant is only kept if different from the language (fr-FR => fr) + val locale = variant?.let { if (lang == variant) lang else "$lang-${variant.uppercase(Locale.ROOT)}" } ?: lang + return Pair(lang, locale) } + return Pair(defaultLanguage, defaultLanguage) } override fun destroy() {} companion object { private val langPattern = Regex("/([a-z]{2})(/.+)") - private val langHeaderParser = Regex("(?:\\b(\\*|[a-z]{2})(?:(?:_|-)\\w+)?)(?:;q=([0-9.]+))?") ADD locale group captue + private val langHeaderParser = Regex("(?:\\b(\\*|[a-z]{2})(?:(?:_|-)(\\w+))?)(?:;q=([0-9.]+))?") } } diff --git a/view-webapp/src/main/webapp/WEB-INF/layouts/standard.html b/view-webapp/src/main/webapp/WEB-INF/layouts/standard.html index bdfdd80..662700e 100644 --- a/view-webapp/src/main/webapp/WEB-INF/layouts/standard.html +++ b/view-webapp/src/main/webapp/WEB-INF/layouts/standard.html @@ -70,6 +70,7 @@ - + +#if($datepickerLocale != 'en') + +#end +