diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index 2bf029b51..5a5f34e4a 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -79,6 +79,7 @@ class HomeController extends Controller
     {
         $locale = app()->getLocale();
         $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
+
         if (cache()->has($cacheKey) && config('app.env') !== 'development') {
             $resp = cache($cacheKey);
         } else {
@@ -89,15 +90,6 @@ class HomeController extends Controller
                 'entities' => trans('entities'),
                 'errors' => trans('errors')
             ];
-            if ($locale !== 'en') {
-                $enTrans = [
-                    'common' => trans('common', [], 'en'),
-                    'components' => trans('components', [], 'en'),
-                    'entities' => trans('entities', [], 'en'),
-                    'errors' => trans('errors', [], 'en')
-                ];
-                $translations = array_replace_recursive($enTrans, $translations);
-            }
             $resp = 'window.translations = ' . json_encode($translations);
             cache()->put($cacheKey, $resp, 120);
         }
diff --git a/app/Providers/TranslationServiceProvider.php b/app/Providers/TranslationServiceProvider.php
new file mode 100644
index 000000000..0e628c7da
--- /dev/null
+++ b/app/Providers/TranslationServiceProvider.php
@@ -0,0 +1,32 @@
+<?php namespace BookStack\Providers;
+
+
+use BookStack\Translation\Translator;
+
+class TranslationServiceProvider extends \Illuminate\Translation\TranslationServiceProvider
+{
+    /**
+     * Register the service provider.
+     *
+     * @return void
+     */
+    public function register()
+    {
+        $this->registerLoader();
+
+        $this->app->singleton('translator', function ($app) {
+            $loader = $app['translation.loader'];
+
+            // When registering the translator component, we'll need to set the default
+            // locale as well as the fallback locale. So, we'll grab the application
+            // configuration so we can easily get both of these values from there.
+            $locale = $app['config']['app.locale'];
+
+            $trans = new Translator($loader, $locale);
+
+            $trans->setFallback($app['config']['app.fallback_locale']);
+
+            return $trans;
+        });
+    }
+}
\ No newline at end of file
diff --git a/app/Translation/Translator.php b/app/Translation/Translator.php
new file mode 100644
index 000000000..2edfecf73
--- /dev/null
+++ b/app/Translation/Translator.php
@@ -0,0 +1,74 @@
+<?php namespace BookStack\Translation;
+
+
+class Translator extends \Illuminate\Translation\Translator
+{
+
+    /**
+     * Mapping of locales to their base locales
+     * @var array
+     */
+    protected $baseLocaleMap = [
+        'de_informal' => 'de',
+    ];
+
+    /**
+     * Get the translation for a given key.
+     *
+     * @param  string  $key
+     * @param  array   $replace
+     * @param  string  $locale
+     * @return string|array|null
+     */
+    public function trans($key, array $replace = [], $locale = null)
+    {
+        $translation = $this->get($key, $replace, $locale);
+
+        if (is_array($translation)) {
+            $translation = $this->mergeBackupTranslations($translation, $key, $locale);
+        }
+
+        return $translation;
+    }
+
+    /**
+     * Merge the fallback translations, and base translations if existing,
+     * into the provided core key => value array of translations content.
+     * @param array $translationArray
+     * @param string $key
+     * @param null $locale
+     * @return array
+     */
+    protected function mergeBackupTranslations(array $translationArray, string $key, $locale = null)
+    {
+        $fallback = $this->get($key, [], $this->fallback);
+        $baseLocale = $this->getBaseLocale($locale ?? $this->locale);
+        $baseTranslations = $baseLocale ? $this->get($key, [], $baseLocale) : [];
+
+        return array_replace_recursive($fallback, $baseTranslations, $translationArray);
+    }
+
+    /**
+     * Get the array of locales to be checked.
+     *
+     * @param  string|null  $locale
+     * @return array
+     */
+    protected function localeArray($locale)
+    {
+        $primaryLocale = $locale ?: $this->locale;
+        return array_filter([$primaryLocale, $this->getBaseLocale($primaryLocale), $this->fallback]);
+    }
+
+    /**
+     * Get the locale to extend for the given locale.
+     *
+     * @param string $locale
+     * @return string|null
+     */
+    protected function getBaseLocale($locale)
+    {
+        return $this->baseLocaleMap[$locale] ?? null;
+    }
+
+}
\ No newline at end of file
diff --git a/composer.json b/composer.json
index a34c65091..a9b38bff4 100644
--- a/composer.json
+++ b/composer.json
@@ -6,6 +6,7 @@
     "type": "project",
     "require": {
         "php": ">=7.0.0",
+        "ext-json": "*",
         "ext-tidy": "*",
         "ext-dom": "*",
         "laravel/framework": "~5.5.44",
diff --git a/config/app.php b/config/app.php
index 5209b5372..3040a36c6 100755
--- a/config/app.php
+++ b/config/app.php
@@ -187,7 +187,6 @@ return [
         Illuminate\Redis\RedisServiceProvider::class,
         Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
         Illuminate\Session\SessionServiceProvider::class,
-        Illuminate\Translation\TranslationServiceProvider::class,
         Illuminate\Validation\ValidationServiceProvider::class,
         Illuminate\View\ViewServiceProvider::class,
         Illuminate\Notifications\NotificationServiceProvider::class,
@@ -205,6 +204,7 @@ return [
          * Application Service Providers...
          */
         BookStack\Providers\PaginationServiceProvider::class,
+        BookStack\Providers\TranslationServiceProvider::class,
 
         BookStack\Providers\AuthServiceProvider::class,
         BookStack\Providers\AppServiceProvider::class,
diff --git a/resources/lang/de_informal/activities.php b/resources/lang/de_informal/activities.php
index 79595ac4b..c82c9e0c4 100644
--- a/resources/lang/de_informal/activities.php
+++ b/resources/lang/de_informal/activities.php
@@ -1,8 +1,6 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
-    
-];
-
-return array_replace($de_formal, $de_informal);
+// Extends 'de'
+return [
+    //
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/auth.php b/resources/lang/de_informal/auth.php
index 588f03dc1..de9ef91a4 100644
--- a/resources/lang/de_informal/auth.php
+++ b/resources/lang/de_informal/auth.php
@@ -1,7 +1,8 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
+
     /*
     |--------------------------------------------------------------------------
     | Authentication Language Lines
@@ -13,6 +14,7 @@ $de_informal = [
     |
     */
     'throttle' => 'Zu viele Anmeldeversuche. Bitte versuche es in :seconds Sekunden erneut.',
+
     /**
      * Login & Register
      */
@@ -20,6 +22,7 @@ $de_informal = [
     'register_confirm' => 'Bitte prüfe Deinen Posteingang und bestätig die Registrierung.',
     'registration_email_domain_invalid' => 'Du kannst dich mit dieser E-Mail nicht registrieren.',
     'register_success' => 'Vielen Dank für Deine Registrierung! Die Daten sind gespeichert und Du bist angemeldet.',
+
     /**
      * Password Reset
      */
@@ -28,6 +31,7 @@ $de_informal = [
     'reset_password_success' => 'Dein Passwort wurde erfolgreich zurückgesetzt.',
     'email_reset_text' => 'Du erhältsts diese E-Mail, weil jemand versucht hat, Dein Passwort zurückzusetzen.',
     'email_reset_not_requested' => 'Wenn Du das nicht warst, brauchst Du nichts weiter zu tun.',
+
     /**
      * Email Confirmation
      */
@@ -40,6 +44,4 @@ $de_informal = [
     'email_not_confirmed_text' => 'Deine E-Mail-Adresse ist bisher nicht bestätigt.',
     'email_not_confirmed_click_link' => 'Bitte klicke auf den Link in der E-Mail, die Du nach der Registrierung erhalten hast.',
     'email_not_confirmed_resend' => 'Wenn Du die E-Mail nicht erhalten hast, kannst Du die Nachricht erneut anfordern. Fülle hierzu bitte das folgende Formular aus:',
-];
-
-return array_replace($de_formal, $de_informal);
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/common.php b/resources/lang/de_informal/common.php
index 9121b18ca..d80fa9dcf 100644
--- a/resources/lang/de_informal/common.php
+++ b/resources/lang/de_informal/common.php
@@ -1,11 +1,9 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
     /**
      * Email Content
      */
     'email_action_help' => 'Sollte es beim Anklicken der Schaltfläche ":action_text" Probleme geben, öffne die folgende URL in Deinem Browser:',
-];
-
-return array_replace($de_formal, $de_informal);
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/components.php b/resources/lang/de_informal/components.php
index 4027da46e..31cc9ca1b 100644
--- a/resources/lang/de_informal/components.php
+++ b/resources/lang/de_informal/components.php
@@ -1,12 +1,10 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
     /**
      * Image Manager
      */
     'image_delete_confirm' => 'Bitte klicke erneut auf löschen, wenn Du dieses Bild wirklich entfernen möchtest.',
     'image_dropzone' => 'Ziehe Bilder hierher oder klicke hier, um ein Bild auszuwählen',
-];
-
-return array_replace($de_formal, $de_informal);
\ No newline at end of file
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/entities.php b/resources/lang/de_informal/entities.php
index d50b0029d..21fdbb13d 100644
--- a/resources/lang/de_informal/entities.php
+++ b/resources/lang/de_informal/entities.php
@@ -1,21 +1,24 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
     /**
      * Shared
      */
     'no_pages_viewed' => 'Du hast bisher keine Seiten angesehen.',
     'no_pages_recently_created' => 'Du hast bisher keine Seiten angelegt.',
     'no_pages_recently_updated' => 'Du hast bisher keine Seiten aktualisiert.',
+
     /**
      * Books
      */
     'books_delete_confirmation' => 'Bist Du sicher, dass Du dieses Buch löschen möchtest?',
+
     /**
      * Chapters
      */
     'chapters_delete_confirm' => 'Bist Du sicher, dass Du dieses Kapitel löschen möchtest?',
+
     /**
      * Pages
      */
@@ -30,6 +33,7 @@ $de_informal = [
         'time_b' => 'in den letzten :minCount Minuten',
         'message' => ':start :time. Achte darauf, keine Änderungen von anderen Benutzern zu überschreiben!',
     ],
+
     /**
      * Editor sidebar
      */
@@ -39,15 +43,15 @@ $de_informal = [
     'attachments_dropzone' => 'Ziehe Dateien hierher oder klicke hier, um eine Datei auszuwählen',
     'attachments_explain_link' => 'Wenn Du keine Datei hochladen möchtest, kannst Du stattdessen einen Link hinzufügen. Dieser Link kann auf eine andere Seite oder eine Datei im Internet verweisen.',
     'attachments_edit_drop_upload' => 'Ziehe Dateien hierher, um diese hochzuladen und zu überschreiben',
+
     /**
      * Comments
      */
     'comment_placeholder' => 'Gib hier Deine Kommentare ein (Markdown unterstützt)',
     'comment_delete_confirm' => 'Möchtst Du diesen Kommentar wirklich löschen?',
+
     /**
      * Revision
      */
     'revision_delete_confirm' => 'Bist Du sicher, dass Du diese Revision löschen möchtest?',
 ];
-
-return array_replace($de_formal, $de_informal);
diff --git a/resources/lang/de_informal/errors.php b/resources/lang/de_informal/errors.php
index 9cc123c3d..924deee0d 100644
--- a/resources/lang/de_informal/errors.php
+++ b/resources/lang/de_informal/errors.php
@@ -1,10 +1,11 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
     // Pages
     'permission' => 'Du hast keine Berechtigung, auf diese Seite zuzugreifen.',
     'permissionJson' => 'Du hast keine Berechtigung, die angeforderte Aktion auszuführen.',
+
     // Auth
     'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melde dich an.',
     'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registriere dich erneut.',
@@ -12,18 +13,20 @@ $de_informal = [
     'social_account_email_in_use' => 'Die E-Mail-Adresse ":email" ist bereits registriert. Wenn Du bereits registriert bist, kannst Du Dein :socialAccount-Konto in Deinen Profil-Einstellungen verknüpfen.',
     'social_account_not_used' => 'Dieses :socialAccount-Konto ist bisher keinem Benutzer zugeordnet. Du kannst das in Deinen Profil-Einstellungen tun.',
     'social_account_register_instructions' => 'Wenn Du bisher kein Social-Media Konto besitzt, kannst Du ein solches Konto mit der :socialAccount Option anlegen.',
+
     // System
     'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stelle sicher, dass dieser Ordner auf dem Server beschreibbar ist.',
     'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfe, ob die GD PHP-Erweiterung installiert ist.',
     'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuche es mit einer kleineren Datei.',
+
     // Pages
     'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stelle sicher, dass Du mit dem Internet verbunden bist, bevor Du den Entwurf dieser Seite speicherst.',
     'page_custom_home_deletion' => 'Eine als Startseite gesetzte Seite kann nicht gelöscht werden.',
+
     // Users
     'users_cannot_delete_only_admin' => 'Du kannst den einzigen Administrator nicht löschen.',
     'users_cannot_delete_guest' => 'Du kannst den Gast-Benutzer nicht löschen',
+
     // Error pages
     'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Du angefordert hast, wurde nicht gefunden.',
 ];
-
-return array_replace($de_formal, $de_informal);
diff --git a/resources/lang/de_informal/pagination.php b/resources/lang/de_informal/pagination.php
index efab3e48f..c82c9e0c4 100644
--- a/resources/lang/de_informal/pagination.php
+++ b/resources/lang/de_informal/pagination.php
@@ -1,8 +1,6 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
-
-];
-
-return array_replace($de_formal, $de_informal);
+// Extends 'de'
+return [
+    //
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/passwords.php b/resources/lang/de_informal/passwords.php
index efab3e48f..c82c9e0c4 100644
--- a/resources/lang/de_informal/passwords.php
+++ b/resources/lang/de_informal/passwords.php
@@ -1,8 +1,6 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
-
-];
-
-return array_replace($de_formal, $de_informal);
+// Extends 'de'
+return [
+    //
+];
\ No newline at end of file
diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php
index 67bd32c13..c8f5a1b10 100644
--- a/resources/lang/de_informal/settings.php
+++ b/resources/lang/de_informal/settings.php
@@ -1,12 +1,13 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
+// Extends 'de'
+return [
     /**
      * Settings text strings
      * Contains all text strings used in the general settings sections of BookStack
      * including users and roles.
      */
+
     /**
      * App settings
      */
@@ -14,17 +15,20 @@ $de_informal = [
     'app_primary_color_desc' => "Dies sollte ein HEX Wert sein.\nWenn Du nichts eingibst, wird die Anwendung auf die Standardfarbe zurückgesetzt.",
     'app_homepage_desc' => 'Wähle eine Seite als Startseite aus, die statt der Standardansicht angezeigt werden soll. Seitenberechtigungen werden für die ausgewählten Seiten ignoriert.',
     'app_homepage_books' => 'Oder wähle die Buch-Übersicht als Startseite. Das wird die Seiten-Auswahl überschreiben.',
+
     /**
      * Maintenance settings
      */
     'maint_image_cleanup_desc' => 'Überprüft Seiten- und Versionsinhalte auf ungenutzte und mehrfach vorhandene Bilder. Erstelle vor dem Start ein Backup Deiner Datenbank und Bilder.',
     'maint_image_cleanup_warning' => ':count eventuell unbenutze Bilder wurden gefunden. Möchtest Du diese Bilder löschen?',
+
     /**
      * Role settings
      */
     'role_delete_confirm' => 'Du möchtest die Rolle ":roleName" löschen.',
     'role_delete_users_assigned' => 'Diese Rolle ist :userCount Benutzern zugeordnet. Du kannst unten eine neue Rolle auswählen, die Du diesen Benutzern zuordnen möchtest.',
     'role_delete_sure' => 'Bist Du sicher, dass Du diese Rolle löschen möchtest?',
+
     /**
      * Users
      */
@@ -32,5 +36,3 @@ $de_informal = [
     'users_delete_confirm' => 'Bist Du sicher, dass Du diesen Benutzer löschen möchtest?',
     'users_social_accounts_info' => 'Hier kannst Du andere Social-Media-Konten für eine schnellere und einfachere Anmeldung verknüpfen. Wenn Du ein Social-Media Konto löschst, bleibt der Zugriff erhalten. Entferne in diesem Falle die Berechtigung in Deinen Profil-Einstellungen des verknüpften Social-Media-Kontos.',
 ];
-
-return array_replace($de_formal, $de_informal);
diff --git a/resources/lang/de_informal/validation.php b/resources/lang/de_informal/validation.php
index efab3e48f..c82c9e0c4 100644
--- a/resources/lang/de_informal/validation.php
+++ b/resources/lang/de_informal/validation.php
@@ -1,8 +1,6 @@
 <?php
-$de_formal = (include resource_path() . '/lang/de/' . basename(__FILE__));
 
-$de_informal = [
-
-];
-
-return array_replace($de_formal, $de_informal);
+// Extends 'de'
+return [
+    //
+];
\ No newline at end of file
diff --git a/tests/LanguageTest.php b/tests/LanguageTest.php
index 2b3b00ac0..64cad4817 100644
--- a/tests/LanguageTest.php
+++ b/tests/LanguageTest.php
@@ -81,4 +81,30 @@ class LanguageTest extends TestCase
         $this->assertTrue(config('app.rtl'), "App RTL config should have been set to true by middleware");
     }
 
+    public function test_de_informal_falls_base_to_de()
+    {
+        // Base de back value
+        $deBack = trans()->get('common.cancel', [], 'de', false);
+        $this->assertEquals('Abbrechen', $deBack);
+        // Ensure de_informal has no value set
+        $this->assertEquals('common.cancel', trans()->get('common.cancel', [], 'de_informal', false));
+        // Ensure standard trans falls back to de
+        $this->assertEquals($deBack, trans('common.cancel', [], 'de_informal'));
+        // Ensure de_informal gets its own values where set
+        $deEmailActionHelp = trans()->get('common.email_action_help', [], 'de', false);
+        $enEmailActionHelp = trans()->get('common.email_action_help', [], 'en', false);
+        $deInformalEmailActionHelp = trans()->get('common.email_action_help', [], 'de_informal', false);
+        $this->assertNotEquals($deEmailActionHelp, $deInformalEmailActionHelp);
+        $this->assertNotEquals($enEmailActionHelp, $deInformalEmailActionHelp);
+    }
+
+    public function test_de_informal_falls_base_to_de_in_js_endpoint()
+    {
+        $this->asEditor();
+        setting()->putUser($this->getEditor(), 'language', 'de_informal');
+
+        $transResp = $this->get('/translations');
+        $transResp->assertSee('"cancel":"Abbrechen"');
+    }
+
 }
\ No newline at end of file