feat(i18n): populate frontend datetime locale from backend settings

This commit is contained in:
Gregor Kleen 2019-10-29 15:54:11 +01:00
parent 83a458ddf5
commit 498d6168a0
6 changed files with 44 additions and 12 deletions

View File

@ -1,3 +1,5 @@
import moment from 'moment';
/** /**
* I18n * I18n
* *
@ -13,10 +15,15 @@
export class I18n { export class I18n {
translations = {}; _translations = {};
_datetimeLocale = undefined;
add(id, translation) { 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) { addMany(manyTranslations) {
@ -24,9 +31,27 @@ export class I18n {
} }
get(id) { get(id) {
if (!this.translations[id]) { if (!this._translations[id]) {
throw new Error('I18N Error: Translation missing for »' + 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;
} }
} }

View File

@ -48,9 +48,6 @@ const DATEPICKER_CONFIG = {
timeMinutes: 0, timeMinutes: 0,
timeSeconds: 0, timeSeconds: 0,
// german settings
// TODO: hardcoded, get from current language / settings
locale: 'de',
weekStart: 1, weekStart: 1,
dateFormat: FORM_DATE_FORMAT_DATE_DT, dateFormat: FORM_DATE_FORMAT_DATE_DT,
timeFormat: FORM_DATE_FORMAT_TIME_DT, timeFormat: FORM_DATE_FORMAT_TIME_DT,
@ -86,6 +83,7 @@ export class Datepicker {
datepickerInstance; datepickerInstance;
_element; _element;
elementType; elementType;
_locale;
constructor(element) { constructor(element) {
if (!element) { if (!element) {
@ -96,6 +94,8 @@ export class Datepicker {
return false; return false;
} }
this._locale = window.App.i18n.getDatetimeLocale();
// initialize datepickerCollections singleton if not already done // initialize datepickerCollections singleton if not already done
if (!Datepicker.datepickerCollections) { if (!Datepicker.datepickerCollections) {
Datepicker.datepickerCollections = new Map(); 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 // 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 // reset date to something sane
if (parsedMomentDate) if (parsedMomentDate)

View File

@ -1930,6 +1930,7 @@ siteLayout' headingOverride widget = do
let let
-- See Utils.Frontend.I18n and files in messages/frontend for message definitions -- See Utils.Frontend.I18n and files in messages/frontend for message definitions
frontendI18n = toJSON (mr :: FrontendMessage -> Text) frontendI18n = toJSON (mr :: FrontendMessage -> Text)
frontendDatetimeLocale <- toJSON <$> selectLanguage frontendDatetimeLocales
pc <- widgetToPageContent $ do pc <- widgetToPageContent $ do
-- fonts -- fonts

View File

@ -1,5 +1,6 @@
module Utils.Frontend.I18n module Utils.Frontend.I18n
( FrontendMessage(..) ( FrontendMessage(..)
, frontendDatetimeLocales
) where ) where
import ClassyPrelude import ClassyPrelude
@ -14,6 +15,9 @@ import Data.Aeson.Types (toJSONKeyText)
import Data.Aeson.TH import Data.Aeson.TH
import qualified Data.Char as Char import qualified Data.Char as Char
import Data.List.NonEmpty (NonEmpty(..))
import Text.Shakespeare.I18N (Lang)
-- | I18n-Messages used in JavaScript-Frontend -- | I18n-Messages used in JavaScript-Frontend
-- --
@ -39,3 +43,7 @@ instance ToJSONKey FrontendMessage where
toJSONKey = toJSONKeyText toPathPiece toJSONKey = toJSONKeyText toPathPiece
instance FromJSONKey FrontendMessage where instance FromJSONKey FrontendMessage where
fromJSONKey = FromJSONKeyTextParser $ parseJSON . String fromJSONKey = FromJSONKeyTextParser $ parseJSON . String
frontendDatetimeLocales :: NonEmpty Lang
frontendDatetimeLocales = "de" :| ["en"]

View File

@ -11,8 +11,6 @@ import qualified Data.List as List
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
import Control.Lens (none)
import Yesod.Core.Types (HandlerData(handlerRequest), YesodRequest(reqLangs)) import Yesod.Core.Types (HandlerData(handlerRequest), YesodRequest(reqLangs))
import qualified Network.Wai.Parse as NWP import qualified Network.Wai.Parse as NWP
@ -41,7 +39,7 @@ selectLanguages avL (l:ls)
, l'' <- matchesFor l' , l'' <- matchesFor l'
, langMatches lParts' 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 others = selectLanguages avL ls
in maybe id (\now' others' -> NonEmpty.fromList $ toList now' ++ filter (`notElem` toList now') (toList others')) now others in maybe id (\now' others' -> NonEmpty.fromList $ toList now' ++ filter (`notElem` toList now') (toList others')) now others
| otherwise = selectLanguages avL ls | otherwise = selectLanguages avL ls

View File

@ -1,6 +1,6 @@
if (window.App) { if (window.App) {
window.App.i18n.addMany(#{frontendI18n}); window.App.i18n.addMany(#{frontendI18n});
// window.App.i18n.setLang(lang); TODO: set language string for datepicker config window.App.i18n.setDatetimeLocale(#{frontendDatetimeLocale});
} else { } else {
throw new Error('I18n JavaScript service is missing!'); throw new Error('I18n JavaScript service is missing!');
} }