diff --git a/css/osticket.css b/css/osticket.css
index 37cdb26f2846ac6df03cc266bc7b32f0a2785cd6..0d6d887324cc95c93ba4c7ec896d932e512a183d 100644
--- a/css/osticket.css
+++ b/css/osticket.css
@@ -77,6 +77,9 @@ input.dp {
     border-radius: 3px;
     text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
     line-height: 14px;
+    position: absolute;
+    top: 3em;
+    right: 0.5em;
 }
 
 .delete-draft:hover {
diff --git a/css/rtl.css b/css/rtl.css
index a9a3e7cb04a7926d198e9402cb2cc6ca372e6fc8..b784117a74cc7cabc839483a06b252bd0892b7a1 100644
--- a/css/rtl.css
+++ b/css/rtl.css
@@ -65,3 +65,7 @@
 .rtl .flush-left {
     text-align: right;
 }
+.rtl .draft-saved {
+    right: initial;
+    left: 0.5em;
+}
diff --git a/include/ajax.config.php b/include/ajax.config.php
index 1cff41842b82d4d8c7c08fde9a4222561810c7e2..733fa014d2c18af5e09d92c5b3ba497561f1b8ca 100644
--- a/include/ajax.config.php
+++ b/include/ajax.config.php
@@ -25,12 +25,19 @@ class ConfigAjaxAPI extends AjaxController {
         $lang = Internationalization::getCurrentLanguage();
         list($sl, $locale) = explode('_', $lang);
 
+        $rtl = false;
+        foreach (Internationalization::availableLanguages() as $info) {
+            if (isset($info['direction']))
+                $rtl = true;
+        }
+
         $config=array(
               'lock_time'       => ($cfg->getLockTime()*3600),
               'html_thread'     => (bool) $cfg->isHtmlThreadEnabled(),
               'date_format'     => ($cfg->getDateFormat()),
               'lang'            => $lang,
               'short_lang'      => $sl,
+              'has_rtl'         => $rtl,
         );
         return $this->json_encode($config);
     }
@@ -41,10 +48,17 @@ class ConfigAjaxAPI extends AjaxController {
         $lang = Internationalization::getCurrentLanguage();
         list($sl, $locale) = explode('_', $lang);
 
+        $rtl = false;
+        foreach (Internationalization::availableLanguages() as $info) {
+            if (isset($info['direction']))
+                $rtl = true;
+        }
+
         $config=array(
             'html_thread'     => (bool) $cfg->isHtmlThreadEnabled(),
             'lang'            => $lang,
             'short_lang'      => $sl,
+            'has_rtl'         => $rtl,
         );
 
         $config = $this->json_encode($config);
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index c0d0ec7c4a60cec6dbf086d111fee3ac15a9cb0c..4cb8b22ca788748a2e928abbafbd2308cbbf5fb5 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -41,6 +41,7 @@ if (($lang = Internationalization::getCurrentLanguage())
     <script src="<?php echo ROOT_PATH; ?>scp/js/bootstrap-typeahead.js"></script>
     <script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/redactor.min.js"></script>
     <script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/redactor-osticket.js"></script>
+    <script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/redactor-fonts.js"></script>
     <?php
     if($ost && ($headers=$ost->getExtraHeaders())) {
         echo "\n\t".implode("\n\t", $headers)."\n";
diff --git a/include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php b/include/upgrader/streams/core/03ff59bf-b26f29a6.task.php
similarity index 100%
rename from include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php
rename to include/upgrader/streams/core/03ff59bf-b26f29a6.task.php
diff --git a/js/osticket.js b/js/osticket.js
index 684c71cdf9d3c8e4db9e851aacb86f7643027172..f96c0595904966804fdb3f48d64b8da55349c718 100644
--- a/js/osticket.js
+++ b/js/osticket.js
@@ -218,3 +218,5 @@ function __(s) {
     return $.oststrings[s];
   return s;
 }
+
+$.clientPortal = true;
diff --git a/js/redactor-fonts.js b/js/redactor-fonts.js
index 28cbf34957a0a063cfaeb5c7af0d795419987567..a052e57ec8a00c1389c5849ea8f501f4a4bda73a 100644
--- a/js/redactor-fonts.js
+++ b/js/redactor-fonts.js
@@ -120,7 +120,7 @@ RedactorPlugins.fontsize = {
                 callback: function() { that.setFontsize(s); } };
 		});
 
-		dropdown['remove'] = { title: 'Remove font size', callback: function() { that.resetFontsize(); } };
+		dropdown['remove'] = { title: __('Remove font size'), callback: function() { that.resetFontsize(); } };
 
 		this.buttonAddAfter('formatting', 'fontsize', __('Change font size'), false, dropdown);
 	},
@@ -133,3 +133,40 @@ RedactorPlugins.fontsize = {
 		this.inlineRemoveStyle('font-size');
 	}
 };
+
+RedactorPlugins.textdirection = {
+    init: function()
+    {
+        var that = this;
+        var dropdown = {};
+
+        dropdown.ltr = { title: __('Left to Right'), callback: this.setLtr };
+        dropdown.rtl = { title: __('Right to Left'), callback: this.setRtl };
+
+        var button = this.buttonAdd('textdirection', __('Change Text Direction'),
+            false, dropdown);
+    },
+    setRtl: function()
+    {
+        if (!this.opts.linebreaks) {
+            this.bufferSet();
+            this.blockSetAttr('dir', 'rtl');
+        }
+        else {
+            this.$editor.attr('dir', 'rtl');
+        }
+        this.$box.removeClass('ltr').addClass('rtl');
+
+    },
+    setLtr: function()
+    {
+        if (!this.opts.linebreaks) {
+            this.bufferSet();
+            this.blockSetAttr('dir', 'ltr');
+        }
+        else {
+            this.$editor.attr('dir', 'ltr');
+        }
+        this.$box.removeClass('rtl').addClass('ltr');
+    }
+};
diff --git a/js/redactor-osticket.js b/js/redactor-osticket.js
index 0cf266156a1471c7036e63ab89cbece9fcf231c1..810fa7f9e98945d6252112e40ad2fe699debe6ed 100644
--- a/js/redactor-osticket.js
+++ b/js/redactor-osticket.js
@@ -28,7 +28,6 @@ RedactorPlugins.draft = {
 
         this.$draft_saved = $('<span>')
             .addClass("pull-right draft-saved")
-            .css({'position':'absolute','top':'3em','right':'0.5em'})
             .hide()
             .append($('<span>')
                 .text(__('Draft Saved')));
@@ -226,7 +225,7 @@ $(function() {
                 'autoresize': !el.hasClass('no-bar'),
                 'minHeight': el.hasClass('small') ? 75 : 150,
                 'focus': false,
-                'plugins': ['fontcolor','fontfamily', 'signature'],
+                'plugins': [],
                 'imageGetJson': 'ajax.php/draft/images/browse',
                 'syncBeforeCallback': captureImageSizes,
                 'linebreaks': true,
@@ -253,6 +252,10 @@ $(function() {
             // the image was inserted.
             el.redactor('sync');
         });
+        if (!$.clientPortal) {
+            options['plugins'] = options['plugins'].concat(
+                    'fontcolor', 'fontfamily', 'signature');
+        }
         if (el.hasClass('draft')) {
             el.closest('form').append($('<input type="hidden" name="draft_id"/>'));
             options['plugins'].push('draft');
@@ -262,6 +265,10 @@ $(function() {
             if (c.lang && c.lang.toLowerCase() != 'en_us' &&
                     $.Redactor.opts.langs[c.short_lang])
                 options['lang'] = c.short_lang;
+            if (c.has_rtl)
+                options['plugins'].push('textdirection');
+            if ($('html.rtl').length)
+                options['direction'] = 'rtl';
             el.redactor(options);
         });
     },
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 5e3579d5ee8d48e692522b76ed039b0d09a132ae..0dc2092a119c3d89d5e0625067459cd22fd75abe 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1925,6 +1925,9 @@ table.custom-info td {
     border-radius: 3px;
     text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
     line-height: 14px;
+    position: absolute;
+    top: 3em;
+    right: 0.5em;
 }
 
 .delete-draft:hover {