From 498d6168a0f47b0f93bab75d65b87c34670535f1 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Tue, 29 Oct 2019 15:54:11 +0100 Subject: [PATCH] feat(i18n): populate frontend datetime locale from backend settings --- frontend/src/services/i18n/i18n.js | 33 +++++++++++++++++++++++---- frontend/src/utils/form/datepicker.js | 8 +++---- src/Foundation.hs | 1 + src/Utils/Frontend/I18n.hs | 8 +++++++ src/Utils/Lang.hs | 4 +--- templates/i18n.julius | 2 +- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/frontend/src/services/i18n/i18n.js b/frontend/src/services/i18n/i18n.js index 7061f6ba6..fd383b1b6 100644 --- a/frontend/src/services/i18n/i18n.js +++ b/frontend/src/services/i18n/i18n.js @@ -1,3 +1,5 @@ +import moment from 'moment'; + /** * I18n * @@ -13,10 +15,15 @@ export class I18n { - translations = {}; + _translations = {}; + _datetimeLocale = undefined; add(id, translation) { - this.translations[id] = translation; + if (!this._translations[id]) { + this._translations[id] = translation; + } else { + throw new Error('I18N Error: Attempting to set translation multiple times for »' + id + '«!'); + } } addMany(manyTranslations) { @@ -24,9 +31,27 @@ export class I18n { } get(id) { - if (!this.translations[id]) { + if (!this._translations[id]) { throw new Error('I18N Error: Translation missing for »' + id + '«!'); } - return this.translations[id]; + return this._translations[id]; + } + + + setDatetimeLocale(locale) { + if (!this._datetimeLocale) { + moment.locale(locale); + this._datetimeLocale = locale; + } else { + throw new Error('I18N Error: Attempting to set datetime locale multiple times!'); + } + } + + getDatetimeLocale() { + if (!this._datetimeLocale) { + throw new Error('I18N Error: Attempting to access datetime locale when it has not been set!'); + } + + return this._datetimeLocale; } } diff --git a/frontend/src/utils/form/datepicker.js b/frontend/src/utils/form/datepicker.js index 2cc4972c8..b8ba0869f 100644 --- a/frontend/src/utils/form/datepicker.js +++ b/frontend/src/utils/form/datepicker.js @@ -48,9 +48,6 @@ const DATEPICKER_CONFIG = { timeMinutes: 0, timeSeconds: 0, - // german settings - // TODO: hardcoded, get from current language / settings - locale: 'de', weekStart: 1, dateFormat: FORM_DATE_FORMAT_DATE_DT, timeFormat: FORM_DATE_FORMAT_TIME_DT, @@ -86,6 +83,7 @@ export class Datepicker { datepickerInstance; _element; elementType; + _locale; constructor(element) { if (!element) { @@ -96,6 +94,8 @@ export class Datepicker { return false; } + this._locale = window.App.i18n.getDatetimeLocale(); + // initialize datepickerCollections singleton if not already done if (!Datepicker.datepickerCollections) { Datepicker.datepickerCollections = new Map(); @@ -134,7 +134,7 @@ export class Datepicker { } // initialize tail.datetime (datepicker) instance and let it do weird stuff with the element value - this.datepickerInstance = datetime(this._element, { ...datepickerGlobalConfig, ...datepickerConfig }); + this.datepickerInstance = datetime(this._element, { ...datepickerGlobalConfig, ...datepickerConfig, locale: this._locale }); // reset date to something sane if (parsedMomentDate) diff --git a/src/Foundation.hs b/src/Foundation.hs index 34b7d6013..50d2b538d 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -1930,6 +1930,7 @@ siteLayout' headingOverride widget = do let -- See Utils.Frontend.I18n and files in messages/frontend for message definitions frontendI18n = toJSON (mr :: FrontendMessage -> Text) + frontendDatetimeLocale <- toJSON <$> selectLanguage frontendDatetimeLocales pc <- widgetToPageContent $ do -- fonts diff --git a/src/Utils/Frontend/I18n.hs b/src/Utils/Frontend/I18n.hs index 9c8533496..1d1c24652 100644 --- a/src/Utils/Frontend/I18n.hs +++ b/src/Utils/Frontend/I18n.hs @@ -1,5 +1,6 @@ module Utils.Frontend.I18n ( FrontendMessage(..) + , frontendDatetimeLocales ) where import ClassyPrelude @@ -14,6 +15,9 @@ import Data.Aeson.Types (toJSONKeyText) import Data.Aeson.TH import qualified Data.Char as Char +import Data.List.NonEmpty (NonEmpty(..)) +import Text.Shakespeare.I18N (Lang) + -- | I18n-Messages used in JavaScript-Frontend -- @@ -39,3 +43,7 @@ instance ToJSONKey FrontendMessage where toJSONKey = toJSONKeyText toPathPiece instance FromJSONKey FrontendMessage where fromJSONKey = FromJSONKeyTextParser $ parseJSON . String + + +frontendDatetimeLocales :: NonEmpty Lang +frontendDatetimeLocales = "de" :| ["en"] diff --git a/src/Utils/Lang.hs b/src/Utils/Lang.hs index fe41e110f..3280c62fc 100644 --- a/src/Utils/Lang.hs +++ b/src/Utils/Lang.hs @@ -11,8 +11,6 @@ import qualified Data.List as List import qualified Data.CaseInsensitive as CI -import Control.Lens (none) - import Yesod.Core.Types (HandlerData(handlerRequest), YesodRequest(reqLangs)) import qualified Network.Wai.Parse as NWP @@ -41,7 +39,7 @@ selectLanguages avL (l:ls) , l'' <- matchesFor l' , langMatches lParts' l'' ] - = let now = nonEmpty . filter (\l' -> none (((==) `on` CI.mk) l') ls) $ sortOn (Down . length) found + = let now = nonEmpty $ sortOn (Down . length) found others = selectLanguages avL ls in maybe id (\now' others' -> NonEmpty.fromList $ toList now' ++ filter (`notElem` toList now') (toList others')) now others | otherwise = selectLanguages avL ls diff --git a/templates/i18n.julius b/templates/i18n.julius index 97c088a81..690f8da89 100644 --- a/templates/i18n.julius +++ b/templates/i18n.julius @@ -1,6 +1,6 @@ if (window.App) { window.App.i18n.addMany(#{frontendI18n}); - // window.App.i18n.setLang(lang); TODO: set language string for datepicker config + window.App.i18n.setDatetimeLocale(#{frontendDatetimeLocale}); } else { throw new Error('I18n JavaScript service is missing!'); }