diff --git a/config/trans.toml b/config/trans.toml
index c7a4216caffaa00881b304340e4623c023c42650..febbc897efc7c02febdf3728344db791113f7c65 100644
--- a/config/trans.toml
+++ b/config/trans.toml
@@ -7,4 +7,8 @@ default = true
 
 [locales.en]
 path = "en"
-name = "English"
\ No newline at end of file
+name = "English"
+
+[locales.es]
+path = "es"
+name = "EspaƱol"
\ No newline at end of file
diff --git a/src/app/user/web/web.go b/src/app/user/web/web.go
index 7ef607df91230febd15bf494c70ebd82508c0e71..06b481a37d5513679c47f6766804a2cbfbd366e5 100644
--- a/src/app/user/web/web.go
+++ b/src/app/user/web/web.go
@@ -6,9 +6,11 @@ import (
 	"github.com/org-harmony/harmony/src/core/auth"
 	"github.com/org-harmony/harmony/src/core/config"
 	"github.com/org-harmony/harmony/src/core/hctx"
+	"github.com/org-harmony/harmony/src/core/trans"
 	"github.com/org-harmony/harmony/src/core/util"
 	"github.com/org-harmony/harmony/src/core/web"
 	"net/http"
+	"time"
 )
 
 const Pkg = "app.user.web"
@@ -18,6 +20,7 @@ var ErrUpdateUser = errors.New("user.settings.update-error")
 
 // RegisterController registers the web controllers for the user module.
 // It registers the following routes:
+//   - GET /user/me/language/{locale} For updating the user language.
 //   - GET /auth/login For displaying various OAuth2 login buttons.
 //   - GET /auth/logout For logging out the user.
 //   - GET /user/me For displaying the user profile.
@@ -35,6 +38,7 @@ func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
 	authCfg := &auth.Cfg{}
 	util.Ok(config.C(authCfg, config.From("auth"), config.Validate(appCtx.Validator)))
 
+	router.Get("/user/me/language/{locale}", userLanguageController(appCtx, webCtx).ServeHTTP)
 	router.Get("/auth/login", loginController(appCtx, webCtx, authCfg).ServeHTTP)
 	router.Get("/auth/logout", logoutController(appCtx, webCtx).ServeHTTP)
 
@@ -78,6 +82,34 @@ func registerNavigation(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
 		},
 		Position: 1000,
 	})
+
+	webCtx.Navigation.Add("user.language.de", web.NavItem{
+		URL:  "/user/me/language/de",
+		Name: "harmony.menu.language.de",
+		Display: func(io web.IO) (bool, error) {
+			locale, err := io.Request().Cookie(trans.LocaleSessionKey)
+			if err != nil {
+				return false, err
+			}
+
+			return locale.Value != "de", nil
+		},
+		Position: 1050,
+	})
+
+	webCtx.Navigation.Add("user.language.en", web.NavItem{
+		URL:  "/user/me/language/en",
+		Name: "harmony.menu.language.en",
+		Display: func(io web.IO) (bool, error) {
+			locale, err := io.Request().Cookie(trans.LocaleSessionKey)
+			if err != nil {
+				return true, err
+			}
+
+			return locale.Value != "en", nil
+		},
+		Position: 1050,
+	})
 }
 
 func registerTemplateDataExtensions(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
@@ -122,6 +154,25 @@ func logoutController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
 	})
 }
 
+func userLanguageController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		request := io.Request()
+		locale := web.URLParam(request, "locale")
+
+		cookie := http.Cookie{
+			Name:     trans.LocaleSessionKey,
+			Value:    locale,
+			Expires:  time.Now().Add(365 * 24 * time.Hour),
+			SameSite: http.SameSiteLaxMode,
+			Path:     "/",
+		}
+
+		http.SetCookie(io.Response(), &cookie)
+
+		return io.Redirect("/", http.StatusTemporaryRedirect)
+	})
+}
+
 func userProfileController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
 	return web.NewController(appCtx, webCtx, func(io web.IO) error {
 		return io.Render(
diff --git a/translations/de.json b/translations/de.json
index 8f03d16efa0799c2f523a7e7b5978ba5345aac4b..7364b49815a4c16687a000c26037702f00c64b26 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -181,7 +181,12 @@
       "template-sets": "Schablonen",
       "user": "Profil",
       "login": "Anmelden",
-      "logout": "Abmelden"
+      "logout": "Abmelden",
+      "language": {
+        "label": "Sprache",
+        "de": "Deutsch",
+        "en": "Englisch"
+      }
     },
     "error": {
       "generic": "Leider ist ein unerwarteter Fehler aufgetreten.",
diff --git a/translations/es.json b/translations/es.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/translations/es.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file