diff --git a/app/Config/app.php b/app/Config/app.php
index 24ed5799b..7297048b4 100755
--- a/app/Config/app.php
+++ b/app/Config/app.php
@@ -124,6 +124,7 @@ return [
         BookStack\Providers\EventServiceProvider::class,
         BookStack\Providers\RouteServiceProvider::class,
         BookStack\Providers\CustomFacadeProvider::class,
+        BookStack\Providers\CustomValidationServiceProvider::class,
     ],
 
     /*
diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php
index 008a9080c..f32dd8582 100644
--- a/app/Entities/Repos/BookRepo.php
+++ b/app/Entities/Repos/BookRepo.php
@@ -6,11 +6,9 @@ use BookStack\Entities\Book;
 use BookStack\Entities\Managers\TrashCan;
 use BookStack\Exceptions\ImageUploadException;
 use BookStack\Exceptions\NotFoundException;
-use BookStack\Exceptions\NotifyException;
 use BookStack\Facades\Activity;
 use BookStack\Uploads\ImageRepo;
 use Exception;
-use Illuminate\Contracts\Container\BindingResolutionException;
 use Illuminate\Contracts\Pagination\LengthAwarePaginator;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Support\Collection;
@@ -24,7 +22,6 @@ class BookRepo
 
     /**
      * BookRepo constructor.
-     * @param $tagRepo
      */
     public function __construct(BaseRepo $baseRepo, TagRepo $tagRepo, ImageRepo $imageRepo)
     {
diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php
index 7cd333ff3..039278228 100644
--- a/app/Entities/Repos/BookshelfRepo.php
+++ b/app/Entities/Repos/BookshelfRepo.php
@@ -18,7 +18,6 @@ class BookshelfRepo
 
     /**
      * BookshelfRepo constructor.
-     * @param $baseRepo
      */
     public function __construct(BaseRepo $baseRepo)
     {
diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php
index 6b593d85e..0e5b48482 100644
--- a/app/Entities/Repos/PageRepo.php
+++ b/app/Entities/Repos/PageRepo.php
@@ -11,7 +11,6 @@ use BookStack\Entities\Page;
 use BookStack\Entities\PageRevision;
 use BookStack\Exceptions\MoveOperationException;
 use BookStack\Exceptions\NotFoundException;
-use BookStack\Exceptions\NotifyException;
 use BookStack\Exceptions\PermissionsException;
 use BookStack\Facades\Activity;
 use Exception;
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index f41815399..c9bf4f36b 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -13,7 +13,6 @@ use Illuminate\Support\Facades\View;
 use Illuminate\Support\ServiceProvider;
 use Schema;
 use URL;
-use Validator;
 
 class AppServiceProvider extends ServiceProvider
 {
@@ -32,37 +31,11 @@ class AppServiceProvider extends ServiceProvider
             URL::forceScheme($isHttps ? 'https' : 'http');
         }
 
-        // Custom validation methods
-        Validator::extend('image_extension', function ($attribute, $value, $parameters, $validator) {
-            $validImageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'webp'];
-            return in_array(strtolower($value->getClientOriginalExtension()), $validImageExtensions);
-        });
-
-        Validator::extend('no_double_extension', function ($attribute, $value, $parameters, $validator) {
-            $uploadName = $value->getClientOriginalName();
-            return substr_count($uploadName, '.') < 2;
-        });
-
-        Validator::extend('safe_url', function ($attribute, $value, $parameters, $validator) {
-            $cleanLinkName = strtolower(trim($value));
-            $isJs = strpos($cleanLinkName, 'javascript:') === 0;
-            $isData = strpos($cleanLinkName, 'data:') === 0;
-            return !$isJs && !$isData;
-        });
-
         // Custom blade view directives
         Blade::directive('icon', function ($expression) {
             return "<?php echo icon($expression); ?>";
         });
 
-        Blade::directive('exposeTranslations', function ($expression) {
-            return "<?php \$__env->startPush('translations'); ?>" .
-                "<?php foreach({$expression} as \$key): ?>" .
-                '<meta name="translation" key="<?php echo e($key); ?>" value="<?php echo e(trans($key)); ?>">' . "\n" .
-                "<?php endforeach; ?>" .
-                '<?php $__env->stopPush(); ?>';
-        });
-
         // Allow longer string lengths after upgrade to utf8mb4
         Schema::defaultStringLength(191);
 
diff --git a/app/Providers/CustomValidationServiceProvider.php b/app/Providers/CustomValidationServiceProvider.php
new file mode 100644
index 000000000..4a5272b40
--- /dev/null
+++ b/app/Providers/CustomValidationServiceProvider.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace BookStack\Providers;
+
+use Illuminate\Support\Facades\Validator;
+use Illuminate\Support\ServiceProvider;
+
+class CustomValidationServiceProvider extends ServiceProvider
+{
+
+    /**
+     * Register our custom validation rules when the application boots.
+     */
+    public function boot(): void
+    {
+        Validator::extend('image_extension', function ($attribute, $value, $parameters, $validator) {
+            $validImageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'webp'];
+            return in_array(strtolower($value->getClientOriginalExtension()), $validImageExtensions);
+        });
+
+        Validator::extend('no_double_extension', function ($attribute, $value, $parameters, $validator) {
+            $uploadName = $value->getClientOriginalName();
+            return substr_count($uploadName, '.') < 2;
+        });
+
+        Validator::extend('safe_url', function ($attribute, $value, $parameters, $validator) {
+            $cleanLinkName = strtolower(trim($value));
+            $isJs = strpos($cleanLinkName, 'javascript:') === 0;
+            $isData = strpos($cleanLinkName, 'data:') === 0;
+            return !$isJs && !$isData;
+        });
+    }
+}
diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js
index 19d26d4a9..bd107f2bf 100644
--- a/resources/js/components/markdown-editor.js
+++ b/resources/js/components/markdown-editor.js
@@ -13,6 +13,7 @@ class MarkdownEditor {
 
         this.pageId = this.$opts.pageId;
         this.textDirection = this.$opts.textDirection;
+        this.imageUploadErrorText = this.$opts.imageUploadErrorText;
 
         this.markdown = new MarkdownIt({html: true});
         this.markdown.use(mdTasksLists, {label: true});
@@ -373,7 +374,7 @@ class MarkdownEditor {
                 const newContent = `[![${selectedText}](${resp.data.thumbs.display})](${resp.data.url})`;
                 replaceContent(placeHolderText, newContent);
             }).catch(err => {
-                window.$events.emit('error', trans('errors.image_upload_error'));
+                window.$events.emit('error', context.imageUploadErrorText);
                 replaceContent(placeHolderText, selectedText);
                 console.log(err);
             });
@@ -492,7 +493,7 @@ class MarkdownEditor {
                 this.cm.focus();
                 DrawIO.close();
             }).catch(err => {
-                window.$events.emit('error', trans('errors.image_upload_error'));
+                window.$events.emit('error', this.imageUploadErrorText);
                 console.log(err);
             });
         });
diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js
index a32e78161..bae70ad14 100644
--- a/resources/js/components/wysiwyg-editor.js
+++ b/resources/js/components/wysiwyg-editor.js
@@ -38,7 +38,7 @@ function editorPaste(event, editor, wysiwygComponent) {
                 editor.dom.replace(newEl, id);
             }).catch(err => {
                 editor.dom.remove(id);
-                window.$events.emit('error', trans('errors.image_upload_error'));
+                window.$events.emit('error', wysiwygComponent.imageUploadErrorText);
                 console.log(err);
             });
         }, 10);
@@ -236,7 +236,7 @@ function codePlugin() {
     });
 }
 
-function drawIoPlugin(drawioUrl, isDarkMode, pageId) {
+function drawIoPlugin(drawioUrl, isDarkMode, pageId, wysiwygComponent) {
 
     let pageEditor = null;
     let currentNode = null;
@@ -280,7 +280,7 @@ function drawIoPlugin(drawioUrl, isDarkMode, pageId) {
                 pageEditor.dom.setAttrib(imgElem, 'src', img.url);
                 pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', img.id);
             } catch (err) {
-                window.$events.emit('error', trans('errors.image_upload_error'));
+                window.$events.emit('error', wysiwygComponent.imageUploadErrorText);
                 console.log(err);
             }
             return;
@@ -295,7 +295,7 @@ function drawIoPlugin(drawioUrl, isDarkMode, pageId) {
                 pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', img.id);
             } catch (err) {
                 pageEditor.dom.remove(id);
-                window.$events.emit('error', trans('errors.image_upload_error'));
+                window.$events.emit('error', wysiwygComponent.imageUploadErrorText);
                 console.log(err);
             }
         }, 5);
@@ -414,12 +414,12 @@ function listenForBookStackEditorEvents(editor) {
 
 class WysiwygEditor {
 
-
     setup() {
         this.elem = this.$el;
 
         this.pageId = this.$opts.pageId;
         this.textDirection = this.$opts.textDirection;
+        this.imageUploadErrorText = this.$opts.imageUploadErrorText;
         this.isDarkMode = document.documentElement.classList.contains('dark-mode');
 
         this.plugins = "image table textcolor paste link autolink fullscreen code customhr autosave lists codeeditor media";
@@ -437,7 +437,7 @@ class WysiwygEditor {
         const drawioUrlElem = document.querySelector('[drawio-url]');
         if (drawioUrlElem) {
             const url = drawioUrlElem.getAttribute('drawio-url');
-            drawIoPlugin(url, this.isDarkMode, this.pageId);
+            drawIoPlugin(url, this.isDarkMode, this.pageId, this);
             this.plugins += ' drawio';
         }
 
diff --git a/resources/views/pages/markdown-editor.blade.php b/resources/views/pages/markdown-editor.blade.php
index 6c1437ec1..a9d1f1174 100644
--- a/resources/views/pages/markdown-editor.blade.php
+++ b/resources/views/pages/markdown-editor.blade.php
@@ -1,10 +1,8 @@
 <div id="markdown-editor" component="markdown-editor"
      option:markdown-editor:page-id="{{ $model->id ?? 0 }}"
      option:markdown-editor:text-direction="{{ config('app.rtl') ? 'rtl' : 'ltr' }}"
+     option:markdown-editor:image-upload-error-text="{{ trans('errors.image_upload_error') }}"
      class="flex-fill flex code-fill">
-    @exposeTranslations([
-        'errors.image_upload_error',
-    ])
 
     <div class="markdown-editor-wrap active">
         <div class="editor-toolbar">
diff --git a/resources/views/pages/wysiwyg-editor.blade.php b/resources/views/pages/wysiwyg-editor.blade.php
index 3bc85caa9..d8b8b1c35 100644
--- a/resources/views/pages/wysiwyg-editor.blade.php
+++ b/resources/views/pages/wysiwyg-editor.blade.php
@@ -1,12 +1,9 @@
 <div component="wysiwyg-editor"
      option:wysiwyg-editor:page-id="{{ $model->id ?? 0 }}"
      option:wysiwyg-editor:text-direction="{{ config('app.rtl') ? 'rtl' : 'ltr' }}"
+     option:wysiwyg-editor:image-upload-error-text="{{ trans('errors.image_upload_error') }}"
      class="flex-fill flex">
 
-    @exposeTranslations([
-        'errors.image_upload_error',
-    ])
-
     <textarea id="html-editor"  name="html" rows="5"
           @if($errors->has('html')) class="text-neg" @endif>@if(isset($model) || old('html')){{ old('html') ? old('html') : $model->html }}@endif</textarea>
 </div>