diff --git a/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po b/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000000000000000000000000000000000..335d14ad4e58736619502c3176135bb205d8dbe2
--- /dev/null
+++ b/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-21 21:04+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
+"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+
+#: static/js/main.js:21
+msgid "Today"
+msgstr ""
+
+#: static/js/main.js:22
+msgid "Cancel"
+msgstr ""
+
+#: static/js/main.js:23
+msgid "OK"
+msgstr ""
diff --git a/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po b/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000000000000000000000000000000000..01864b41af67222125210762c072fb23302fda3a
--- /dev/null
+++ b/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po
@@ -0,0 +1,30 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-21 21:04+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: static/js/main.js:21
+msgid "Today"
+msgstr ""
+
+#: static/js/main.js:22
+msgid "Cancel"
+msgstr ""
+
+#: static/js/main.js:23
+msgid "OK"
+msgstr ""
diff --git a/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po b/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000000000000000000000000000000000..d714559929037c311183f5533697aef73d8b6a12
--- /dev/null
+++ b/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po
@@ -0,0 +1,31 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-21 21:04+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: static/js/main.js:21
+msgid "Today"
+msgstr ""
+
+#: static/js/main.js:22
+msgid "Cancel"
+msgstr ""
+
+#: static/js/main.js:23
+msgid "OK"
+msgstr ""
diff --git a/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po b/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000000000000000000000000000000000..01864b41af67222125210762c072fb23302fda3a
--- /dev/null
+++ b/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po
@@ -0,0 +1,30 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-21 21:04+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: static/js/main.js:21
+msgid "Today"
+msgstr ""
+
+#: static/js/main.js:22
+msgid "Cancel"
+msgstr ""
+
+#: static/js/main.js:23
+msgid "OK"
+msgstr ""
diff --git a/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po b/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po
new file mode 100644
index 0000000000000000000000000000000000000000..01864b41af67222125210762c072fb23302fda3a
--- /dev/null
+++ b/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po
@@ -0,0 +1,30 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-21 21:04+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: static/js/main.js:21
+msgid "Today"
+msgstr ""
+
+#: static/js/main.js:22
+msgid "Cancel"
+msgstr ""
+
+#: static/js/main.js:23
+msgid "OK"
+msgstr ""
diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py
index 8dcea9b41d3b7bbec67dd5e09ec9babb471f879e..8b0f6bcd271f599026d7bb43ea5d966f4e407a67 100644
--- a/aleksis/core/settings.py
+++ b/aleksis/core/settings.py
@@ -97,6 +97,7 @@ MIDDLEWARE = [
     "django.middleware.security.SecurityMiddleware",
     "django.contrib.sessions.middleware.SessionMiddleware",
     "django.middleware.locale.LocaleMiddleware",
+    "django.middleware.http.ConditionalGetMiddleware",
     "django_global_request.middleware.GlobalRequestMiddleware",
     "django.middleware.common.CommonMiddleware",
     "django.middleware.csrf.CsrfViewMiddleware",
diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js
index bc06c7eed31d859f8e329a0e43ef936a289a8107..f3439d2a573a93a094e189c142e0d9fc6ee41cf8 100644
--- a/aleksis/core/static/js/main.js
+++ b/aleksis/core/static/js/main.js
@@ -8,8 +8,8 @@ $(document).ready( function () {
 
     // Initialize datepicker [MAT]
     $('.datepicker').datepicker({
-        format: 'dd.mm.yyyy',
-        // Translate to German
+        format: get_format('SHORT_DATE_FORMAT').toLowerCase().replace('d', 'dd').replace('m', 'mm').replace('y', 'yyyy'),
+        // Pull translations from Django helpers
         i18n: {
             months: calendarweek_i18n.month_names,
             monthsShort: calendarweek_i18n.month_abbrs,
@@ -18,13 +18,13 @@ $(document).ready( function () {
             weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v])=> v),
 
             // Buttons
-            today: 'Heute',
-            cancel: 'Abbrechen',
-            done: 'OK',
+            today: gettext('Today'),
+            cancel: gettext('Cancel'),
+            done: gettext('OK'),
         },
 
         // Set monday as first day of week
-        firstDay: 1,
+        firstDay: get_format('FIRST_DAY_OF_WEEK'),
         autoClose: true
     });
 
diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html
index 7be24fc5e9b61f80466dc48a73fa4d429397d6a8..a461e88fa37859b9220e5910e6f9046bf25388db 100644
--- a/aleksis/core/templates/core/base.html
+++ b/aleksis/core/templates/core/base.html
@@ -35,8 +35,9 @@
   <script src="{% url "js_reverse" %}" type="text/javascript"></script>
 
   {# Add i18n names for calendar (for use in datepicker) #}
-  {# Passing the locale is not necessary for the script to work, but prevents caching issues #}
+  {# Passing the locale is not necessary for the scripts to work, but prevents caching issues #}
   {% get_current_language as LANGUAGE_CODE %}
+  <script src="{% url "javascript-catalog" %}?locale={{ LANGUAGE_CODE }}" type="text/javascript"></script>
   <script src="{% url "calendarweek_i18n_js" %}?first_day=6&amp;locale={{ LANGUAGE_CODE }}" type="text/javascript"></script>
 
   {# Include jQuery to provide $(document).ready #}
diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py
index bcf01d82b86b9d7a390254a34bfb9df5140ebcc9..63929088ba38406d0e560fcaee218404ad1462bf 100644
--- a/aleksis/core/urls.py
+++ b/aleksis/core/urls.py
@@ -4,6 +4,7 @@ from django.conf.urls.static import static
 from django.contrib import admin
 from django.contrib.auth import views as auth_views
 from django.urls import include, path
+from django.views.i18n import JavaScriptCatalog
 
 import calendarweek.django
 import debug_toolbar
@@ -40,6 +41,7 @@ urlpatterns = [
     path("select2/", include("django_select2.urls")),
     path("jsreverse.js", urls_js, name='js_reverse'),
     path("calendarweek_i18n.js", calendarweek.django.i18n_js, name="calendarweek_i18n_js"),
+    path('gettext.js', JavaScriptCatalog.as_view(), name='javascript-catalog'),
 ]
 
 # Serve static files from STATIC_ROOT to make it work with runserver
diff --git a/dev.sh b/dev.sh
index 51884395620140fb107680066825d668c61bf55c..a9bae65132dd9c9d48ac8a38f67053e4af476886 100755
--- a/dev.sh
+++ b/dev.sh
@@ -29,6 +29,7 @@ case "$1" in
 	for d in aleksis/core apps/official/*/aleksis/apps/*; do
 		echo; echo "Entering $d."
 		poetry run sh -c "cd $d; $manage_py makemessages --no-wrap -i static $locales"
+		poetry run sh -c "cd $d; $manage_py makemessages --no-wrap -d djangojs $locales"
 	done
 	exit
 	;;