From 1762e7afac02996f35af0ce783dd5dae31dfacba Mon Sep 17 00:00:00 2001
From: Eike Kettner <eike.kettner@posteo.de>
Date: Mon, 5 Apr 2021 21:31:45 +0200
Subject: [PATCH] Externalize strings for home page

---
 modules/webapp/src/main/elm/App/View2.elm     |  21 +++-
 .../webapp/src/main/elm/Comp/ConfirmModal.elm |   8 +-
 .../main/elm/Comp/CustomFieldMultiInput.elm   |  23 ++--
 modules/webapp/src/main/elm/Comp/ItemCard.elm |  28 +++--
 .../webapp/src/main/elm/Comp/ItemCardList.elm |  19 +--
 .../src/main/elm/Comp/ItemDetail/EditForm.elm |  11 +-
 .../elm/Comp/ItemDetail/MultiEditMenu.elm     | 102 +++++++++-------
 .../src/main/elm/Comp/ItemDetail/Update.elm   |   8 ++
 .../src/main/elm/Comp/PowerSearchInput.elm    |  15 ++-
 .../webapp/src/main/elm/Comp/SearchMenu.elm   | 115 ++++++++++--------
 .../src/main/elm/Comp/SearchStatsView.elm     |  17 +--
 modules/webapp/src/main/elm/Messages.elm      |   4 +
 .../webapp/src/main/elm/Messages/Basics.elm   |   6 +
 .../webapp/src/main/elm/Messages/HomePage.elm |  58 +++++++++
 .../src/main/elm/Messages/HomeSideMenu.elm    |  27 ++++
 .../src/main/elm/Messages/ItemCardComp.elm    |  12 ++
 .../main/elm/Messages/ItemCardListComp.elm    |  14 +++
 .../src/main/elm/Messages/MultiEditComp.elm   |  61 ++++++++++
 .../src/main/elm/Messages/SearchMenuComp.elm  |  74 +++++++++++
 .../main/elm/Messages/SearchStatsViewComp.elm |  22 ++++
 .../webapp/src/main/elm/Page/Home/Data.elm    |  11 +-
 .../src/main/elm/Page/Home/SideMenu.elm       |  40 +++---
 .../webapp/src/main/elm/Page/Home/Update.elm  |  19 +--
 .../webapp/src/main/elm/Page/Home/View2.elm   | 111 ++++++++++-------
 24 files changed, 601 insertions(+), 225 deletions(-)
 create mode 100644 modules/webapp/src/main/elm/Messages/HomePage.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/HomeSideMenu.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/ItemCardComp.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/ItemCardListComp.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/MultiEditComp.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/SearchMenuComp.elm
 create mode 100644 modules/webapp/src/main/elm/Messages/SearchStatsViewComp.elm

diff --git a/modules/webapp/src/main/elm/App/View2.elm b/modules/webapp/src/main/elm/App/View2.elm
index ba3cac4e..0cf078cf 100644
--- a/modules/webapp/src/main/elm/App/View2.elm
+++ b/modules/webapp/src/main/elm/App/View2.elm
@@ -118,7 +118,7 @@ mainContent model =
         ]
         (case model.page of
             HomePage ->
-                viewHome model
+                viewHome texts model
 
             CollectiveSettingPage ->
                 viewCollectiveSettings texts model
@@ -397,10 +397,21 @@ dropdownMenu =
     " absolute right-0 bg-white dark:bg-bluegray-800 border dark:border-bluegray-700 dark:text-bluegray-300 shadow-lg opacity-1 transition duration-200 min-w-max "
 
 
-viewHome : Model -> List (Html Msg)
-viewHome model =
-    [ Html.map HomeMsg (Home.viewSidebar model.sidebarVisible model.flags model.uiSettings model.homeModel)
-    , Html.map HomeMsg (Home.viewContent model.flags model.uiSettings model.homeModel)
+viewHome : Messages -> Model -> List (Html Msg)
+viewHome texts model =
+    [ Html.map HomeMsg
+        (Home.viewSidebar texts.home
+            model.sidebarVisible
+            model.flags
+            model.uiSettings
+            model.homeModel
+        )
+    , Html.map HomeMsg
+        (Home.viewContent texts.home
+            model.flags
+            model.uiSettings
+            model.homeModel
+        )
     ]
 
 
diff --git a/modules/webapp/src/main/elm/Comp/ConfirmModal.elm b/modules/webapp/src/main/elm/Comp/ConfirmModal.elm
index 10b5a3ad..5f01a733 100644
--- a/modules/webapp/src/main/elm/Comp/ConfirmModal.elm
+++ b/modules/webapp/src/main/elm/Comp/ConfirmModal.elm
@@ -23,14 +23,14 @@ type alias Settings msg =
     }
 
 
-defaultSettings : msg -> msg -> String -> Settings msg
-defaultSettings confirm cancel confirmMsg =
+defaultSettings : msg -> msg -> String -> String -> String -> Settings msg
+defaultSettings confirm cancel okLabel cancelLabel confirmMsg =
     { enabled = True
     , extraClass = ""
     , headerIcon = "fa fa-exclamation-circle mr-3"
     , headerClass = "text-2xl font-bold text-center w-full"
-    , confirmText = "Ok"
-    , cancelText = "Cancel"
+    , confirmText = okLabel
+    , cancelText = cancelLabel
     , message = confirmMsg
     , confirm = confirm
     , cancel = cancel
diff --git a/modules/webapp/src/main/elm/Comp/CustomFieldMultiInput.elm b/modules/webapp/src/main/elm/Comp/CustomFieldMultiInput.elm
index bb39cf65..8cf7ed94 100644
--- a/modules/webapp/src/main/elm/Comp/CustomFieldMultiInput.elm
+++ b/modules/webapp/src/main/elm/Comp/CustomFieldMultiInput.elm
@@ -313,23 +313,28 @@ type alias ViewSettings =
     { showAddButton : Bool
     , classes : String
     , fieldIcon : CustomField -> Maybe String
+    , style : DS.DropdownStyle
+    , createCustomFieldTitle : String
     }
 
 
-view2 : DS.DropdownStyle -> ViewSettings -> Model -> Html Msg
-view2 ddstyle viewSettings model =
+view2 : ViewSettings -> Model -> Html Msg
+view2 viewSettings model =
     div [ class viewSettings.classes ]
-        (viewMenuBar2 ddstyle viewSettings model
+        (viewMenuBar2 viewSettings model
             :: List.map (viewCustomField2 viewSettings model) (visibleFields model)
         )
 
 
-viewMenuBar2 : DS.DropdownStyle -> ViewSettings -> Model -> Html Msg
-viewMenuBar2 ddstyle viewSettings model =
+viewMenuBar2 : ViewSettings -> Model -> Html Msg
+viewMenuBar2 viewSettings model =
     let
         { dropdown, selected } =
             model.fieldSelect
 
+        ddstyle =
+            viewSettings.style
+
         ddstyleFlex =
             { display = \f -> Maybe.withDefault f.name f.label
             , icon = \_ -> Nothing
@@ -350,7 +355,7 @@ viewMenuBar2 ddstyle viewSettings model =
                 dropdown
             )
             :: (if viewSettings.showAddButton then
-                    [ addFieldLink2 "ml-1" model
+                    [ addFieldLink2 viewSettings.createCustomFieldTitle "ml-1" model
                     ]
 
                 else
@@ -377,8 +382,8 @@ viewCustomField2 viewSettings model field =
             span [] []
 
 
-addFieldLink2 : String -> Model -> Html Msg
-addFieldLink2 classes _ =
+addFieldLink2 : String -> String -> Model -> Html Msg
+addFieldLink2 titleStr classes _ =
     a
         [ class classes
         , class S.secondaryButton
@@ -386,7 +391,7 @@ addFieldLink2 classes _ =
         --        , class "absolute -right-12 top-0"
         , href "#"
         , onClick CreateNewField
-        , title "Create a new custom field"
+        , title titleStr
         ]
         [ i [ class "fa fa-plus" ] []
         ]
diff --git a/modules/webapp/src/main/elm/Comp/ItemCard.elm b/modules/webapp/src/main/elm/Comp/ItemCard.elm
index b361830f..0e18bd73 100644
--- a/modules/webapp/src/main/elm/Comp/ItemCard.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemCard.elm
@@ -23,6 +23,7 @@ import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (onClick)
 import Markdown
+import Messages.ItemCardComp exposing (Texts)
 import Page exposing (Page(..))
 import Set exposing (Set)
 import Styles as S
@@ -135,12 +136,11 @@ update ddm msg model =
 
 
 
---- View
 --- View2
 
 
-view2 : ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg
-view2 cfg settings model item =
+view2 : Texts -> ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg
+view2 texts cfg settings model item =
     let
         isConfirmed =
             item.state /= "created"
@@ -200,8 +200,8 @@ view2 cfg settings model item =
             [ previewImage2 settings cardAction model item
             ]
          )
-            ++ [ mainContent2 cardAction cardColor isConfirmed settings cfg item
-               , metaDataContent2 settings item
+            ++ [ mainContent2 texts cardAction cardColor isConfirmed settings cfg item
+               , metaDataContent2 texts settings item
                , notesContent2 settings item
                , fulltextResultsContent2 item
                , previewMenu2 settings model item (currentAttachment model item)
@@ -221,8 +221,8 @@ fulltextResultsContent2 item =
         (List.map renderHighlightEntry2 item.highlighting)
 
 
-metaDataContent2 : UiSettings -> ItemLight -> Html Msg
-metaDataContent2 settings item =
+metaDataContent2 : Texts -> UiSettings -> ItemLight -> Html Msg
+metaDataContent2 texts settings item =
     let
         fieldHidden f =
             Data.UiSettings.fieldHidden settings f
@@ -234,7 +234,7 @@ metaDataContent2 settings item =
                     [ ( "hidden", fieldHidden Data.Fields.Folder )
                     ]
                 , class "hover:opacity-60"
-                , title "Folder"
+                , title texts.folder
                 ]
                 [ Icons.folderIcon2 "mr-2"
                 , Comp.LinkTarget.makeFolderLink item
@@ -273,8 +273,16 @@ notesContent2 settings item =
         ]
 
 
-mainContent2 : List (Attribute Msg) -> String -> Bool -> UiSettings -> ViewConfig -> ItemLight -> Html Msg
-mainContent2 cardAction cardColor isConfirmed settings _ item =
+mainContent2 :
+    Texts
+    -> List (Attribute Msg)
+    -> String
+    -> Bool
+    -> UiSettings
+    -> ViewConfig
+    -> ItemLight
+    -> Html Msg
+mainContent2 texts cardAction cardColor isConfirmed settings _ item =
     let
         dirIcon =
             i
diff --git a/modules/webapp/src/main/elm/Comp/ItemCardList.elm b/modules/webapp/src/main/elm/Comp/ItemCardList.elm
index e3432c19..19f8a59d 100644
--- a/modules/webapp/src/main/elm/Comp/ItemCardList.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemCardList.elm
@@ -22,6 +22,7 @@ import Data.UiSettings exposing (UiSettings)
 import Dict exposing (Dict)
 import Html exposing (..)
 import Html.Attributes exposing (..)
+import Messages.ItemCardListComp exposing (Texts)
 import Page exposing (Page(..))
 import Styles as S
 import Util.ItemDragDrop as DD
@@ -148,19 +149,19 @@ type alias ViewConfig =
     }
 
 
-view2 : ViewConfig -> UiSettings -> Model -> Html Msg
-view2 cfg settings model =
+view2 : Texts -> ViewConfig -> UiSettings -> Model -> Html Msg
+view2 texts cfg settings model =
     div
         [ classList
             [ ( "ds-item-list", True )
             , ( "ds-multi-select-mode", isMultiSelectMode cfg )
             ]
         ]
-        (List.map (viewGroup2 model cfg settings) model.results.groups)
+        (List.map (viewGroup2 texts model cfg settings) model.results.groups)
 
 
-viewGroup2 : Model -> ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
-viewGroup2 model cfg settings group =
+viewGroup2 : Texts -> Model -> ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
+viewGroup2 texts model cfg settings group =
     div [ class "ds-item-group" ]
         [ div
             [ class "flex py-0 mt-2 flex flex-row items-center"
@@ -185,12 +186,12 @@ viewGroup2 model cfg settings group =
                 []
             ]
         , div [ class "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-2" ]
-            (List.map (viewItem2 model cfg settings) group.items)
+            (List.map (viewItem2 texts model cfg settings) group.items)
         ]
 
 
-viewItem2 : Model -> ViewConfig -> UiSettings -> ItemLight -> Html Msg
-viewItem2 model cfg settings item =
+viewItem2 : Texts -> Model -> ViewConfig -> UiSettings -> ItemLight -> Html Msg
+viewItem2 texts model cfg settings item =
     let
         currentClass =
             if cfg.current == Just item.id then
@@ -207,7 +208,7 @@ viewItem2 model cfg settings item =
                 |> Maybe.withDefault Comp.ItemCard.init
 
         cardHtml =
-            Comp.ItemCard.view2 vvcfg settings cardModel item
+            Comp.ItemCard.view2 texts.itemCard vvcfg settings cardModel item
     in
     Html.map (ItemCardMsg item) cardHtml
 
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/EditForm.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/EditForm.elm
index 3cedc45f..c5370009 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/EditForm.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/EditForm.elm
@@ -96,10 +96,12 @@ formTabs flags settings model =
             Data.UiSettings.fieldVisible settings field
 
         customFieldSettings =
-            Comp.CustomFieldMultiInput.ViewSettings
-                True
-                "field"
-                (\f -> Dict.get f.id model.customFieldSavingIcon)
+            { showAddButton = True
+            , classes = ""
+            , fieldIcon = \f -> Dict.get f.id model.customFieldSavingIcon
+            , style = dds
+            , createCustomFieldTitle = "Create new custom field"
+            }
 
         optional fields html =
             if
@@ -255,7 +257,6 @@ item visible. This message will disappear then.
             [ div [ class "mb-4" ]
                 [ Html.map CustomFieldMsg
                     (Comp.CustomFieldMultiInput.view2
-                        dds
                         customFieldSettings
                         model.customFieldsModel
                     )
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm
index cc734ea7..d63af8ce 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm
@@ -39,6 +39,7 @@ import Html.Attributes exposing (..)
 import Html.Events exposing (onClick, onInput)
 import Http
 import Markdown
+import Messages.MultiEditComp exposing (Texts)
 import Page exposing (Page(..))
 import Set exposing (Set)
 import Styles as S
@@ -601,13 +602,13 @@ defaultViewConfig =
 --- View2
 
 
-view2 : Flags -> ViewConfig -> UiSettings -> Model -> Html Msg
+view2 : Texts -> Flags -> ViewConfig -> UiSettings -> Model -> Html Msg
 view2 =
     renderEditForm2
 
 
-renderEditForm2 : Flags -> ViewConfig -> UiSettings -> Model -> Html Msg
-renderEditForm2 flags cfg settings model =
+renderEditForm2 : Texts -> Flags -> ViewConfig -> UiSettings -> Model -> Html Msg
+renderEditForm2 texts flags cfg settings model =
     let
         fieldVisible field =
             Data.UiSettings.fieldVisible settings field
@@ -636,13 +637,13 @@ renderEditForm2 flags cfg settings model =
         tagModeMsg =
             case model.tagEditMode of
                 AddTags ->
-                    "Tags chosen here are *added* to all selected items."
+                    texts.tagModeAddInfo
 
                 RemoveTags ->
-                    "Tags chosen here are *removed* from all selected items."
+                    texts.tagModeRemoveInfo
 
                 ReplaceTags ->
-                    "Tags chosen here *replace* those on selected items."
+                    texts.tagModeReplaceInfo
 
         customFieldIcon field =
             case cfg.customFieldState field.id of
@@ -656,10 +657,12 @@ renderEditForm2 flags cfg settings model =
                     Just "fa fa-sync-alt animate-spin"
 
         customFieldSettings =
-            Comp.CustomFieldMultiInput.ViewSettings
-                False
-                "mb-4"
-                customFieldIcon
+            { showAddButton = False
+            , classes = "mb-4"
+            , fieldIcon = customFieldIcon
+            , style = dds
+            , createCustomFieldTitle = ""
+            }
 
         dds =
             Data.DropdownStyle.sidebarStyle
@@ -677,7 +680,7 @@ renderEditForm2 flags cfg settings model =
         idNameCfg =
             { makeOption = \e -> { text = e.name, additional = "" }
             , labelColor = \_ -> \_ -> ""
-            , placeholder = "Select…"
+            , placeholder = texts.selectPlaceholder
             , style = dds
             }
 
@@ -687,7 +690,7 @@ renderEditForm2 flags cfg settings model =
                     { text = Data.Direction.toString entry
                     , additional = ""
                     }
-            , placeholder = "Choose a direction…"
+            , placeholder = texts.chooseDirection
             , labelColor = \_ -> \_ -> ""
             , style = dds
             }
@@ -697,7 +700,7 @@ renderEditForm2 flags cfg settings model =
             tabStyle
             (tabState settings model)
             [ { name = tabName TabConfirmUnconfirm
-              , title = "Confirm/Unconfirm item metadata"
+              , title = texts.confirmUnconfirm
               , titleRight = []
               , info = Nothing
               , body =
@@ -709,32 +712,32 @@ renderEditForm2 flags cfg settings model =
                             , class "flex-grow"
                             , onClick (ConfirmMsg True)
                             ]
-                            [ text "Confirm"
+                            [ text texts.confirm
                             ]
                         , button
                             [ class S.secondaryButton
                             , class "flex-grow"
                             , onClick (ConfirmMsg False)
                             ]
-                            [ text "Unconfirm"
+                            [ text texts.unconfirm
                             ]
                         ]
                     ]
               }
             , { name = tabName TabTags
-              , title = "Tags"
+              , title = texts.basics.tags
               , titleRight = []
               , info = Nothing
               , body =
                     [ div [ class "field" ]
                         [ label [ class S.inputLabel ]
                             [ Icons.tagsIcon2 ""
-                            , text "Tags"
+                            , text texts.basics.tags
                             , a
                                 [ class "float-right"
                                 , class S.link
                                 , href "#"
-                                , title "Change tag edit mode"
+                                , title texts.changeTagMode
                                 , onClick ToggleTagEditMode
                                 ]
                                 [ tagModeIcon
@@ -750,7 +753,7 @@ renderEditForm2 flags cfg settings model =
                     ]
               }
             , { name = tabName TabFolder
-              , title = "Folder"
+              , title = texts.folderTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -761,25 +764,24 @@ renderEditForm2 flags cfg settings model =
                             , ( "hidden", isFolderMember model )
                             ]
                         ]
-                        [ Markdown.toHtml [] """
-You are **not a member** of this folder. This item will be **hidden**
-from any search now. Use a folder where you are a member of to make this
-item visible. This message will disappear then.
-                      """
+                        [ Markdown.toHtml [] texts.folderNotOwnerWarning
                         ]
                     ]
               }
             , { name = tabName TabCustomFields
-              , title = "Custom Fields"
+              , title = texts.customFieldsTab
               , titleRight = []
               , info = Nothing
               , body =
                     [ Html.map CustomFieldMsg
-                        (Comp.CustomFieldMultiInput.view2 dds customFieldSettings model.customFieldModel)
+                        (Comp.CustomFieldMultiInput.view2
+                            customFieldSettings
+                            model.customFieldModel
+                        )
                     ]
               }
             , { name = tabName TabDate
-              , title = "Date"
+              , title = texts.dateTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -802,7 +804,7 @@ item visible. This message will disappear then.
                     ]
               }
             , { name = tabName TabDueDate
-              , title = "Due Date"
+              , title = texts.dueDateTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -825,7 +827,7 @@ item visible. This message will disappear then.
                     ]
               }
             , { name = tabName TabCorrespondent
-              , title = "Correspondent"
+              , title = texts.correspondentTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -834,25 +836,35 @@ item visible. This message will disappear then.
                             [ label [ class S.inputLabel ]
                                 [ Icons.organizationIcon2 ""
                                 , span [ class "ml-2" ]
-                                    [ text "Organization"
+                                    [ text texts.organization
                                     ]
                                 ]
-                            , Html.map OrgDropdownMsg (Comp.Dropdown.view2 idNameCfg settings model.corrOrgModel)
+                            , Html.map OrgDropdownMsg
+                                (Comp.Dropdown.view2
+                                    idNameCfg
+                                    settings
+                                    model.corrOrgModel
+                                )
                             ]
                     , optional [ Data.Fields.CorrPerson ] <|
                         div [ class "mb-4" ]
                             [ label [ class S.inputLabel ]
                                 [ Icons.personIcon2 ""
                                 , span [ class "ml-2" ]
-                                    [ text "Person"
+                                    [ text texts.person
                                     ]
                                 ]
-                            , Html.map CorrPersonMsg (Comp.Dropdown.view2 idNameCfg settings model.corrPersonModel)
+                            , Html.map CorrPersonMsg
+                                (Comp.Dropdown.view2
+                                    idNameCfg
+                                    settings
+                                    model.corrPersonModel
+                                )
                             ]
                     ]
               }
             , { name = tabName TabConcerning
-              , title = "Concerning"
+              , title = texts.concerningTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -861,7 +873,7 @@ item visible. This message will disappear then.
                             [ label [ class S.inputLabel ]
                                 [ Icons.personIcon2 ""
                                 , span [ class "ml-2" ]
-                                    [ text "Person" ]
+                                    [ text texts.person ]
                                 ]
                             , Html.map ConcPersonMsg (Comp.Dropdown.view2 idNameCfg settings model.concPersonModel)
                             ]
@@ -870,7 +882,7 @@ item visible. This message will disappear then.
                             [ label [ class S.inputLabel ]
                                 [ Icons.equipmentIcon2 ""
                                 , span [ class "ml-2" ]
-                                    [ text "Equipment" ]
+                                    [ text texts.equipment ]
                                 ]
                             , Html.map ConcEquipMsg
                                 (Comp.Dropdown.view2 idNameCfg
@@ -881,7 +893,7 @@ item visible. This message will disappear then.
                     ]
               }
             , { name = tabName TabDirection
-              , title = "Direction"
+              , title = texts.directionTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -889,7 +901,7 @@ item visible. This message will disappear then.
                     ]
               }
             , { name = tabName TabName
-              , title = "Name"
+              , title = texts.nameTab
               , titleRight = []
               , info = Nothing
               , body =
@@ -904,9 +916,15 @@ item visible. This message will disappear then.
                         , span [ class S.inputLeftIconOnly ]
                             [ i
                                 [ classList
-                                    [ ( "text-green-500 fa fa-check", cfg.nameState == SaveSuccess )
-                                    , ( "text-red-500 fa fa-exclamation-triangle", cfg.nameState == SaveFailed )
-                                    , ( "sync fa fa-circle-notch animate-spin", cfg.nameState == Saving )
+                                    [ ( "text-green-500 fa fa-check"
+                                      , cfg.nameState == SaveSuccess
+                                      )
+                                    , ( "text-red-500 fa fa-exclamation-triangle"
+                                      , cfg.nameState == SaveFailed
+                                      )
+                                    , ( "sync fa fa-circle-notch animate-spin"
+                                      , cfg.nameState == Saving
+                                      )
                                     ]
                                 ]
                                 []
@@ -923,7 +941,7 @@ tabState settings model tab =
     FTabState.tabState settings
         model.openTabs
         (Just model.customFieldModel)
-        (.title >> ToggleAkkordionTab)
+        (.name >> ToggleAkkordionTab)
         tab
 
 
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
index 8e523908..d47da245 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
@@ -550,6 +550,8 @@ update key flags inav settings msg model =
                     Comp.ConfirmModal.defaultSettings
                         DeleteItemConfirmed
                         ItemModalCancelled
+                        "Ok"
+                        "Cancel"
                         confirmMsg
             in
             resultModel { model | itemModal = Just confirm }
@@ -923,6 +925,8 @@ update key flags inav settings msg model =
                     Comp.ConfirmModal.defaultSettings
                         (DeleteAttachConfirmed id)
                         AttachModalCancelled
+                        "Ok"
+                        "Cancel"
                         "Really delete this file?"
 
                 model_ =
@@ -1511,6 +1515,8 @@ update key flags inav settings msg model =
                     Comp.ConfirmModal.defaultSettings
                         (ReprocessFileConfirmed id)
                         AttachModalCancelled
+                        "Ok"
+                        "Cancel"
                         confirmMsg
 
                 model_ =
@@ -1546,6 +1552,8 @@ update key flags inav settings msg model =
                     Comp.ConfirmModal.defaultSettings
                         ReprocessItemConfirmed
                         ItemModalCancelled
+                        "Ok"
+                        "Cancel"
                         confirmMsg
 
                 model_ =
diff --git a/modules/webapp/src/main/elm/Comp/PowerSearchInput.elm b/modules/webapp/src/main/elm/Comp/PowerSearchInput.elm
index ac1b35f3..6d51b2e0 100644
--- a/modules/webapp/src/main/elm/Comp/PowerSearchInput.elm
+++ b/modules/webapp/src/main/elm/Comp/PowerSearchInput.elm
@@ -2,6 +2,7 @@ module Comp.PowerSearchInput exposing
     ( Action(..)
     , Model
     , Msg
+    , ViewSettings
     , init
     , update
     , viewInput
@@ -133,12 +134,18 @@ throttleUpdate model =
 --- View
 
 
-viewInput : List (Attribute Msg) -> Model -> Html Msg
-viewInput attrs model =
+type alias ViewSettings =
+    { placeholder : String
+    , extraAttrs : List (Attribute Msg)
+    }
+
+
+viewInput : ViewSettings -> Model -> Html Msg
+viewInput cfg model =
     input
-        (attrs
+        (cfg.extraAttrs
             ++ [ type_ "text"
-               , placeholder "Search query …"
+               , placeholder cfg.placeholder
                , onInput SetSearch
                , Util.Html.onKeyUpCode KeyUpMsg
                , Maybe.map value model.input
diff --git a/modules/webapp/src/main/elm/Comp/SearchMenu.elm b/modules/webapp/src/main/elm/Comp/SearchMenu.elm
index ff3c335f..2e7a16b7 100644
--- a/modules/webapp/src/main/elm/Comp/SearchMenu.elm
+++ b/modules/webapp/src/main/elm/Comp/SearchMenu.elm
@@ -44,6 +44,7 @@ import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (onClick, onInput)
 import Http
+import Messages.SearchMenuComp exposing (Texts)
 import Set exposing (Set)
 import Styles as S
 import Util.Html exposing (KeyCode(..))
@@ -902,8 +903,7 @@ updateDrop ddm flags settings msg model =
         ToggleOpenAllAkkordionTabs ->
             let
                 allNames =
-                    searchTabs (DD.DragDropData ddm Nothing) flags settings model
-                        |> List.map .title
+                    List.map tabName allTabs
                         |> Set.fromList
 
                 next =
@@ -924,8 +924,8 @@ updateDrop ddm flags settings msg model =
 --- View2
 
 
-viewDrop2 : DD.DragDropData -> Flags -> UiSettings -> Model -> Html Msg
-viewDrop2 ddd flags settings model =
+viewDrop2 : Texts -> DD.DragDropData -> Flags -> UiSettings -> Model -> Html Msg
+viewDrop2 texts ddd flags settings model =
     let
         akkordionStyle =
             Comp.Tabs.searchMenuStyle
@@ -933,7 +933,7 @@ viewDrop2 ddd flags settings model =
     Comp.Tabs.akkordion
         akkordionStyle
         (searchTabState settings model)
-        (searchTabs ddd flags settings model)
+        (searchTabs texts ddd flags settings model)
 
 
 type SearchTab
@@ -950,6 +950,22 @@ type SearchTab
     | TabDirection
 
 
+allTabs : List SearchTab
+allTabs =
+    [ TabInbox
+    , TabTags
+    , TabTagCategories
+    , TabFolder
+    , TabCorrespondent
+    , TabConcerning
+    , TabCustomFields
+    , TabDate
+    , TabDueDate
+    , TabSource
+    , TabDirection
+    ]
+
+
 tabName : SearchTab -> String
 tabName tab =
     case tab of
@@ -1085,8 +1101,8 @@ searchTabState settings model tab =
     ( state, ToggleAkkordionTab tab.name )
 
 
-searchTabs : DD.DragDropData -> Flags -> UiSettings -> Model -> List (Comp.Tabs.Tab Msg)
-searchTabs ddd flags settings model =
+searchTabs : Texts -> DD.DragDropData -> Flags -> UiSettings -> Model -> List (Comp.Tabs.Tab Msg)
+searchTabs texts ddd flags settings model =
     let
         isHidden f =
             Data.UiSettings.fieldHidden settings f
@@ -1100,21 +1116,14 @@ searchTabs ddd flags settings model =
                     { text = Data.Direction.toString entry
                     , additional = ""
                     }
-            , placeholder = "Choose a direction…"
+            , placeholder = texts.chooseDirection
             , labelColor = \_ -> \_ -> ""
             , style = DS.sidebarStyle
             }
 
-        corrPersonCfg =
+        personCfg =
             { makeOption = \e -> { text = e.name, additional = "" }
-            , placeholder = "Choose a person"
-            , labelColor = \_ -> \_ -> ""
-            , style = DS.sidebarStyle
-            }
-
-        concPersonCfg =
-            { makeOption = \e -> { text = e.name, additional = "" }
-            , placeholder = "Choose a person"
+            , placeholder = texts.choosePerson
             , labelColor = \_ -> \_ -> ""
             , style = DS.sidebarStyle
             }
@@ -1122,12 +1131,12 @@ searchTabs ddd flags settings model =
         concEquipCfg =
             { makeOption = \e -> { text = e.name, additional = "" }
             , labelColor = \_ -> \_ -> ""
-            , placeholder = "Choose an equipment"
+            , placeholder = texts.chooseEquipment
             , style = DS.sidebarStyle
             }
     in
     [ { name = tabName TabInbox
-      , title = "Inbox"
+      , title = texts.inbox
       , info = Nothing
       , titleRight = []
       , body =
@@ -1135,7 +1144,7 @@ searchTabs ddd flags settings model =
                 MB.Checkbox
                     { id = "search-inbox"
                     , value = model.inboxCheckbox
-                    , label = "Inbox"
+                    , label = texts.inbox
                     , tagger = \_ -> ToggleInbox
                     }
             , div [ class "mt-2 hidden" ]
@@ -1143,10 +1152,10 @@ searchTabs ddd flags settings model =
                     [ text
                         (case model.textSearchModel of
                             Fulltext _ ->
-                                "Fulltext Search"
+                                texts.fulltextSearch
 
                             Names _ ->
-                                "Search in names"
+                                texts.searchInNames
                         )
                     , a
                         [ classList
@@ -1156,7 +1165,7 @@ searchTabs ddd flags settings model =
                         , class S.link
                         , href "#"
                         , onClick SwapTextSearch
-                        , title "Switch between text search modes"
+                        , title texts.switchSearchModes
                         ]
                         [ i [ class "fa fa-exchange-alt" ] []
                         ]
@@ -1168,26 +1177,26 @@ searchTabs ddd flags settings model =
                     , textSearchString model.textSearchModel |> Maybe.withDefault "" |> value
                     , case model.textSearchModel of
                         Fulltext _ ->
-                            placeholder "Content search…"
+                            placeholder texts.contentSearch
 
                         Names _ ->
-                            placeholder "Search in various names…"
+                            placeholder texts.searchInNamesPlaceholder
                     , class S.textInputSidebar
                     ]
                     []
                 , span [ class "opacity-50 text-sm" ]
                     [ case model.textSearchModel of
                         Fulltext _ ->
-                            text "Fulltext search in document contents and notes."
+                            text texts.fulltextSearchInfo
 
                         Names _ ->
-                            text "Looks in correspondents, concerned entities, item name and notes."
+                            text texts.nameSearchInfo
                     ]
                 ]
             ]
       }
     , { name = tabName TabTags
-      , title = "Tags"
+      , title = texts.basics.tags
       , titleRight = []
       , info = Nothing
       , body =
@@ -1200,7 +1209,7 @@ searchTabs ddd flags settings model =
                 )
       }
     , { name = tabName TabTagCategories
-      , title = "Tag Categories"
+      , title = texts.tagCategoryTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1213,7 +1222,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabFolder
-      , title = "Folder"
+      , title = texts.folderTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1225,7 +1234,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabCorrespondent
-      , title = "Correspondent"
+      , title = texts.correspondentTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1234,10 +1243,10 @@ searchTabs ddd flags settings model =
                 , classList [ ( "hidden", isHidden Data.Fields.CorrOrg ) ]
                 ]
                 [ label [ class S.inputLabel ]
-                    [ text "Organization" ]
+                    [ text texts.organization ]
                 , Html.map OrgMsg
                     (Comp.Dropdown.view2
-                        (Comp.Dropdown.orgFormViewSettings "Choose an organization" DS.sidebarStyle)
+                        (Comp.Dropdown.orgFormViewSettings texts.chooseOrganization DS.sidebarStyle)
                         settings
                         model.orgModel
                     )
@@ -1246,10 +1255,10 @@ searchTabs ddd flags settings model =
                 [ class "mb-4"
                 , classList [ ( "hidden", isHidden Data.Fields.CorrPerson ) ]
                 ]
-                [ label [ class S.inputLabel ] [ text "Person" ]
+                [ label [ class S.inputLabel ] [ text texts.person ]
                 , Html.map CorrPersonMsg
                     (Comp.Dropdown.view2
-                        corrPersonCfg
+                        personCfg
                         settings
                         model.corrPersonModel
                     )
@@ -1257,7 +1266,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabConcerning
-      , title = "Concerning"
+      , title = texts.concerningTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1265,10 +1274,10 @@ searchTabs ddd flags settings model =
                 [ class "mb-4"
                 , classList [ ( "hidden", isHidden Data.Fields.ConcPerson ) ]
                 ]
-                [ label [ class S.inputLabel ] [ text "Person" ]
+                [ label [ class S.inputLabel ] [ text texts.person ]
                 , Html.map ConcPersonMsg
                     (Comp.Dropdown.view2
-                        concPersonCfg
+                        personCfg
                         settings
                         model.concPersonModel
                     )
@@ -1277,7 +1286,7 @@ searchTabs ddd flags settings model =
                 [ class "mb-4"
                 , classList [ ( "hidden", isHidden Data.Fields.ConcEquip ) ]
                 ]
-                [ label [ class S.inputLabel ] [ text "Equipment" ]
+                [ label [ class S.inputLabel ] [ text texts.equipment ]
                 , Html.map ConcEquipmentMsg
                     (Comp.Dropdown.view2
                         concEquipCfg
@@ -1288,20 +1297,24 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabCustomFields
-      , title = "Custom Fields"
+      , title = texts.customFieldsTab
       , titleRight = []
       , info = Nothing
       , body =
             [ Html.map CustomFieldMsg
                 (Comp.CustomFieldMultiInput.view2
-                    DS.sidebarStyle
-                    (Comp.CustomFieldMultiInput.ViewSettings False "field" (\_ -> Nothing))
+                    { showAddButton = False
+                    , classes = ""
+                    , fieldIcon = \_ -> Nothing
+                    , style = DS.sidebarStyle
+                    , createCustomFieldTitle = texts.createCustomFieldTitle
+                    }
                     model.customFieldModel
                 )
             ]
       }
     , { name = tabName TabDate
-      , title = "Date"
+      , title = texts.dateTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1309,7 +1322,7 @@ searchTabs ddd flags settings model =
                 [ class "flex flex-col" ]
                 [ div [ class "mb-2" ]
                     [ label [ class S.inputLabel ]
-                        [ text "From"
+                        [ text texts.from
                         ]
                     , div [ class "relative" ]
                         [ Html.map FromDateMsg
@@ -1326,7 +1339,7 @@ searchTabs ddd flags settings model =
                     ]
                 , div [ class "mb-2" ]
                     [ label [ class S.inputLabel ]
-                        [ text "To"
+                        [ text texts.to
                         ]
                     , div [ class "relative" ]
                         [ Html.map UntilDateMsg
@@ -1341,7 +1354,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabDueDate
-      , title = "Due Date"
+      , title = texts.dueDateTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1349,7 +1362,7 @@ searchTabs ddd flags settings model =
                 [ class "flex flex-col" ]
                 [ div [ class "mb-2" ]
                     [ label [ class S.inputLabel ]
-                        [ text "Due From"
+                        [ text texts.dueFrom
                         ]
                     , div [ class "relative" ]
                         [ Html.map FromDueDateMsg
@@ -1366,7 +1379,7 @@ searchTabs ddd flags settings model =
                     ]
                 , div [ class "mb-2" ]
                     [ label [ class S.inputLabel ]
-                        [ text "Due To"
+                        [ text texts.dueTo
                         ]
                     , div [ class "relative" ]
                         [ Html.map UntilDueDateMsg
@@ -1385,7 +1398,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabSource
-      , title = "Source"
+      , title = texts.sourceTab
       , titleRight = []
       , info = Nothing
       , body =
@@ -1395,7 +1408,7 @@ searchTabs ddd flags settings model =
                     , onInput SetSource
                     , Util.Html.onKeyUpCode KeyUpMsg
                     , model.sourceModel |> Maybe.withDefault "" |> value
-                    , placeholder "Search in item source…"
+                    , placeholder texts.searchInItemSource
                     , class S.textInputSidebar
                     ]
                     []
@@ -1403,7 +1416,7 @@ searchTabs ddd flags settings model =
             ]
       }
     , { name = tabName TabDirection
-      , title = "Direction"
+      , title = texts.directionTab
       , titleRight = []
       , info = Nothing
       , body =
diff --git a/modules/webapp/src/main/elm/Comp/SearchStatsView.elm b/modules/webapp/src/main/elm/Comp/SearchStatsView.elm
index 6e03fd35..861680eb 100644
--- a/modules/webapp/src/main/elm/Comp/SearchStatsView.elm
+++ b/modules/webapp/src/main/elm/Comp/SearchStatsView.elm
@@ -11,6 +11,7 @@ import Data.Icons as Icons
 import Data.Money
 import Html exposing (..)
 import Html.Attributes exposing (..)
+import Messages.SearchStatsViewComp exposing (Texts)
 import Styles as S
 
 
@@ -28,8 +29,8 @@ sortFields fields =
 --- View2
 
 
-view2 : String -> SearchStats -> Html msg
-view2 classes stats =
+view2 : Texts -> String -> SearchStats -> Html msg
+view2 texts classes stats =
     let
         isNumField f =
             f.sum > 0
@@ -75,7 +76,7 @@ view2 classes stats =
                     { rootClass = ""
                     , valueClass = "text-4xl"
                     , value = String.fromInt stats.count
-                    , label = "Items"
+                    , label = texts.items
                     }
                 ]
             , div [ class "flex-grow" ]
@@ -87,15 +88,15 @@ view2 classes stats =
                         [ tr [ class "" ]
                             [ th [ class "py-2 text-left" ] []
                             , th [ class "py-2 text-center" ]
-                                [ text "Count" ]
+                                [ text texts.count ]
                             , th [ class "py-2 text-center" ]
-                                [ text "Sum" ]
+                                [ text texts.sum ]
                             , th [ class "py-2 text-center hidden md:table-cell" ]
-                                [ text "Avg" ]
+                                [ text texts.avg ]
                             , th [ class "py-2 text-center hidden md:table-cell" ]
-                                [ text "Min" ]
+                                [ text texts.min ]
                             , th [ class "py-2 text-center hidden md:table-cell" ]
-                                [ text "Max" ]
+                                [ text texts.max ]
                             ]
                         ]
                     , tbody []
diff --git a/modules/webapp/src/main/elm/Messages.elm b/modules/webapp/src/main/elm/Messages.elm
index ef8d3956..5b9d80ba 100644
--- a/modules/webapp/src/main/elm/Messages.elm
+++ b/modules/webapp/src/main/elm/Messages.elm
@@ -7,6 +7,7 @@ module Messages exposing
 
 import Messages.App
 import Messages.CollectiveSettingsPage
+import Messages.HomePage
 import Messages.ItemDetailPage
 import Messages.LoginPage
 import Messages.ManageDataPage
@@ -35,6 +36,7 @@ type alias Messages =
     , queue : Messages.QueuePage.Texts
     , userSettings : Messages.UserSettingsPage.Texts
     , manageData : Messages.ManageDataPage.Texts
+    , home : Messages.HomePage.Texts
     }
 
 
@@ -97,6 +99,7 @@ gb =
     , queue = Messages.QueuePage.gb
     , userSettings = Messages.UserSettingsPage.gb
     , manageData = Messages.ManageDataPage.gb
+    , home = Messages.HomePage.gb
     }
 
 
@@ -116,4 +119,5 @@ de =
     , queue = Messages.QueuePage.de
     , userSettings = Messages.UserSettingsPage.de
     , manageData = Messages.ManageDataPage.de
+    , home = Messages.HomePage.de
     }
diff --git a/modules/webapp/src/main/elm/Messages/Basics.elm b/modules/webapp/src/main/elm/Messages/Basics.elm
index 5237d95f..aef37b84 100644
--- a/modules/webapp/src/main/elm/Messages/Basics.elm
+++ b/modules/webapp/src/main/elm/Messages/Basics.elm
@@ -16,6 +16,9 @@ type alias Texts =
     , backToList : String
     , searchPlaceholder : String
     , id : String
+    , ok : String
+    , yes : String
+    , no : String
     }
 
 
@@ -35,6 +38,9 @@ gb =
     , backToList = "Back to list"
     , searchPlaceholder = "Search…"
     , id = "Id"
+    , ok = "Ok"
+    , yes = "Yes"
+    , no = "No"
     }
 
 
diff --git a/modules/webapp/src/main/elm/Messages/HomePage.elm b/modules/webapp/src/main/elm/Messages/HomePage.elm
new file mode 100644
index 00000000..575af594
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/HomePage.elm
@@ -0,0 +1,58 @@
+module Messages.HomePage exposing (..)
+
+import Messages.Basics
+import Messages.HomeSideMenu
+import Messages.ItemCardListComp
+import Messages.SearchStatsViewComp
+
+
+type alias Texts =
+    { basics : Messages.Basics.Texts
+    , sideMenu : Messages.HomeSideMenu.Texts
+    , itemCardList : Messages.ItemCardListComp.Texts
+    , searchStatsView : Messages.SearchStatsViewComp.Texts
+    , contentSearch : String
+    , searchInNames : String
+    , selectModeTitle : String
+    , fullHeightPreviewTitle : String
+    , fullWidthPreviewTitle : String
+    , powerSearchPlaceholder : String
+    , reallyReprocessQuestion : String
+    , reallyDeleteQuestion : String
+    , editSelectedItems : Int -> String
+    , reprocessSelectedItems : Int -> String
+    , deleteSelectedItems : Int -> String
+    , selectAllVisible : String
+    , selectNone : String
+    , resetSearchForm : String
+    , exitSelectMode : String
+    }
+
+
+gb : Texts
+gb =
+    { basics = Messages.Basics.gb
+    , sideMenu = Messages.HomeSideMenu.gb
+    , itemCardList = Messages.ItemCardListComp.gb
+    , searchStatsView = Messages.SearchStatsViewComp.gb
+    , contentSearch = "Content search…"
+    , searchInNames = "Search in names…"
+    , selectModeTitle = "Select Mode"
+    , fullHeightPreviewTitle = "Full height preview"
+    , fullWidthPreviewTitle = "Full width preview"
+    , powerSearchPlaceholder = "Search query …"
+    , reallyReprocessQuestion = "Really reprocess all selected items? Metadata of unconfirmed items may change."
+    , reallyDeleteQuestion = "Really delete all selected items?"
+    , editSelectedItems = \n -> "Edit " ++ String.fromInt n ++ " selected items"
+    , reprocessSelectedItems = \n -> "Reprocess " ++ String.fromInt n ++ " selected items"
+    , deleteSelectedItems = \n -> "Delete " ++ String.fromInt n ++ " selected items"
+    , selectAllVisible = "Select all visible"
+    , selectNone = "Select none"
+    , resetSearchForm = "Reset search form"
+    , exitSelectMode = "Exit Select Mode"
+    }
+
+
+de : Texts
+de =
+    gb
diff --git a/modules/webapp/src/main/elm/Messages/HomeSideMenu.elm b/modules/webapp/src/main/elm/Messages/HomeSideMenu.elm
new file mode 100644
index 00000000..bc6a9256
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/HomeSideMenu.elm
@@ -0,0 +1,27 @@
+module Messages.HomeSideMenu exposing (..)
+
+import Messages.MultiEditComp
+import Messages.SearchMenuComp
+
+
+type alias Texts =
+    { searchMenu : Messages.SearchMenuComp.Texts
+    , multiEdit : Messages.MultiEditComp.Texts
+    , editMode : String
+    , resetSearchForm : String
+    , multiEditHeader : String
+    , multiEditInfo : String
+    , close : String
+    }
+
+
+gb : Texts
+gb =
+    { searchMenu = Messages.SearchMenuComp.gb
+    , multiEdit = Messages.MultiEditComp.gb
+    , editMode = "Edit Mode"
+    , resetSearchForm = "Reset search form"
+    , multiEditHeader = "Multi-Edit"
+    , multiEditInfo = "Note that a change here immediatly affects all selected items on the right!"
+    , close = "Close"
+    }
diff --git a/modules/webapp/src/main/elm/Messages/ItemCardComp.elm b/modules/webapp/src/main/elm/Messages/ItemCardComp.elm
new file mode 100644
index 00000000..e83dc466
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/ItemCardComp.elm
@@ -0,0 +1,12 @@
+module Messages.ItemCardComp exposing (..)
+
+
+type alias Texts =
+    { folder : String
+    }
+
+
+gb : Texts
+gb =
+    { folder = "Folder"
+    }
diff --git a/modules/webapp/src/main/elm/Messages/ItemCardListComp.elm b/modules/webapp/src/main/elm/Messages/ItemCardListComp.elm
new file mode 100644
index 00000000..79a5adeb
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/ItemCardListComp.elm
@@ -0,0 +1,14 @@
+module Messages.ItemCardListComp exposing (..)
+
+import Messages.ItemCardComp
+
+
+type alias Texts =
+    { itemCard : Messages.ItemCardComp.Texts
+    }
+
+
+gb : Texts
+gb =
+    { itemCard = Messages.ItemCardComp.gb
+    }
diff --git a/modules/webapp/src/main/elm/Messages/MultiEditComp.elm b/modules/webapp/src/main/elm/Messages/MultiEditComp.elm
new file mode 100644
index 00000000..77f0752f
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/MultiEditComp.elm
@@ -0,0 +1,61 @@
+module Messages.MultiEditComp exposing (..)
+
+import Messages.Basics
+
+
+type alias Texts =
+    { basics : Messages.Basics.Texts
+    , tagModeAddInfo : String
+    , tagModeRemoveInfo : String
+    , tagModeReplaceInfo : String
+    , selectPlaceholder : String
+    , chooseDirection : String
+    , confirmUnconfirm : String
+    , confirm : String
+    , unconfirm : String
+    , changeTagMode : String
+    , folderTab : String
+    , folderNotOwnerWarning : String
+    , customFieldsTab : String
+    , dateTab : String
+    , dueDateTab : String
+    , correspondentTab : String
+    , organization : String
+    , person : String
+    , concerningTab : String
+    , equipment : String
+    , directionTab : String
+    , nameTab : String
+    }
+
+
+gb : Texts
+gb =
+    { basics = Messages.Basics.gb
+    , tagModeAddInfo = "Tags chosen here are *added* to all selected items."
+    , tagModeRemoveInfo = "Tags chosen here are *removed* from all selected items."
+    , tagModeReplaceInfo = "Tags chosen here *replace* those on selected items."
+    , selectPlaceholder = "Select…"
+    , chooseDirection = "Choose a direction…"
+    , confirmUnconfirm = "Confirm/Unconfirm item metadata"
+    , confirm = "Confirm"
+    , unconfirm = "Unconfirm"
+    , changeTagMode = "Change tag edit mode"
+    , folderTab = "Folder"
+    , folderNotOwnerWarning =
+        """
+You are **not a member** of this folder. This item will be **hidden**
+from any search now. Use a folder where you are a member of to make this
+item visible. This message will disappear then.
+                      """
+    , customFieldsTab = "Custom Fields"
+    , dateTab = "Date"
+    , dueDateTab = "Due Date"
+    , correspondentTab = "Correspondent"
+    , organization = "Organization"
+    , person = "Person"
+    , concerningTab = "Concerning"
+    , equipment = "Equipment"
+    , directionTab = "Direction"
+    , nameTab = "Name"
+    }
diff --git a/modules/webapp/src/main/elm/Messages/SearchMenuComp.elm b/modules/webapp/src/main/elm/Messages/SearchMenuComp.elm
new file mode 100644
index 00000000..80fad1d6
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/SearchMenuComp.elm
@@ -0,0 +1,74 @@
+module Messages.SearchMenuComp exposing (..)
+
+import Messages.Basics
+
+
+type alias Texts =
+    { basics : Messages.Basics.Texts
+    , chooseDirection : String
+    , choosePerson : String
+    , chooseEquipment : String
+    , inbox : String
+    , fulltextSearch : String
+    , searchInNames : String
+    , switchSearchModes : String
+    , contentSearch : String
+    , searchInNamesPlaceholder : String
+    , fulltextSearchInfo : String
+    , nameSearchInfo : String
+    , tagCategoryTab : String
+    , folderTab : String
+    , correspondentTab : String
+    , organization : String
+    , chooseOrganization : String
+    , person : String
+    , concerningTab : String
+    , equipment : String
+    , customFieldsTab : String
+    , createCustomFieldTitle : String
+    , dateTab : String
+    , from : String
+    , to : String
+    , dueDateTab : String
+    , dueFrom : String
+    , dueTo : String
+    , sourceTab : String
+    , searchInItemSource : String
+    , directionTab : String
+    }
+
+
+gb : Texts
+gb =
+    { basics = Messages.Basics.gb
+    , chooseDirection = "Choose a direction…"
+    , choosePerson = "Choose a person"
+    , chooseEquipment = "Choose an equipment"
+    , inbox = "Inbox"
+    , fulltextSearch = "Fulltext Search"
+    , searchInNames = "Search in names"
+    , switchSearchModes = "Switch between text search modes"
+    , contentSearch = "Content search…"
+    , searchInNamesPlaceholder = "Search in various names…"
+    , fulltextSearchInfo = "Fulltext search in document contents and notes."
+    , nameSearchInfo = "Looks in correspondents, concerned entities, item name and notes."
+    , tagCategoryTab = "Tag Categories"
+    , folderTab = "Folder"
+    , correspondentTab = "Correspondent"
+    , organization = "Organization"
+    , chooseOrganization = "Choose an organization"
+    , person = "Person"
+    , concerningTab = "Concerning"
+    , equipment = "Equipment"
+    , customFieldsTab = "Custom Fields"
+    , createCustomFieldTitle = "Create a new custom field"
+    , dateTab = "Date"
+    , from = "From"
+    , to = "To"
+    , dueDateTab = "Due Date"
+    , dueFrom = "Due From"
+    , dueTo = "Due To"
+    , sourceTab = "Source"
+    , searchInItemSource = "Search in item source…"
+    , directionTab = "Direction"
+    }
diff --git a/modules/webapp/src/main/elm/Messages/SearchStatsViewComp.elm b/modules/webapp/src/main/elm/Messages/SearchStatsViewComp.elm
new file mode 100644
index 00000000..d6913f09
--- /dev/null
+++ b/modules/webapp/src/main/elm/Messages/SearchStatsViewComp.elm
@@ -0,0 +1,22 @@
+module Messages.SearchStatsViewComp exposing (..)
+
+
+type alias Texts =
+    { items : String
+    , count : String
+    , sum : String
+    , avg : String
+    , min : String
+    , max : String
+    }
+
+
+gb : Texts
+gb =
+    { items = "Items"
+    , count = "Count"
+    , sum = "Sum"
+    , avg = "Avg"
+    , min = "Min"
+    , max = "Max"
+    }
diff --git a/modules/webapp/src/main/elm/Page/Home/Data.elm b/modules/webapp/src/main/elm/Page/Home/Data.elm
index 2f2302d5..2190afb7 100644
--- a/modules/webapp/src/main/elm/Page/Home/Data.elm
+++ b/modules/webapp/src/main/elm/Page/Home/Data.elm
@@ -1,5 +1,6 @@
 module Page.Home.Data exposing
-    ( Model
+    ( ConfirmModalValue(..)
+    , Model
     , Msg(..)
     , SearchParam
     , SearchType(..)
@@ -21,7 +22,6 @@ import Api.Model.BasicResult exposing (BasicResult)
 import Api.Model.ItemLightList exposing (ItemLightList)
 import Api.Model.SearchStats exposing (SearchStats)
 import Browser.Dom as Dom
-import Comp.ConfirmModal
 import Comp.ItemCardList
 import Comp.ItemDetail.FormChange exposing (FormChange)
 import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
@@ -58,10 +58,15 @@ type alias Model =
     }
 
 
+type ConfirmModalValue
+    = ConfirmReprocessItems
+    | ConfirmDelete
+
+
 type alias SelectViewModel =
     { ids : Set String
     , action : SelectActionMode
-    , confirmModal : Maybe (Comp.ConfirmModal.Settings Msg)
+    , confirmModal : Maybe ConfirmModalValue
     , editModel : Comp.ItemDetail.MultiEditMenu.Model
     , saveNameState : SaveNameState
     , saveCustomFieldState : Set String
diff --git a/modules/webapp/src/main/elm/Page/Home/SideMenu.elm b/modules/webapp/src/main/elm/Page/Home/SideMenu.elm
index 412cddcf..f09c84e9 100644
--- a/modules/webapp/src/main/elm/Page/Home/SideMenu.elm
+++ b/modules/webapp/src/main/elm/Page/Home/SideMenu.elm
@@ -9,13 +9,14 @@ import Data.UiSettings exposing (UiSettings)
 import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (onClick)
+import Messages.HomeSideMenu exposing (Texts)
 import Page.Home.Data exposing (..)
 import Set
 import Styles as S
 
 
-view : Flags -> UiSettings -> Model -> Html Msg
-view flags settings model =
+view : Texts -> Flags -> UiSettings -> Model -> Html Msg
+view texts flags settings model =
     div
         [ class "flex flex-col"
         ]
@@ -25,7 +26,7 @@ view flags settings model =
                     { tagger = ToggleSelectView
                     , label = ""
                     , icon = Just "fa fa-tasks"
-                    , title = "Edit Mode"
+                    , title = texts.editMode
                     , inputClass =
                         [ ( S.secondaryBasicButton, True )
                         , ( "bg-gray-200 dark:bg-bluegray-600", selectActive model )
@@ -35,7 +36,7 @@ view flags settings model =
                     { tagger = ResetSearch
                     , label = ""
                     , icon = Just "fa fa-sync"
-                    , title = "Reset search form"
+                    , title = texts.resetSearchForm
                     , inputClass = [ ( S.secondaryBasicButton, True ) ]
                     }
                 ]
@@ -47,19 +48,19 @@ view flags settings model =
                 SelectView svm ->
                     case svm.action of
                         EditSelected ->
-                            viewEditMenu flags svm settings
+                            viewEditMenu texts flags svm settings
 
                         _ ->
-                            viewSearch flags settings model
+                            viewSearch texts flags settings model
 
                 _ ->
-                    viewSearch flags settings model
+                    viewSearch texts flags settings model
             )
         ]
 
 
-viewSearch : Flags -> UiSettings -> Model -> List (Html Msg)
-viewSearch flags settings model =
+viewSearch : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
+viewSearch texts flags settings model =
     [ MB.viewSide
         { start =
             [ MB.CustomElement <|
@@ -75,7 +76,8 @@ viewSearch flags settings model =
         , rootClasses = "my-1 text-xs hidden sm:flex"
         }
     , Html.map SearchMenuMsg
-        (Comp.SearchMenu.viewDrop2 model.dragDropData
+        (Comp.SearchMenu.viewDrop2 texts.searchMenu
+            model.dragDropData
             flags
             settings
             model.searchMenuModel
@@ -83,8 +85,8 @@ viewSearch flags settings model =
     ]
 
 
-viewEditMenu : Flags -> SelectViewModel -> UiSettings -> List (Html Msg)
-viewEditMenu flags svm settings =
+viewEditMenu : Texts -> Flags -> SelectViewModel -> UiSettings -> List (Html Msg)
+viewEditMenu texts flags svm settings =
     let
         cfg_ =
             Comp.ItemDetail.MultiEditMenu.defaultViewConfig
@@ -104,17 +106,17 @@ viewEditMenu flags svm settings =
     [ div [ class S.header2 ]
         [ i [ class "fa fa-edit" ] []
         , span [ class "ml-2" ]
-            [ text "Multi-Edit"
+            [ text texts.multiEditHeader
             ]
         ]
     , div [ class S.infoMessage ]
-        [ text "Note that a change here immediatly affects all selected items on the right!"
+        [ text texts.multiEditInfo
         ]
     , MB.viewSide
         { start =
             [ MB.CustomElement <|
                 B.secondaryButton
-                    { label = "Close"
+                    { label = texts.close
                     , disabled = False
                     , icon = "fa fa-times"
                     , handler = onClick ToggleSelectView
@@ -127,5 +129,11 @@ viewEditMenu flags svm settings =
         , rootClasses = "mt-2 text-sm"
         }
     , Html.map EditMenuMsg
-        (Comp.ItemDetail.MultiEditMenu.view2 flags cfg settings svm.editModel)
+        (Comp.ItemDetail.MultiEditMenu.view2
+            texts.multiEdit
+            flags
+            cfg
+            settings
+            svm.editModel
+        )
     ]
diff --git a/modules/webapp/src/main/elm/Page/Home/Update.elm b/modules/webapp/src/main/elm/Page/Home/Update.elm
index 740ffe06..97abd815 100644
--- a/modules/webapp/src/main/elm/Page/Home/Update.elm
+++ b/modules/webapp/src/main/elm/Page/Home/Update.elm
@@ -3,8 +3,6 @@ module Page.Home.Update exposing (update)
 import Api
 import Api.Model.ItemLightList exposing (ItemLightList)
 import Browser.Navigation as Nav
-import Comp.ConfirmModal
-import Comp.FixedDropdown
 import Comp.ItemCardList
 import Comp.ItemDetail.FormChange exposing (FormChange(..))
 import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
@@ -27,7 +25,6 @@ import Throttle
 import Time
 import Util.Html exposing (KeyCode(..))
 import Util.ItemDragDrop as DD
-import Util.Maybe
 import Util.Update
 
 
@@ -378,19 +375,13 @@ update mId key flags settings msg model =
 
                     else
                         let
-                            lmsg =
-                                Comp.ConfirmModal.defaultSettings
-                                    ReprocessSelectedConfirmed
-                                    CloseConfirmModal
-                                    "Really reprocess all selected items? Metadata of unconfirmed items may change."
-
                             model_ =
                                 { model
                                     | viewMode =
                                         SelectView
                                             { svm
                                                 | action = ReprocessSelected
-                                                , confirmModal = Just lmsg
+                                                , confirmModal = Just ConfirmReprocessItems
                                             }
                                 }
                         in
@@ -446,19 +437,13 @@ update mId key flags settings msg model =
 
                     else
                         let
-                            lmsg =
-                                Comp.ConfirmModal.defaultSettings
-                                    DeleteSelectedConfirmed
-                                    CloseConfirmModal
-                                    "Really delete all selected items?"
-
                             model_ =
                                 { model
                                     | viewMode =
                                         SelectView
                                             { svm
                                                 | action = DeleteSelected
-                                                , confirmModal = Just lmsg
+                                                , confirmModal = Just ConfirmDelete
                                             }
                                 }
                         in
diff --git a/modules/webapp/src/main/elm/Page/Home/View2.elm b/modules/webapp/src/main/elm/Page/Home/View2.elm
index 15602b8a..a1e223e4 100644
--- a/modules/webapp/src/main/elm/Page/Home/View2.elm
+++ b/modules/webapp/src/main/elm/Page/Home/View2.elm
@@ -13,6 +13,7 @@ import Data.UiSettings exposing (UiSettings)
 import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (onClick, onInput)
+import Messages.HomePage exposing (Texts)
 import Page exposing (Page(..))
 import Page.Home.Data exposing (..)
 import Page.Home.SideMenu
@@ -21,28 +22,28 @@ import Styles as S
 import Util.Html
 
 
-viewSidebar : Bool -> Flags -> UiSettings -> Model -> Html Msg
-viewSidebar visible flags settings model =
+viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg
+viewSidebar texts visible flags settings model =
     div
         [ id "sidebar"
         , class S.sidebar
         , class S.sidebarBg
         , classList [ ( "hidden", not visible ) ]
         ]
-        [ Page.Home.SideMenu.view flags settings model
+        [ Page.Home.SideMenu.view texts.sideMenu flags settings model
         ]
 
 
-viewContent : Flags -> UiSettings -> Model -> Html Msg
-viewContent flags settings model =
+viewContent : Texts -> Flags -> UiSettings -> Model -> Html Msg
+viewContent texts flags settings model =
     div
         [ id "item-card-list" -- this id is used in scroll-to-card
         , class S.content
         ]
-        (searchStats flags settings model
-            ++ itemsBar flags settings model
-            ++ itemCardList flags settings model
-            ++ deleteSelectedDimmer model
+        (searchStats texts flags settings model
+            ++ itemsBar texts flags settings model
+            ++ itemCardList texts flags settings model
+            ++ confirmModal texts model
         )
 
 
@@ -50,13 +51,32 @@ viewContent flags settings model =
 --- Helpers
 
 
-deleteSelectedDimmer : Model -> List (Html Msg)
-deleteSelectedDimmer model =
+confirmModal : Texts -> Model -> List (Html Msg)
+confirmModal texts model =
+    let
+        settings modalValue =
+            case modalValue of
+                ConfirmReprocessItems ->
+                    Comp.ConfirmModal.defaultSettings
+                        ReprocessSelectedConfirmed
+                        CloseConfirmModal
+                        texts.basics.yes
+                        texts.basics.no
+                        texts.reallyReprocessQuestion
+
+                ConfirmDelete ->
+                    Comp.ConfirmModal.defaultSettings
+                        DeleteSelectedConfirmed
+                        CloseConfirmModal
+                        texts.basics.yes
+                        texts.basics.no
+                        texts.reallyDeleteQuestion
+    in
     case model.viewMode of
         SelectView svm ->
             case svm.confirmModal of
                 Just confirm ->
-                    [ Comp.ConfirmModal.view confirm
+                    [ Comp.ConfirmModal.view (settings confirm)
                     ]
 
                 Nothing ->
@@ -66,21 +86,21 @@ deleteSelectedDimmer model =
             []
 
 
-itemsBar : Flags -> UiSettings -> Model -> List (Html Msg)
-itemsBar flags settings model =
+itemsBar : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
+itemsBar texts flags settings model =
     case model.viewMode of
         SimpleView ->
-            [ defaultMenuBar flags settings model ]
+            [ defaultMenuBar texts flags settings model ]
 
         SearchView ->
-            [ defaultMenuBar flags settings model ]
+            [ defaultMenuBar texts flags settings model ]
 
         SelectView svm ->
-            [ editMenuBar model svm ]
+            [ editMenuBar texts model svm ]
 
 
-defaultMenuBar : Flags -> UiSettings -> Model -> Html Msg
-defaultMenuBar _ settings model =
+defaultMenuBar : Texts -> Flags -> UiSettings -> Model -> Html Msg
+defaultMenuBar texts _ settings model =
     let
         btnStyle =
             S.secondaryBasicButton ++ " text-sm"
@@ -97,10 +117,10 @@ defaultMenuBar _ settings model =
                     , placeholder
                         (case model.searchTypeDropdownValue of
                             ContentOnlySearch ->
-                                "Content search…"
+                                texts.contentSearch
 
                             BasicSearch ->
-                                "Search in names…"
+                                texts.searchInNames
                         )
                     , onInput SetBasicSearch
                     , Util.Html.onKeyUpCode KeyUpSearchbarMsg
@@ -124,7 +144,10 @@ defaultMenuBar _ settings model =
             div
                 [ class "relative flex flex-grow flex-row" ]
                 [ Html.map PowerSearchMsg
-                    (Comp.PowerSearchInput.viewInput []
+                    (Comp.PowerSearchInput.viewInput
+                        { placeholder = texts.powerSearchPlaceholder
+                        , extraAttrs = []
+                        }
                         model.powerSearchInput
                     )
                 , Html.map PowerSearchMsg
@@ -150,7 +173,7 @@ defaultMenuBar _ settings model =
                 { tagger = ToggleSelectView
                 , label = ""
                 , icon = Just "fa fa-tasks"
-                , title = "Select Mode"
+                , title = texts.selectModeTitle
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "bg-gray-200 dark:bg-bluegray-600", selectActive model )
@@ -170,10 +193,10 @@ defaultMenuBar _ settings model =
                 , icon = Just "fa fa-expand"
                 , title =
                     if settings.cardPreviewFullWidth then
-                        "Full height preview"
+                        texts.fullHeightPreviewTitle
 
                     else
-                        "Full width preview"
+                        texts.fullHeightPreviewTitle
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "hidden sm:inline-block", False )
@@ -185,11 +208,11 @@ defaultMenuBar _ settings model =
         }
 
 
-editMenuBar : Model -> SelectViewModel -> Html Msg
-editMenuBar model svm =
+editMenuBar : Texts -> Model -> SelectViewModel -> Html Msg
+editMenuBar texts model svm =
     let
         selectCount =
-            Set.size svm.ids |> String.fromInt
+            Set.size svm.ids
 
         btnStyle =
             S.secondaryBasicButton ++ " text-sm"
@@ -200,7 +223,7 @@ editMenuBar model svm =
                 { tagger = EditSelectedItems
                 , label = ""
                 , icon = Just "fa fa-edit"
-                , title = "Edit " ++ selectCount ++ " selected items"
+                , title = texts.editSelectedItems selectCount
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "bg-gray-200 dark:bg-bluegray-600", svm.action == EditSelected )
@@ -210,7 +233,7 @@ editMenuBar model svm =
                 { tagger = RequestReprocessSelected
                 , label = ""
                 , icon = Just "fa fa-redo"
-                , title = "Reprocess " ++ selectCount ++ " selected items"
+                , title = texts.reprocessSelectedItems selectCount
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "bg-gray-200 dark:bg-bluegray-600", svm.action == ReprocessSelected )
@@ -220,7 +243,7 @@ editMenuBar model svm =
                 { tagger = RequestDeleteSelected
                 , label = ""
                 , icon = Just "fa fa-trash"
-                , title = "Delete " ++ selectCount ++ " selected items"
+                , title = texts.deleteSelectedItems selectCount
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "bg-gray-200 dark:bg-bluegray-600", svm.action == DeleteSelected )
@@ -232,7 +255,7 @@ editMenuBar model svm =
                 { tagger = SelectAllItems
                 , label = ""
                 , icon = Just "fa fa-check-square font-thin"
-                , title = "Select all visible"
+                , title = texts.selectAllVisible
                 , inputClass =
                     [ ( btnStyle, True )
                     ]
@@ -241,21 +264,21 @@ editMenuBar model svm =
                 { tagger = SelectNoItems
                 , label = ""
                 , icon = Just "fa fa-square font-thin"
-                , title = "Select none"
+                , title = texts.selectNone
                 , inputClass =
                     [ ( btnStyle, True )
                     ]
                 }
             , MB.TextLabel
                 { icon = ""
-                , label = selectCount
+                , label = String.fromInt selectCount
                 , class = "px-4 py-2 w-10 rounded-full font-bold bg-blue-100 dark:bg-lightblue-600 "
                 }
             , MB.CustomButton
                 { tagger = ResetSearch
                 , label = ""
                 , icon = Just "fa fa-sync"
-                , title = "Reset search form"
+                , title = texts.resetSearchForm
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "hidden sm:block", True )
@@ -265,7 +288,7 @@ editMenuBar model svm =
                 { tagger = ToggleSelectView
                 , label = ""
                 , icon = Just "fa fa-tasks"
-                , title = "Exit Select Mode"
+                , title = texts.exitSelectMode
                 , inputClass =
                     [ ( btnStyle, True )
                     , ( "bg-gray-200 dark:bg-bluegray-600", selectActive model )
@@ -276,18 +299,18 @@ editMenuBar model svm =
         }
 
 
-searchStats : Flags -> UiSettings -> Model -> List (Html Msg)
-searchStats _ settings model =
+searchStats : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
+searchStats texts _ settings model =
     if settings.searchStatsVisible then
-        [ Comp.SearchStatsView.view2 "my-2" model.searchStats
+        [ Comp.SearchStatsView.view2 texts.searchStatsView "my-2" model.searchStats
         ]
 
     else
         []
 
 
-itemCardList : Flags -> UiSettings -> Model -> List (Html Msg)
-itemCardList _ settings model =
+itemCardList : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
+itemCardList texts _ settings model =
     let
         itemViewCfg =
             case model.viewMode of
@@ -302,7 +325,11 @@ itemCardList _ settings model =
                         Data.ItemSelection.Inactive
     in
     [ Html.map ItemCardListMsg
-        (Comp.ItemCardList.view2 itemViewCfg settings model.itemListModel)
+        (Comp.ItemCardList.view2 texts.itemCardList
+            itemViewCfg
+            settings
+            model.itemListModel
+        )
     , loadMore settings model
     ]