diff --git a/modules/webapp/src/main/elm/App/Data.elm b/modules/webapp/src/main/elm/App/Data.elm index b047f250..4c3a4c6c 100644 --- a/modules/webapp/src/main/elm/App/Data.elm +++ b/modules/webapp/src/main/elm/App/Data.elm @@ -2,6 +2,7 @@ module App.Data exposing ( Model , Msg(..) , defaultPage + , getUiLanguage , init ) @@ -24,6 +25,7 @@ import Page.Queue.Data import Page.Register.Data import Page.Upload.Data import Page.UserSettings.Data +import UiLanguage exposing (UiLanguage) import Url exposing (Url) @@ -48,6 +50,8 @@ type alias Model = , uiSettings : UiSettings , sidebarVisible : Bool , anonymousTheme : UiTheme + , anonymousUiLang : UiLanguage + , langMenuOpen : Bool } @@ -97,6 +101,8 @@ init key url flags_ settings = , uiSettings = settings , sidebarVisible = settings.sideMenuVisible , anonymousTheme = Data.UiTheme.Light + , anonymousUiLang = UiLanguage.English + , langMenuOpen = False } , Cmd.batch [ Cmd.map UserSettingsMsg uc @@ -152,8 +158,20 @@ type Msg | GetUiSettings UiSettings | ToggleSidebar | ToggleDarkMode + | ToggleLangMenu + | SetLanguage UiLanguage defaultPage : Flags -> Page defaultPage flags = HomePage + + +getUiLanguage : Model -> UiLanguage +getUiLanguage model = + case model.flags.account of + Just _ -> + model.uiSettings.uiLang + + Nothing -> + model.anonymousUiLang diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm index 63e3aceb..4752f4b0 100644 --- a/modules/webapp/src/main/elm/App/Update.elm +++ b/modules/webapp/src/main/elm/App/Update.elm @@ -84,6 +84,15 @@ updateWithSub msg model = , Sub.none ) + ToggleLangMenu -> + ( { model | langMenuOpen = not model.langMenuOpen } + , Cmd.none + , Sub.none + ) + + SetLanguage lang -> + ( { model | anonymousUiLang = lang, langMenuOpen = False }, Cmd.none, Sub.none ) + HomeMsg lm -> updateHome lm model diff --git a/modules/webapp/src/main/elm/App/View2.elm b/modules/webapp/src/main/elm/App/View2.elm index 7c907437..fe32be78 100644 --- a/modules/webapp/src/main/elm/App/View2.elm +++ b/modules/webapp/src/main/elm/App/View2.elm @@ -7,6 +7,7 @@ import Data.Flags import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (onClick) +import Messages import Page exposing (Page(..)) import Page.CollectiveSettings.View2 as CollectiveSettings import Page.Home.Data @@ -20,6 +21,7 @@ import Page.Register.View2 as Register import Page.Upload.View2 as Upload import Page.UserSettings.View2 as UserSettings import Styles as S +import UiLanguage view : Model -> List (Html Msg) @@ -64,13 +66,18 @@ topNavUser auth model = topNavAnon : Model -> Html Msg topNavAnon model = + let + texts = + Messages.get <| App.Data.getUiLanguage model + in nav [ id "top-nav" , class styleTopNav ] [ headerNavItem model , div [ class "flex flex-grow justify-end" ] - [ a + [ langMenu model + , a [ href "#" , onClick ToggleDarkMode , class dropdownLink @@ -100,6 +107,10 @@ headerNavItem model = mainContent : Model -> Html Msg mainContent model = + let + texts = + Messages.get <| App.Data.getUiLanguage model + in div [ id "main" , class styleMain @@ -151,6 +162,45 @@ styleMain = "mt-12 flex md:flex-row flex-col w-full h-screen-12 overflow-y-hidden bg-white dark:bg-bluegray-800 text-gray-800 dark:text-bluegray-300 antialiased" +langMenu : Model -> Html Msg +langMenu model = + let + texts = + Messages.get <| App.Data.getUiLanguage model + + langItem lang = + let + langMsg = + Messages.get lang + in + a + [ classList + [ ( dropdownItem, True ) + , ( "bg-gray-200 dark:bg-bluegray-700", lang == texts.lang ) + ] + , onClick (SetLanguage lang) + , href "#" + ] + [ i [ langMsg |> .flagIcon |> class ] [] + , span [ class "ml-2" ] [ text langMsg.label ] + ] + in + div [ class "relative" ] + [ a + [ class dropdownLink + , onClick ToggleLangMenu + , href "#" + ] + [ i [ class texts.flagIcon ] [] + ] + , div + [ class dropdownMenu + , classList [ ( "hidden", not model.langMenuOpen ) ] + ] + (List.map langItem UiLanguage.all) + ] + + dataMenu : AuthResult -> Model -> Html Msg dataMenu _ model = div [ class "relative" ] diff --git a/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm b/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm index c9f0a010..3f086604 100644 --- a/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm +++ b/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm @@ -11,11 +11,13 @@ import Api.Model.TagList exposing (TagList) import Comp.BasicSizeField import Comp.ColorTagger import Comp.FieldListSelect +import Comp.FixedDropdown import Comp.IntField import Comp.MenuBar as MB import Comp.Tabs import Data.BasicSize exposing (BasicSize) import Data.Color exposing (Color) +import Data.DropdownStyle as DS import Data.Fields exposing (Field) import Data.Flags exposing (Flags) import Data.ItemTemplate as IT exposing (ItemTemplate) @@ -26,8 +28,10 @@ import Html.Attributes exposing (..) import Html.Events exposing (onClick, onInput) import Http import Markdown +import Messages import Set exposing (Set) import Styles as S +import UiLanguage exposing (UiLanguage) import Util.Maybe import Util.Tag @@ -56,6 +60,8 @@ type alias Model = , searchStatsVisible : Bool , sideMenuVisible : Bool , powerSearchEnabled : Bool + , uiLangModel : Comp.FixedDropdown.Model UiLanguage + , uiLang : UiLanguage , openTabs : Set String } @@ -148,6 +154,10 @@ init flags settings = , searchStatsVisible = settings.searchStatsVisible , sideMenuVisible = settings.sideMenuVisible , powerSearchEnabled = settings.powerSearchEnabled + , uiLang = settings.uiLang + , uiLangModel = + List.map langItem UiLanguage.all + |> Comp.FixedDropdown.init , openTabs = Set.empty } , Api.getTags flags "" GetTagsResp @@ -174,6 +184,15 @@ type Msg | ToggleAkkordionTab String | ToggleSideMenuVisible | TogglePowerSearch + | UiLangMsg (Comp.FixedDropdown.Msg UiLanguage) + + +langItem : UiLanguage -> Comp.FixedDropdown.Item UiLanguage +langItem lang = + { id = lang + , display = Messages.get lang |> .label + , icon = Just (Messages.get lang |> .flagIcon) + } @@ -445,6 +464,22 @@ update sett msg model = , Just { sett | powerSearchEnabled = next } ) + UiLangMsg lm -> + let + ( m, sel ) = + Comp.FixedDropdown.update lm model.uiLangModel + + newLang = + Maybe.withDefault model.uiLang sel + in + ( { model | uiLangModel = m, uiLang = newLang } + , if newLang == model.uiLang then + Nothing + + else + Just { sett | uiLang = newLang } + ) + --- View2 @@ -494,6 +529,15 @@ settingFormTabs flags _ model = , value = model.sideMenuVisible } ] + , div [ class "mb-4" ] + [ label [ class S.inputLabel ] [ text "UI Language" ] + , Html.map UiLangMsg + (Comp.FixedDropdown.viewStyled2 DS.mainStyle + False + (Just <| langItem model.uiLang) + model.uiLangModel + ) + ] ] } , { title = "Item Search" diff --git a/modules/webapp/src/main/elm/Data/UiSettings.elm b/modules/webapp/src/main/elm/Data/UiSettings.elm index 988eb2d4..3bcbb0c0 100644 --- a/modules/webapp/src/main/elm/Data/UiSettings.elm +++ b/modules/webapp/src/main/elm/Data/UiSettings.elm @@ -32,6 +32,8 @@ import Data.UiTheme exposing (UiTheme) import Dict exposing (Dict) import Html exposing (Attribute) import Html.Attributes as HA +import Messages +import UiLanguage exposing (UiLanguage) {-| Settings for the web ui. All fields should be optional, since it @@ -63,6 +65,7 @@ type alias StoredUiSettings = , uiTheme : Maybe String , sideMenuVisible : Bool , powerSearchEnabled : Bool + , uiLang : Maybe String } @@ -94,6 +97,7 @@ type alias UiSettings = , uiTheme : UiTheme , sideMenuVisible : Bool , powerSearchEnabled : Bool + , uiLang : UiLanguage } @@ -165,6 +169,7 @@ defaults = , uiTheme = Data.UiTheme.Light , sideMenuVisible = True , powerSearchEnabled = False + , uiLang = UiLanguage.English } @@ -217,6 +222,9 @@ merge given fallback = |> Maybe.withDefault fallback.uiTheme , sideMenuVisible = given.sideMenuVisible , powerSearchEnabled = given.powerSearchEnabled + , uiLang = + Maybe.map Messages.fromIso2 given.uiLang + |> Maybe.withDefault UiLanguage.English } @@ -254,6 +262,7 @@ toStoredUiSettings settings = , uiTheme = Just (Data.UiTheme.toString settings.uiTheme) , sideMenuVisible = settings.sideMenuVisible , powerSearchEnabled = settings.powerSearchEnabled + , uiLang = Just <| Messages.toIso2 settings.uiLang } diff --git a/modules/webapp/src/main/elm/Messages.elm b/modules/webapp/src/main/elm/Messages.elm new file mode 100644 index 00000000..0a07608e --- /dev/null +++ b/modules/webapp/src/main/elm/Messages.elm @@ -0,0 +1,87 @@ +module Messages exposing + ( Messages + , fromIso2 + , get + , toIso2 + ) + +import Messages.App +import Messages.LoginPage +import UiLanguage exposing (UiLanguage(..)) + + +{-| The messages record contains all strings used in the application. +-} +type alias Messages = + { lang : UiLanguage + , iso2 : String + , label : String + , flagIcon : String + , app : Messages.App.Texts + , login : Messages.LoginPage.Texts + } + + +get : UiLanguage -> Messages +get lang = + case lang of + English -> + gb + + German -> + de + + +{-| Get a ISO-3166-1 code of the given lanugage. +-} +toIso2 : UiLanguage -> String +toIso2 lang = + get lang |> .iso2 + + +{-| Return the UiLanguage from given iso2 code. If the iso2 code is not +known, return Nothing. +-} +readIso2 : String -> Maybe UiLanguage +readIso2 iso = + let + isIso lang = + iso == toIso2 lang + in + List.filter isIso UiLanguage.all + |> List.head + + +{-| return the language from the given iso2 code. if the iso2 code is +not known, return English as a default. +-} +fromIso2 : String -> UiLanguage +fromIso2 iso = + readIso2 iso + |> Maybe.withDefault English + + + +--- Messages Definitions + + +gb : Messages +gb = + { lang = English + , iso2 = "gb" + , label = "English" + , flagIcon = "flag-icon flag-icon-gb" + , app = Messages.App.gb + , login = Messages.LoginPage.gb + } + + +de : Messages +de = + { lang = German + , iso2 = "de" + , label = "Deutsch" + , flagIcon = "flag-icon flag-icon-de" + , app = Messages.App.de + , login = Messages.LoginPage.de + } diff --git a/modules/webapp/src/main/elm/Messages/App.elm b/modules/webapp/src/main/elm/Messages/App.elm new file mode 100644 index 00000000..1c3af83b --- /dev/null +++ b/modules/webapp/src/main/elm/Messages/App.elm @@ -0,0 +1,22 @@ +module Messages.App exposing + ( Texts + , de + , gb + ) + + +type alias Texts = + { login : String + } + + +gb : Texts +gb = + { login = "Login" + } + + +de : Texts +de = + { login = "Anmelden" + } diff --git a/modules/webapp/src/main/elm/Messages/FixedDropdown.elm b/modules/webapp/src/main/elm/Messages/FixedDropdown.elm new file mode 100644 index 00000000..32f7e983 --- /dev/null +++ b/modules/webapp/src/main/elm/Messages/FixedDropdown.elm @@ -0,0 +1,22 @@ +module Messages.FixedDropdown exposing + ( Texts + , de + , gb + ) + + +type alias Texts = + { select : String + } + + +gb : Texts +gb = + { select = "Select…" + } + + +de : Texts +de = + { select = "Auswahl…" + } diff --git a/modules/webapp/src/main/elm/Messages/LoginPage.elm b/modules/webapp/src/main/elm/Messages/LoginPage.elm new file mode 100644 index 00000000..befd838a --- /dev/null +++ b/modules/webapp/src/main/elm/Messages/LoginPage.elm @@ -0,0 +1,57 @@ +module Messages.LoginPage exposing + ( Texts + , de + , fr + , gb + ) + + +type alias Texts = + { username : String + , password : String + , loginPlaceholder : String + , passwordPlaceholder : String + , loginButton : String + , loginSuccessful : String + , noAccount : String + , signupLink : String + } + + +gb : Texts +gb = + { username = "Username" + , password = "Password" + , loginPlaceholder = "Login" + , passwordPlaceholder = "Password" + , loginButton = "Login" + , loginSuccessful = "Login successful" + , noAccount = "No account?" + , signupLink = "Sign up!" + } + + +de : Texts +de = + { username = "Benutzer" + , password = "Passwort" + , loginPlaceholder = "Benutzer" + , passwordPlaceholder = "Passwort" + , loginButton = "Anmelden" + , loginSuccessful = "Anmeldung erfolgreich" + , noAccount = "Kein Konto?" + , signupLink = "Hier registrieren!" + } + + +fr : Texts +fr = + { username = "Identifiant" + , password = "Mot de passe" + , loginPlaceholder = "Utilisateur" + , passwordPlaceholder = "Mot de passe" + , loginButton = "Connexion" + , loginSuccessful = "Identification réussie" + , noAccount = "Pas de compte ?" + , signupLink = "S'inscrire" + } diff --git a/modules/webapp/src/main/elm/UiLanguage.elm b/modules/webapp/src/main/elm/UiLanguage.elm new file mode 100644 index 00000000..05a46f61 --- /dev/null +++ b/modules/webapp/src/main/elm/UiLanguage.elm @@ -0,0 +1,16 @@ +module UiLanguage exposing + ( UiLanguage(..) + , all + ) + + +type UiLanguage + = English + | German + + +all : List UiLanguage +all = + [ English + , German + ]