diff --git a/account.php b/account.php
index 295073f881172d251c46a29d5e10300b0a19204f..255ac77610a266b29cd71371599e585ed2d91cbf 100644
--- a/account.php
+++ b/account.php
@@ -59,35 +59,36 @@ elseif ($_POST) {
     }
 
     if (!$user_form->isValid(function($f) { return !$f->get('private'); }))
-        $errors['err'] = 'Incomplete client information';
+        $errors['err'] = __('Incomplete client information');
     elseif (!$_POST['backend'] && !$_POST['passwd1'])
-        $errors['passwd1'] = 'New password required';
+        $errors['passwd1'] = __('New password is required');
     elseif (!$_POST['backend'] && $_POST['passwd2'] != $_POST['passwd1'])
-        $errors['passwd1'] = 'Passwords do not match';
+        $errors['passwd1'] = __('Passwords do not match');
 
     // XXX: The email will always be in use already if a guest is logged in
     // and is registering for an account. Instead,
     elseif (($addr = $user_form->getField('email')->getClean())
             && ClientAccount::lookupByUsername($addr)) {
         $user_form->getField('email')->addError(
-            'Email already registered. Would you like to <a href="login.php?e='
-            .urlencode($addr).'" style="color:inherit"><strong>sign in</strong></a>?');
-        $errors['err'] = 'Unable to register account. See messages below';
+            sprintf(__('Email already registered. Would you like to %1$s sign in %2$s?'),
+            '<a href="login.php?e='.urlencode($addr).'" style="color:inherit"><strong>',
+            '</strong></a>');
+        $errors['err'] = __('Unable to register account. See messages below');
     }
     // Users created from ClientCreateRequest
     elseif (isset($_POST['backend']) && !($user = User::fromVars($user_form->getClean())))
-        $errors['err'] = 'Unable to create local account. See messages below';
+        $errors['err'] = __('Unable to create local account. See messages below');
     // Registration for existing users
     elseif (!$user && !$thisclient && !($user = User::fromVars($user_form->getClean())))
-        $errors['err'] = 'Unable to register account. See messages below';
+        $errors['err'] = __('Unable to register account. See messages below');
     // New users and users registering from a ticket access link
     elseif (!$user && !($user = $thisclient ?: User::fromForm($user_form)))
-        $errors['err'] = 'Unable to register account. See messages below';
+        $errors['err'] = __('Unable to register account. See messages below');
     else {
         if (!($acct = ClientAccount::createForUser($user)))
-            $errors['err'] = 'Internal error. Unable to create new account';
+            $errors['err'] = __('Internal error. Unable to create new account');
         elseif (!$acct->update($_POST, $errors))
-            $errors['err'] = 'Errors configuring your profile. See messages below';
+            $errors['err'] = __('Errors configuring your profile. See messages below');
     }
 
     if (!$errors) {
diff --git a/api/cron.php b/api/cron.php
index 787460ee7c3042ee36a46ec39e8060fc73f5beaf..8f47ed3dd72e477ca6a752960ec831261b4f44fa 100644
--- a/api/cron.php
+++ b/api/cron.php
@@ -17,7 +17,7 @@
 require('api.inc.php');
 
 if (!osTicket::is_cli())
-    die('cron.php only supports local cron calls - use http -> api/tasks/cron');
+    die(__('cron.php only supports local cron calls - use http -> api/tasks/cron'));
 
 require_once(INCLUDE_DIR.'api.cron.php');
 LocalCronApiController::call();
diff --git a/api/pipe.php b/api/pipe.php
index 249cfc8a79ffef59dee8295b7feb2e8ffd94f4f2..dfaaeea7c5afcb70ca4355a2725c4d6e0383de14 100644
--- a/api/pipe.php
+++ b/api/pipe.php
@@ -20,7 +20,7 @@ require('api.inc.php');
 
 //Only local piping supported via pipe.php
 if (!osTicket::is_cli())
-    die('pipe.php only supports local piping - use http -> api/tickets.email');
+    die(__('pipe.php only supports local piping - use http -> api/tickets.email'));
 
 require_once(INCLUDE_DIR.'api.tickets.php');
 PipeApiController::process();
diff --git a/attachment.php b/attachment.php
index a2760717f17983ce4f40d11cc5a88d7984e1b85b..0b18dbf8df46f7ddbc772c2c2a2a245ccc91a2e0 100644
--- a/attachment.php
+++ b/attachment.php
@@ -22,7 +22,7 @@ if(!$thisclient
         || !$_GET['h']
         || !($attachment=Attachment::lookup($_GET['id']))
         || !($file=$attachment->getFile()))
-    die(__('Unknown attachment!'));
+    die(__('Unknown or invalid attachment'));
 
 //Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!!
 $vhash=md5($attachment->getFileId().session_id().strtolower($file->getKey()));
diff --git a/bootstrap.php b/bootstrap.php
index 986844c41821fec62b6e7b7bbd298504c6da7e54..8e11f0e9818b0c88b16939dda14f955c172b9690 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -134,13 +134,12 @@ class Bootstrap {
             //Die gracefully on upgraded v1.6 RC5 installation - otherwise script dies with confusing message.
             if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']), 'settings.php'))
                 Http::response(500,
-                    'Please rename config file include/settings.php to '
-                   .'include/ost-config.php to continue!');
+                    _S('Please rename config file include/settings.php to include/ost-config.php to continue!'));
         } elseif(file_exists(ROOT_DIR.'setup/'))
             Http::redirect(ROOT_PATH.'setup/');
 
         if(!$configfile || !file_exists($configfile))
-            Http::response(500,'<b>Error loading settings. Contact admin.</b>');
+            Http::response(500,'<b>'._S('Error loading settings. Contact admin.').'</b>');
 
         require($configfile);
         define('CONFIG_FILE',$configfile); //used in admin.php to check perm.
@@ -165,9 +164,9 @@ class Bootstrap {
             );
 
         if (!db_connect(DBHOST, DBUSER, DBPASS, $options)) {
-            $ferror='Unable to connect to the database -'.db_connect_error();
+            $ferror=sprintf(_S('Unable to connect to the database — %s'),db_connect_error());
         }elseif(!db_select_database(DBNAME)) {
-            $ferror='Unknown or invalid database '.DBNAME;
+            $ferror=sprintf(_S('Unknown or invalid database: %s'),DBNAME);
         }
 
         if($ferror) //Fatal error
@@ -281,11 +280,11 @@ class Bootstrap {
     }
 
     function croak($message) {
-        $msg = $message."\n\n".THISPAGE;
-        Mailer::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg,
-            sprintf('"osTicket Alerts"<%s>', ADMIN_EMAIL));
+        $msg = _S($message)."\n\n".THISPAGE;
+        Mailer::sendmail(ADMIN_EMAIL, _S('osTicket Fatal Error'), $msg,
+            '"'._S('osTicket Alerts').sprintf('" <%s>', ADMIN_EMAIL));
         //Display generic error to the user
-        Http::response(500, "<b>Fatal Error:</b> Contact system administrator.");
+        Http::response(500, _S("<b>Fatal Error:</b> Contact system administrator."));
     }
 }
 
diff --git a/client.inc.php b/client.inc.php
index ad4c7ee4e18c12841a46ac239fd0a7b90bd3e597..856943c0be6cacd65d5adb9ce52db9ebc614a168 100644
--- a/client.inc.php
+++ b/client.inc.php
@@ -73,7 +73,7 @@ $exempt = in_array(basename($_SERVER['SCRIPT_NAME']), array('logout.php', 'ajax.
 
 if (!$exempt && $thisclient && ($acct = $thisclient->getAccount())
         && $acct->isPasswdResetForced()) {
-    $warn = 'Password change required to continue';
+    $warn = __('Password change required to continue');
     require('profile.php'); //profile.php must request this file as require_once to avoid problems.
     exit;
 }
diff --git a/image.php b/image.php
index 405c87c9f6de2df262738aded389343189285331..5b7f27283ba23175ff12772f4212a41859ea3e18 100644
--- a/image.php
+++ b/image.php
@@ -25,7 +25,7 @@ $h=trim($_GET['h']);
 if(!$h  || strlen($h)!=64  //32*2
         || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
         || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    Http::response(404, 'Unknown or invalid file');
+    Http::response(404, __('Unknown or invalid file'));
 
 $file->display();
 ?>
diff --git a/include/ajax.draft.php b/include/ajax.draft.php
index 34679a7e8d6075a40ac24ee29c7581d382caa69a..e24be81efc5ef46f44527bbb2333bf7cdb3a859f 100644
--- a/include/ajax.draft.php
+++ b/include/ajax.draft.php
@@ -265,11 +265,11 @@ class DraftAjaxAPI extends AjaxController {
 
         $files = array();
         $folders = array(
-            'C' => 'Canned Responses',
-            'F' => 'FAQ Articles',
-            'T' => 'Email Templates',
-            'L' => 'Logos',
-            'P' => 'Pages',
+            'C' => __('Canned Responses'),
+            'F' => __('FAQ Articles'),
+            'T' => __('Email Templates'),
+            'L' => __('Logos'),
+            'P' => __('Pages'),
         );
         while (list($id, $type) = db_fetch_row($res)) {
             $f = AttachmentFile::lookup($id);
diff --git a/include/class.auth.php b/include/class.auth.php
index fb5bcb8d94ff00c4bdeab101414515e76c18c2cc..ba925088b889d73c660058e50cae3839835b929f 100644
--- a/include/class.auth.php
+++ b/include/class.auth.php
@@ -221,7 +221,7 @@ abstract class AuthenticationBackend {
         }
 
         if (!$result)
-            $result = new AccessDenied('Access denied');
+            $result = new AccessDenied(__('Access denied'));
 
         if ($result && $result instanceof AccessDenied)
             $errors['err'] = $result->reason;
@@ -266,7 +266,7 @@ abstract class AuthenticationBackend {
         }
 
         if (!$result && $forcedAuth)
-            $result = new  AccessDenied('Unknown user');
+            $result = new  AccessDenied(__('Unknown user'));
 
         if ($result && $result instanceof AccessDenied)
             $errors['err'] = $result->reason;
@@ -423,8 +423,8 @@ abstract class StaffAuthenticationBackend  extends AuthenticationBackend {
             return false;
 
         //Log debug info.
-        $ost->logDebug('Staff login',
-            sprintf("%s logged in [%s], via %s", $staff->getUserName(),
+        $ost->logDebug(_S('Staff login'),
+            sprintf(_S("%s logged in [%s], via %s"), $staff->getUserName(),
                 $_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug.
 
         $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() '
@@ -466,8 +466,8 @@ abstract class StaffAuthenticationBackend  extends AuthenticationBackend {
 
         $_SESSION['_auth']['staff'] = array();
         unset($_SESSION[':token']['staff']);
-        $ost->logDebug('Staff logout',
-                sprintf("%s logged out [%s]",
+        $ost->logDebug(_S('Staff logout'),
+                sprintf(_S("%s logged out [%s]"),
                     $staff->getUserName(),
                     $_SERVER['REMOTE_ADDR'])); //Debug.
 
@@ -600,9 +600,9 @@ abstract class UserAuthenticationBackend  extends AuthenticationBackend {
 
         if ($acct) {
             if (!$acct->isConfirmed())
-                throw new AccessDenied('Account confirmation required');
+                throw new AccessDenied(__('Account confirmation required'));
             elseif ($acct->isLocked())
-                throw new AccessDenied('Account is administratively locked');
+                throw new AccessDenied(__('Account is administratively locked'));
         }
 
         // Tag the user and associated ticket in the SESSION
@@ -620,9 +620,10 @@ abstract class UserAuthenticationBackend  extends AuthenticationBackend {
         }
 
         //Log login info...
-        $msg=sprintf('%s (%s) logged in [%s]',
+        $msg=sprintf(_S('%1$s (%2$s) logged in [%3$s]'
+                /* Tokens are <username>, <id>, and <ip> */),
                 $user->getUserName(), $user->getId(), $_SERVER['REMOTE_ADDR']);
-        $ost->logDebug('User login', $msg);
+        $ost->logDebug(_S('User login'), $msg);
 
         if ($bk->supportsInteractiveAuthentication() && ($acct=$user->getAccount()))
             $acct->cancelResetTokens();
@@ -653,9 +654,9 @@ abstract class UserAuthenticationBackend  extends AuthenticationBackend {
 
         $_SESSION['_auth']['user'] = array();
         unset($_SESSION[':token']['client']);
-        $ost->logDebug('User logout',
-                sprintf("%s logged out [%s]",
-                    $user->getUserName(), $_SERVER['REMOTE_ADDR']));
+        $ost->logDebug(_S('User logout'),
+            sprintf(_S("%s logged out [%s]" /* Tokens are <username> and <ip> */),
+                $user->getUserName(), $_SERVER['REMOTE_ADDR']));
     }
 
     protected function getAuthKey($user) {
@@ -701,18 +702,18 @@ abstract class ExternalUserAuthenticationBackend
     static $service_name = "External";
 
     function renderExternalLink() { ?>
-        <a class="external-sign-in" title="Sign in with <?php echo static::$service_name; ?>"
+        <a class="external-sign-in" title="<?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>"
                 href="login.php?do=ext&amp;bk=<?php echo urlencode(static::$id); ?>">
 <?php if (static::$sign_in_image_url) { ?>
         <img class="sign-in-image" src="<?php echo static::$sign_in_image_url;
-            ?>" alt="Sign in with <?php echo static::$service_name; ?>"/>
+            ?>" alt="<?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>"/>
 <?php } else { ?>
             <div class="external-auth-box">
             <span class="external-auth-icon">
                 <i class="icon-<?php echo static::$fa_icon; ?> icon-large icon-fixed-with"></i>
             </span>
             <span class="external-auth-name">
-                Sign in with <?php echo static::$service_name; ?>
+                <?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>
             </span>
             </div>
 <?php } ?>
@@ -803,7 +804,7 @@ class StaffAuthStrikeBackend extends  AuthStrikeBackend {
         //Veto login due to excessive login attempts.
         if((time()-$authsession['laststrike'])<$cfg->getStaffLoginTimeout()) {
             $authsession['laststrike'] = time(); //reset timer.
-            return new AccessDenied('Max. failed login attempts reached');
+            return new AccessDenied(__('Maximum failed login attempts reached'));
         }
 
         //Timeout is over.
@@ -824,22 +825,24 @@ class StaffAuthStrikeBackend extends  AuthStrikeBackend {
         $authsession['strikes']+=1;
         if($authsession['strikes']>$cfg->getStaffMaxLogins()) {
             $authsession['laststrike']=time();
-            $alert='Excessive login attempts by a staff member?'."\n".
-                   'Username: '.$username."\n"
-                   .'IP: '.$_SERVER['REMOTE_ADDR']."\n"
-                   .'TIME: '.date('M j, Y, g:i a T')."\n\n"
-                   .'Attempts #'.$authsession['strikes']."\n"
-                   .'Timeout: '.($cfg->getStaffLoginTimeout()/60)." minutes \n\n";
-            $ost->logWarning('Excessive login attempts ('.$username.')', $alert,
-                    $cfg->alertONLoginError());
-            return new AccessDenied('Forgot your login info? Contact Admin.');
+            $timeout = $cfg->getStaffLoginTimeout()/60;
+            $alert=_S('Excessive login attempts by a staff member?')."\n"
+                   ._S('Username').": $username\n"
+                   ._S('IP').": {$_SERVER['REMOTE_ADDR']}\n"
+                   ._S('Time').": ".date('M j, Y, g:i a T')."\n\n"
+                   ._S('Attempts').": {$authsession['strikes']}\n"
+                   ._S('Timeout').": ".sprintf(_N('%d minute', '%d minutes', $timeout), $timeout)."\n\n";
+            $ost->logWarning(sprintf(_S('Excessive login attempts (%s)'),$username),
+                    $alert, $cfg->alertONLoginError());
+            return new AccessDenied(__('Forgot your login info? Contact Admin.'));
         //Log every other third failed login attempt as a warning.
         } elseif($authsession['strikes']%3==0) {
-            $alert='Username: '.$username."\n"
-                    .'IP: '.$_SERVER['REMOTE_ADDR']."\n"
-                    .'TIME: '.date('M j, Y, g:i a T')."\n\n"
-                    .'Attempts #'.$authsession['strikes'];
-            $ost->logWarning('Failed staff login attempt ('.$username.')', $alert, false);
+            $alert=_S('Username').": {$username}\n"
+                    ._S('IP').": {$_SERVER['REMOTE_ADDR']}\n"
+                    ._S('Time').": ".date('M j, Y, g:i a T')."\n\n"
+                    ._S('Attempts').": {$authsession['strikes']}";
+            $ost->logWarning(sprintf(_S('Failed staff login attempt (%s)'),$username),
+                $alert, false);
         }
     }
 }
@@ -862,7 +865,7 @@ class UserAuthStrikeBackend extends  AuthStrikeBackend {
         //Veto login due to excessive login attempts.
         if ((time()-$authsession['laststrike']) < $cfg->getStaffLoginTimeout()) {
             $authsession['laststrike'] = time(); //reset timer.
-            return new AccessDenied("You've reached maximum failed login attempts allowed.");
+            return new AccessDenied(__("You've reached maximum failed login attempts allowed."));
         }
 
         //Timeout is over.
@@ -884,16 +887,19 @@ class UserAuthStrikeBackend extends  AuthStrikeBackend {
         $authsession['strikes']+=1;
         if($authsession['strikes']>$cfg->getClientMaxLogins()) {
             $authsession['laststrike'] = time();
-            $alert='Excessive login attempts by a user.'."\n".
-                    'Username: '.$username."\n".
-                    'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
-                    'Attempts #'.$authsession['strikes'];
-            $ost->logError('Excessive login attempts (user)', $alert, ($cfg->alertONLoginError()));
-            return new AccessDenied('Access Denied');
+            $alert=_S('Excessive login attempts by a user.')."\n".
+                    _S('Username').": {$username}\n".
+                    _S('IP').": {$_SERVER['REMOTE_ADDR']}\n".
+                    _S('Time').": ".date('M j, Y, g:i a T')."\n\n".
+                    _S('Attempts').": {$authsession['strikes']}";
+            $ost->logError(_S('Excessive login attempts (user)'), $alert, ($cfg->alertONLoginError()));
+            return new AccessDenied(__('Access Denied'));
         } elseif($authsession['strikes']%3==0) { //Log every third failed login attempt as a warning.
-            $alert='Username: '.$username."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
-                   "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$authsession['strikes'];
-            $ost->logWarning('Failed login attempt (user)', $alert);
+            $alert=_S('Username').": {$username}\n".
+                    _S('IP').": {$_SERVER['REMOTE_ADDR']}\n".
+                    _S('Time').": ".date('M j, Y, g:i a T')."\n\n".
+                    _S('Attempts').": {$authsession['strikes']}";
+            $ost->logWarning(_S('Failed login attempt (user)'), $alert);
         }
 
     }
@@ -939,15 +945,15 @@ class PasswordResetTokenBackend extends StaffAuthenticationBackend {
             return false;
         elseif (($staff = new StaffSession($_POST['userid'])) &&
                 !$staff->getId())
-            $errors['msg'] = 'Invalid user-id given';
+            $errors['msg'] = __('Invalid user-id given');
         elseif (!($id = $_config->get($_POST['token']))
                 || $id != $staff->getId())
-            $errors['msg'] = 'Invalid reset token';
+            $errors['msg'] = __('Invalid reset token');
         elseif (!($ts = $_config->lastModified($_POST['token']))
                 && ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
-            $errors['msg'] = 'Invalid reset token';
+            $errors['msg'] = __('Invalid reset token');
         elseif (!$staff->forcePasswdRest())
-            $errors['msg'] = 'Unable to reset password';
+            $errors['msg'] = __('Unable to reset password');
         else
             return $staff;
     }
@@ -1152,15 +1158,15 @@ class ClientPasswordResetTokenBackend extends UserAuthenticationBackend {
         elseif (!($acct = ClientAccount::lookupByUsername($_POST['userid']))
                 || !$acct->getId()
                 || !($client = new ClientSession(new EndUser($acct->getUser()))))
-            $errors['msg'] = 'Invalid user-id given';
+            $errors['msg'] = __('Invalid user-id given');
         elseif (!($id = $_config->get($_POST['token']))
                 || $id != $client->getId())
-            $errors['msg'] = 'Invalid reset token';
+            $errors['msg'] = __('Invalid reset token');
         elseif (!($ts = $_config->lastModified($_POST['token']))
                 && ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
-            $errors['msg'] = 'Invalid reset token';
+            $errors['msg'] = __('Invalid reset token');
         elseif (!$acct->forcePasswdReset())
-            $errors['msg'] = 'Unable to reset password';
+            $errors['msg'] = __('Unable to reset password');
         else
             return $client;
     }
diff --git a/include/class.client.php b/include/class.client.php
index a4cf0b028b7dfdcfdc3faf5bc99d885cc5248205..5e2485ed0f8f0bcef04f2570c43710954f6d6643 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -342,11 +342,11 @@ class ClientAccount extends UserAccount {
         if ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd'] || $rtoken) {
 
             if (!$vars['passwd1'])
-                $errors['passwd1']=__('New password required');
+                $errors['passwd1']=__('New password is required');
             elseif ($vars['passwd1'] && strlen($vars['passwd1'])<6)
-                $errors['passwd1']=__('Must be at least 6 characters');
+                $errors['passwd1']=__('Password must be at least 6 characters');
             elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
-                $errors['passwd2']=__('Password(s) do not match');
+                $errors['passwd2']=__('Passwords do not match');
 
             if ($rtoken) {
                 $_config = new Config('pwreset');
@@ -360,7 +360,7 @@ class ClientAccount extends UserAccount {
             }
             elseif ($this->get('passwd')) {
                 if (!$vars['cpasswd'])
-                    $errors['cpasswd']=__('Current password required');
+                    $errors['cpasswd']=__('Current password is required');
                 elseif (!$this->hasCurrentPassword($vars['cpasswd']))
                     $errors['cpasswd']=__('Invalid current password!');
                 elseif (!strcasecmp($vars['passwd1'], $vars['cpasswd']))
diff --git a/include/class.collaborator.php b/include/class.collaborator.php
index b8adb93262d1dba483457b7decd82b8af7dd6078..b123644a0d85b3276f2a8e3c9403adaaaa9b60f4 100644
--- a/include/class.collaborator.php
+++ b/include/class.collaborator.php
@@ -96,9 +96,9 @@ class Collaborator extends TicketUser {
     static function add($info, &$errors) {
 
         if (!$info || !$info['ticketId'] || !$info['userId'])
-            $errors['err'] = 'Invalid or missing information';
+            $errors['err'] = __('Invalid or missing information');
         elseif (($c=self::lookup($info)))
-            $errors['err'] = sprintf('%s is already a collaborator',
+            $errors['err'] = sprintf(__('%s is already a collaborator'),
                     $c->getName());
 
         if ($errors) return false;
@@ -112,7 +112,7 @@ class Collaborator extends TicketUser {
         if(db_query($sql) && ($id=db_insert_id()))
             return self::lookup($id);
 
-        $errors['err'] = 'Unable to add collaborator. Internal error';
+        $errors['err'] = __('Unable to add collaborator. Internal error');
 
         return false;
     }
diff --git a/include/class.config.php b/include/class.config.php
index f8b60c4d9ecd4a92dc3a3ea364b7e268fefd5098..a8785fc1364ab6996a6307e2cabefcdd65fb7da3 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -444,8 +444,8 @@ class OsticketConfig extends Config {
     function setTopicSortMode($mode) {
         $modes = static::allTopicSortModes();
         if (!isset($modes[$mode]))
-            throw new InvalidArgumentException($mode
-                .': Unsupport help topic sort mode');
+            throw new InvalidArgumentException(sprintf(
+                __('%s: Unsupport help topic sort mode'), $mode));
 
         $this->update('help_topic_sort_mode', $mode);
     }
@@ -904,7 +904,7 @@ class OsticketConfig extends Config {
         $f['staff_session_timeout']=array('type'=>'int',   'required'=>1, 'error'=>'Enter idle time in minutes');
         $f['client_session_timeout']=array('type'=>'int',   'required'=>1, 'error'=>'Enter idle time in minutes');
         $f['pw_reset_window']=array('type'=>'int', 'required'=>1, 'min'=>1,
-            'error'=>'Valid password reset window required');
+            'error'=>__('Valid password reset window required'));
 
 
         if(!Validator::process($f, $vars, $errors) || $errors)
@@ -966,7 +966,7 @@ class OsticketConfig extends Config {
         if ($vars['default_help_topic']
                 && ($T = Topic::lookup($vars['default_help_topic']))
                 && !$T->isActive()) {
-            $errors['default_help_topic'] = 'Default help topic must be set to active';
+            $errors['default_help_topic'] = __('Default help topic must be set to active');
         }
 
         if(!Validator::process($f, $vars, $errors) || $errors)
@@ -1065,7 +1065,7 @@ class OsticketConfig extends Config {
             elseif ($logo['error'])
                 $errors['logo'] = $logo['error'];
             elseif (!($id = AttachmentFile::uploadLogo($logo, $error)))
-                $errors['logo'] = sprintf(_('Unable to upload logo image: %s'), $error);
+                $errors['logo'] = sprintf(__('Unable to upload logo image: %s'), $error);
         }
 
         $company = $ost->company;
diff --git a/include/class.dispatcher.php b/include/class.dispatcher.php
index d586fd0ba77e010549d72196bcaec0a5f94c44d2..3490e78826d62287530f2fc23ba1a1bf4a15b462 100644
--- a/include/class.dispatcher.php
+++ b/include/class.dispatcher.php
@@ -38,7 +38,7 @@ class Dispatcher {
                 return $matcher->dispatch($url, $args);
             }
         }
-        Http::response(400, "URL not supported");
+        Http::response(400, __("URL not supported"));
     }
     /**
      * Returns the url for the given function and arguments (arguments
@@ -140,7 +140,7 @@ class UrlMatcher {
         }
 
         if (!is_callable($func))
-            Http::response(500, 'Dispatcher compile error. Function not callable');
+            Http::response(500, __('Dispatcher compile error. Function not callable'));
 
         return call_user_func_array($func, $args);
     }
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index c0a203646ffd02170cf4c5a1eff44778687722d8..8d0416011dac0f9f38f14236b88f23493cfe431c 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -70,7 +70,7 @@ class DynamicForm extends VerySimpleModel {
     function __call($what, $args) {
         $delegate = array($this->getForm(), $what);
         if (!is_callable($delegate))
-            throw new Exception($what.': Call to non-existing function');
+            throw new Exception(sprintf(__('%s: Call to non-existing function'), $what));
         return call_user_func_array($delegate, $args);
     }
 
@@ -457,10 +457,13 @@ class DynamicFormField extends VerySimpleModel {
             return false;
         if (!$this->get('label'))
             $this->addError(
-                "Label is required for custom form fields", "label");
+                __("Label is required for custom form fields"), "label");
         if ($this->get('required') && !$this->get('name'))
             $this->addError(
-                "Variable name is required for required fields", "name");
+                __("Variable name is required for required fields"
+                /* `required` is a flag on fields */
+                /* `variable` is used for automation. Internally it's called `name` */
+                ), "name");
         return count($this->errors()) == 0;
     }
 
@@ -919,9 +922,9 @@ class DynamicList extends VerySimpleModel {
 
     function getSortModes() {
         return array(
-            'Alpha'     => 'Alphabetical',
-            '-Alpha'    => 'Alphabetical (Reversed)',
-            'SortCol'   => 'Manually Sorted'
+            'Alpha'     => __('Alphabetical'),
+            '-Alpha'    => __('Alphabetical (Reversed)'),
+            'SortCol'   => __('Manually Sorted')
         );
     }
 
@@ -1017,7 +1020,8 @@ class DynamicList extends VerySimpleModel {
         return $selections;
     }
 }
-FormField::addFieldTypes('Custom Lists', array('DynamicList', 'getSelections'));
+FormField::addFieldTypes(/* trans */ 'Custom Lists',
+    array('DynamicList', 'getSelections'));
 
 /**
  * Represents a single item in a dynamic list
@@ -1199,23 +1203,23 @@ class SelectionField extends FormField {
         $config = $this->getConfiguration();
         parent::validateEntry($item);
         if ($item && !$item instanceof DynamicListItem)
-            $this->_errors[] = 'Select a value from the list';
+            $this->_errors[] = __('Select a value from the list');
         elseif ($item && $config['typeahead']
                 && $this->getWidget()->getEnteredValue() != $item->get('value'))
-            $this->_errors[] = 'Select a value from the list';
+            $this->_errors[] = __('Select a value from the list');
     }
 
     function getConfigurationOptions() {
         return array(
             'typeahead' => new ChoiceField(array(
-                'id'=>1, 'label'=>'Widget', 'required'=>false,
+                'id'=>1, 'label'=>__('Widget'), 'required'=>false,
                 'default'=>false,
-                'choices'=>array(false=>'Drop Down', true=>'Typeahead'),
-                'hint'=>'Typeahead will work better for large lists'
+                'choices'=>array(false=>__('Drop Down'), true=>__('Typeahead')),
+                'hint'=>__('Typeahead will work better for large lists')
             )),
             'prompt' => new TextboxField(array(
-                'id'=>2, 'label'=>'Prompt', 'required'=>false, 'default'=>'',
-                'hint'=>'Leading text shown before a value is selected',
+                'id'=>2, 'label'=>__('Prompt'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Leading text shown before a value is selected'),
                 'configuration'=>array('size'=>40, 'length'=>40),
             )),
         );
@@ -1228,7 +1232,8 @@ class SelectionField extends FormField {
                 $this->_choices[$i->get('id')] = $i->get('value');
             if ($this->value && !isset($this->_choices[$this->value])) {
                 $v = DynamicListItem::lookup($this->value);
-                $this->_choices[$v->get('id')] = $v->get('value').' (Disabled)';
+                $this->_choices[$v->get('id')] = $v->get('value')
+                    . mb_convert_encoding(__(' (Disabled)'), MB_CASE_TITLE);
             }
         }
         return $this->_choices;
diff --git a/include/class.email.php b/include/class.email.php
index 699d37a2ed2732f8737f029b7cf7d23dfb3087b7..a6d1a24119307b8f16484a500e916292d91bbbbd 100644
--- a/include/class.email.php
+++ b/include/class.email.php
@@ -273,7 +273,7 @@ class Email {
                     && $vars['userid']
                     && !Crypto::encrypt($vars['passwd'], SECRET_SALT, $vars['userid'])
                     )
-                $errors['passwd'] = 'Unable to encrypt password - get technical support';
+                $errors['passwd'] = __('Unable to encrypt password - get technical support');
         }
 
         list($vars['mail_protocol'], $encryption) = explode('/', $vars['mail_proto']);
diff --git a/include/class.error.php b/include/class.error.php
index 602304f763c5166b75b854c43597a893f6d42220..7e9ecb8a9cc15cc45d422fd7a13d39278af95091 100644
--- a/include/class.error.php
+++ b/include/class.error.php
@@ -24,7 +24,8 @@ class Error extends Exception {
     function __construct($message) {
         global $ost;
 
-        $message = str_replace(ROOT_DIR, '(root)/', $message);
+        parent::__construct(__($message));
+        $message = str_replace(ROOT_DIR, '(root)/', _S($message));
 
         if ($ost->getConfig()->getLogLevel() == 3)
             $message .= "\n\n" . $this->getBacktrace();
@@ -33,7 +34,7 @@ class Error extends Exception {
     }
 
     function getTitle() {
-        return get_class($this) . ': ' . static::$title;
+        return get_class($this) . ': ' . _S(static::$title);
     }
 
     function getBacktrace() {
diff --git a/include/class.export.php b/include/class.export.php
index 662f2433dd964b1acef27b3c67c3bc66cd584c97..048c1fb4de9ebe16f5be6e51d9e36580bed1c606 100644
--- a/include/class.export.php
+++ b/include/class.export.php
@@ -127,9 +127,9 @@ class Export {
         ob_start();
         echo self::dumpQuery($sql,
                 array(
-                    'name'  =>  'Name',
-                    'organization' => 'Organization',
-                    'email' =>  'Email'
+                    'name'  =>          __('Name'),
+                    'organization' =>   __('Organization'),
+                    'email' =>          __('Email'),
                     ) + $cdata,
                 $how,
                 array('modify' => function(&$record, $keys) use ($fields) {
@@ -361,7 +361,7 @@ class DatabaseExporter {
 
             if (!$table) {
                 if ($error_stream) $error_stream->write(
-                    $t.': Cannot export table with no fields'."\n");
+                    sprintf(__("%s: Cannot export table with no fields\n"), $t));
                 die();
             }
             $this->write_block(
diff --git a/include/class.file.php b/include/class.file.php
index a2ce70bfa1a56b33641eda172b40651619e067fb..203ce5534356d1a295fec5cfd131212d17aa74de 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -282,7 +282,7 @@ class AttachmentFile {
                 break;
             default:
                 // TODO: Return an error
-                $error = 'Invalid image file type';
+                $error = __('Invalid image file type');
                 return false;
         }
 
@@ -291,7 +291,7 @@ class AttachmentFile {
         if ($source_aspect_ratio >= $aspect_ratio)
             return self::upload($file, 'L');
 
-        $error = 'Image is too square. Upload a wider image';
+        $error = __('Image is too square. Upload a wider image');
         return false;
     }
 
diff --git a/include/class.filter.php b/include/class.filter.php
index 656a5cf559ac7050c794a10b9349e338c42f734d..1b209bf708c90262f91480b71ca9bbe12f8dbe6c 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -20,16 +20,16 @@ class Filter {
     var $ht;
 
     static $match_types = array(
-        'User Information' => array(
-            array('name'      => 'Name',
-                'email'     => 'Email',
+        /* trans */ 'User Information' => array(
+            array('name'      =>    /* trans */ 'Name',
+                'email'     =>      /* trans */ 'Email',
             ),
             900
         ),
-        'Email Meta-Data' => array(
-            array('reply-to'  => 'Reply-To Email',
-                'reply-to-name' => 'Reply-To Name',
-                'addressee' => 'Addressee (To and Cc)',
+        /* trans */ 'Email Meta-Data' => array(
+            array('reply-to'  =>    /* trans */ 'Reply-To Email',
+                'reply-to-name' =>  /* trans */ 'Reply-To Name',
+                'addressee' =>      /* trans */ 'Addressee (To and Cc)',
             ),
             200
         ),
@@ -349,14 +349,14 @@ class Filter {
 
     /* static */ function getSupportedMatchTypes() {
         return array(
-            'equal'=>       'Equal',
-            'not_equal'=>   'Not Equal',
-            'contains'=>    'Contains',
-            'dn_contain'=>  'Does Not Contain',
-            'starts'=>      'Starts With',
-            'ends'=>        'Ends With',
-            'match'=>       'Matches Regex',
-            'not_match'=>   'Does Not Match Regex',
+            'equal'=>       __('Equal'),
+            'not_equal'=>   __('Not Equal'),
+            'contains'=>    __('Contains'),
+            'dn_contain'=>  __('Does Not Contain'),
+            'starts'=>      __('Starts With'),
+            'ends'=>        __('Ends With'),
+            'match'=>       __('Matches Regex'),
+            'not_match'=>   __('Does Not Match Regex'),
         );
     }
 
diff --git a/include/class.forms.php b/include/class.forms.php
index e86a07dd09b3a7219c8cc10bf4e5906d559075cb..c3f1ff2c2133b21b1c60ef6c01f87f4de689ffbd 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -20,7 +20,7 @@
  */
 class Form {
     var $fields = array();
-    var $title = 'Unnamed';
+    var $title = '';
     var $instructions = '';
 
     var $_errors = null;
@@ -132,14 +132,14 @@ class FormField {
 
     static $types = array(
         'Basic Fields' => array(
-            'text'  => array('Short Answer', 'TextboxField'),
-            'memo' => array('Long Answer', 'TextareaField'),
-            'thread' => array('Thread Entry', 'ThreadEntryField', false),
-            'datetime' => array('Date and Time', 'DatetimeField'),
-            'phone' => array('Phone Number', 'PhoneField'),
-            'bool' => array('Checkbox', 'BooleanField'),
-            'choices' => array('Choices', 'ChoiceField'),
-            'break' => array('Section Break', 'SectionBreakField'),
+            'text'  => array(   /* trans */ 'Short Answer', 'TextboxField'),
+            'memo' => array(    /* trans */ 'Long Answer', 'TextareaField'),
+            'thread' => array(  /* trans */ 'Thread Entry', 'ThreadEntryField', false),
+            'datetime' => array(/* trans */ 'Date and Time', 'DatetimeField'),
+            'phone' => array(   /* trans */ 'Phone Number', 'PhoneField'),
+            'bool' => array(    /* trans */ 'Checkbox', 'BooleanField'),
+            'choices' => array( /* trans */ 'Choices', 'ChoiceField'),
+            'break' => array(   /* trans */ 'Section Break', 'SectionBreakField'),
         ),
     );
     static $more_types = array();
@@ -231,7 +231,8 @@ class FormField {
         # Validates a user-input into an instance of this field on a dynamic
         # form
         if ($this->get('required') && !$value && $this->hasData())
-            $this->_errors[] = sprintf('%s is a required field', $this->getLabel());
+            $this->_errors[] = sprintf(__('%s is a required field'),
+                $this->getLabel());
 
         # Perform declared validators for the field
         if ($vs = $this->get('validators')) {
@@ -357,7 +358,8 @@ class FormField {
     function __call($what, $args) {
         // XXX: Throw exception if $this->parent is not set
         if (!$this->parent)
-            throw new Exception($what.': Call to undefined function');
+            throw new Exception(sprintf(__('%s: Call to undefined function'),
+                $what));
         // BEWARE: DynamicFormField has a __call() which will create a new
         //      FormField instance and invoke __call() on it or bounce
         //      immediately back
@@ -495,7 +497,7 @@ class FormField {
 
     function getWidget() {
         if (!static::$widget)
-            throw new Exception('Widget not defined for this field');
+            throw new Exception(__('Widget not defined for this field'));
         if (!isset($this->_widget)) {
             $wc = $this->get('widget') ? $this->get('widget') : static::$widget;
             $this->_widget = new $wc($this);
@@ -519,22 +521,22 @@ class TextboxField extends FormField {
     function getConfigurationOptions() {
         return array(
             'size'  =>  new TextboxField(array(
-                'id'=>1, 'label'=>'Size', 'required'=>false, 'default'=>16,
+                'id'=>1, 'label'=>__('Size'), 'required'=>false, 'default'=>16,
                     'validator' => 'number')),
             'length' => new TextboxField(array(
-                'id'=>2, 'label'=>'Max Length', 'required'=>false, 'default'=>30,
+                'id'=>2, 'label'=>__('Max Length'), 'required'=>false, 'default'=>30,
                     'validator' => 'number')),
             'validator' => new ChoiceField(array(
-                'id'=>3, 'label'=>'Validator', 'required'=>false, 'default'=>'',
-                'choices' => array('phone'=>'Phone Number','email'=>'Email Address',
-                    'ip'=>'IP Address', 'number'=>'Number', ''=>'None'))),
+                'id'=>3, 'label'=>__('Validator'), 'required'=>false, 'default'=>'',
+                'choices' => array('phone'=>__('Phone Number'),'email'=>__('Email Address'),
+                    'ip'=>__('IP Address'), 'number'=>__('Number'), ''=>__('None')))),
             'validator-error' => new TextboxField(array(
-                'id'=>4, 'label'=>'Validation Error', 'default'=>'',
+                'id'=>4, 'label'=>__('Validation Error'), 'default'=>'',
                 'configuration'=>array('size'=>40, 'length'=>60),
-                'hint'=>'Message shown to user if the input does not match the validator')),
+                'hint'=>__('Message shown to user if the input does not match the validator'))),
             'placeholder' => new TextboxField(array(
-                'id'=>5, 'label'=>'Placeholder', 'required'=>false, 'default'=>'',
-                'hint'=>'Text shown in before any input from the user',
+                'id'=>5, 'label'=>__('Placeholder'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Text shown in before any input from the user'),
                 'configuration'=>array('size'=>40, 'length'=>40),
             )),
         );
@@ -546,12 +548,12 @@ class TextboxField extends FormField {
         $validators = array(
             '' =>       null,
             'email' =>  array(array('Validator', 'is_email'),
-                'Enter a valid email address'),
+                __('Enter a valid email address')),
             'phone' =>  array(array('Validator', 'is_phone'),
-                'Enter a valid phone number'),
+                __('Enter a valid phone number')),
             'ip' =>     array(array('Validator', 'is_ip'),
-                'Enter a valid IP address'),
-            'number' => array('is_numeric', 'Enter a number')
+                __('Enter a valid IP address')),
+            'number' => array('is_numeric', __('Enter a number'))
         );
         // Support configuration forms, as well as GUI-based form fields
         $valid = $this->get('validator');
@@ -588,17 +590,17 @@ class TextareaField extends FormField {
     function getConfigurationOptions() {
         return array(
             'cols'  =>  new TextboxField(array(
-                'id'=>1, 'label'=>'Width (chars)', 'required'=>true, 'default'=>40)),
+                'id'=>1, 'label'=>__('Width').' '.__('(chars)'), 'required'=>true, 'default'=>40)),
             'rows'  =>  new TextboxField(array(
-                'id'=>2, 'label'=>'Height (rows)', 'required'=>false, 'default'=>4)),
+                'id'=>2, 'label'=>__('Height').' '.__('(rows)'), 'required'=>false, 'default'=>4)),
             'length' => new TextboxField(array(
-                'id'=>3, 'label'=>'Max Length', 'required'=>false, 'default'=>0)),
+                'id'=>3, 'label'=>__('Max Length'), 'required'=>false, 'default'=>0)),
             'html' => new BooleanField(array(
-                'id'=>4, 'label'=>'HTML', 'required'=>false, 'default'=>true,
-                'configuration'=>array('desc'=>'Allow HTML input in this box'))),
+                'id'=>4, 'label'=>__('HTML'), 'required'=>false, 'default'=>true,
+                'configuration'=>array('desc'=>__('Allow HTML input in this box')))),
             'placeholder' => new TextboxField(array(
-                'id'=>5, 'label'=>'Placeholder', 'required'=>false, 'default'=>'',
-                'hint'=>'Text shown in before any input from the user',
+                'id'=>5, 'label'=>__('Placeholder'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Text shown in before any input from the user'),
                 'configuration'=>array('size'=>40, 'length'=>40),
             )),
         );
@@ -624,20 +626,20 @@ class PhoneField extends FormField {
     function getConfigurationOptions() {
         return array(
             'ext' => new BooleanField(array(
-                'label'=>'Extension', 'default'=>true,
+                'label'=>__('Extension'), 'default'=>true,
                 'configuration'=>array(
-                    'desc'=>'Add a separate field for the extension',
+                    'desc'=>__('Add a separate field for the extension'),
                 ),
             )),
             'digits' => new TextboxField(array(
-                'label'=>'Minimum length', 'default'=>7,
-                'hint'=>'Fewest digits allowed in a valid phone number',
+                'label'=>__('Minimum length'), 'default'=>7,
+                'hint'=>__('Fewest digits allowed in a valid phone number'),
                 'configuration'=>array('validator'=>'number', 'size'=>5),
             )),
             'format' => new ChoiceField(array(
-                'label'=>'Display format', 'default'=>'us',
-                'choices'=>array(''=>'-- Unformatted --',
-                    'us'=>'United States'),
+                'label'=>__('Display format'), 'default'=>'us',
+                'choices'=>array(''=>'-- '.__('Unformatted').' --',
+                    'us'=>__('United States')),
             )),
         );
     }
@@ -650,12 +652,12 @@ class PhoneField extends FormField {
         if ($phone && (
                 !is_numeric($phone) ||
                 strlen($phone) < $config['digits']))
-            $this->_errors[] = "Enter a valid phone number";
+            $this->_errors[] = __("Enter a valid phone number");
         if ($ext && $config['ext']) {
             if (!is_numeric($ext))
-                $this->_errors[] = "Enter a valid phone extension";
+                $this->_errors[] = __("Enter a valid phone extension");
             elseif (!$phone)
-                $this->_errors[] = "Enter a phone number for the extension";
+                $this->_errors[] = __("Enter a phone number for the extension");
         }
     }
 
@@ -685,8 +687,8 @@ class BooleanField extends FormField {
     function getConfigurationOptions() {
         return array(
             'desc' => new TextareaField(array(
-                'id'=>1, 'label'=>'Description', 'required'=>false, 'default'=>'',
-                'hint'=>'Text shown inline with the widget',
+                'id'=>1, 'label'=>__('Description'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Text shown inline with the widget'),
                 'configuration'=>array('rows'=>2)))
         );
     }
@@ -703,7 +705,7 @@ class BooleanField extends FormField {
     }
 
     function toString($value) {
-        return ($value) ? 'Yes' : 'No';
+        return ($value) ? __('Yes') : __('No');
     }
 }
 
@@ -713,20 +715,18 @@ class ChoiceField extends FormField {
     function getConfigurationOptions() {
         return array(
             'choices'  =>  new TextareaField(array(
-                'id'=>1, 'label'=>'Choices', 'required'=>false, 'default'=>'',
-                'hint'=>'List choices, one per line. To protect against
-                spelling changes, specify key:value names to preserve
-                entries if the list item names change',
+                'id'=>1, 'label'=>__('Choices'), 'required'=>false, 'default'=>'',
+                'hint'=>__('List choices, one per line. To protect against spelling changes, specify key:value names to preserve entries if the list item names change'),
                 'configuration'=>array('html'=>false)
             )),
             'default' => new TextboxField(array(
-                'id'=>3, 'label'=>'Default', 'required'=>false, 'default'=>'',
-                'hint'=>'(Enter a key). Value selected from the list initially',
+                'id'=>3, 'label'=>__('Default'), 'required'=>false, 'default'=>'',
+                'hint'=>__('(Enter a key). Value selected from the list initially'),
                 'configuration'=>array('size'=>20, 'length'=>40),
             )),
             'prompt' => new TextboxField(array(
-                'id'=>2, 'label'=>'Prompt', 'required'=>false, 'default'=>'',
-                'hint'=>'Leading text shown before a value is selected',
+                'id'=>2, 'label'=>__('Prompt'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Leading text shown before a value is selected'),
                 'configuration'=>array('size'=>40, 'length'=>40),
             )),
         );
@@ -815,23 +815,23 @@ class DatetimeField extends FormField {
     function getConfigurationOptions() {
         return array(
             'time' => new BooleanField(array(
-                'id'=>1, 'label'=>'Time', 'required'=>false, 'default'=>false,
+                'id'=>1, 'label'=>__('Time'), 'required'=>false, 'default'=>false,
                 'configuration'=>array(
-                    'desc'=>'Show time selection with date picker'))),
+                    'desc'=>__('Show time selection with date picker')))),
             'gmt' => new BooleanField(array(
-                'id'=>2, 'label'=>'Timezone Aware', 'required'=>false,
+                'id'=>2, 'label'=>__('Timezone Aware'), 'required'=>false,
                 'configuration'=>array(
-                    'desc'=>"Show date/time relative to user's timezone"))),
+                    'desc'=>__("Show date/time relative to user's timezone")))),
             'min' => new DatetimeField(array(
-                'id'=>3, 'label'=>'Earliest', 'required'=>false,
-                'hint'=>'Earliest date selectable')),
+                'id'=>3, 'label'=>__('Earliest'), 'required'=>false,
+                'hint'=>__('Earliest date selectable'))),
             'max' => new DatetimeField(array(
-                'id'=>4, 'label'=>'Latest', 'required'=>false,
+                'id'=>4, 'label'=>__('Latest'), 'required'=>false,
                 'default'=>null)),
             'future' => new BooleanField(array(
-                'id'=>5, 'label'=>'Allow Future Dates', 'required'=>false,
+                'id'=>5, 'label'=>__('Allow Future Dates'), 'required'=>false,
                 'default'=>true, 'configuration'=>array(
-                    'desc'=>'Allow entries into the future'))),
+                    'desc'=>__('Allow entries into the future' /* Used in the date field */)))),
         );
     }
 
@@ -840,12 +840,12 @@ class DatetimeField extends FormField {
         parent::validateEntry($value);
         if (!$value) return;
         if ($config['min'] and $value < $config['min'])
-            $this->_errors[] = 'Selected date is earlier than permitted';
+            $this->_errors[] = __('Selected date is earlier than permitted');
         elseif ($config['max'] and $value > $config['max'])
-            $this->_errors[] = 'Selected date is later than permitted';
+            $this->_errors[] = __('Selected date is later than permitted');
         // strtotime returns -1 on error for PHP < 5.1.0 and false thereafter
         elseif ($value === -1 or $value === false)
-            $this->_errors[] = 'Enter a valid date';
+            $this->_errors[] = __('Enter a valid date');
     }
 }
 
@@ -936,16 +936,16 @@ class PriorityField extends ChoiceField {
     function getConfigurationOptions() {
         return array(
             'prompt' => new TextboxField(array(
-                'id'=>2, 'label'=>'Prompt', 'required'=>false, 'default'=>'',
-                'hint'=>'Leading text shown before a value is selected',
+                'id'=>2, 'label'=>__('Prompt'), 'required'=>false, 'default'=>'',
+                'hint'=>__('Leading text shown before a value is selected'),
                 'configuration'=>array('size'=>40, 'length'=>40),
             )),
         );
     }
 }
-FormField::addFieldTypes('Built-in Lists', function() {
+FormField::addFieldTypes(/*trans*/ 'Built-in Lists', function() {
     return array(
-        'priority' => array('Priority Level', PriorityField),
+        'priority' => array(__('Priority Level'), PriorityField),
     );
 });
 
diff --git a/include/class.json.php b/include/class.json.php
index f3dfd282cdf565522c45b4f7f173da45e7e40bfa..ad5ac65c12e3da2c939faecdb67dfec3f049c635 100644
--- a/include/class.json.php
+++ b/include/class.json.php
@@ -43,19 +43,19 @@ class JsonDataParser {
     function lastError() {
         if (function_exists("json_last_error")) {
             $errors = array(
-            JSON_ERROR_NONE => 'No errors',
-            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
-            JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
-            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
-            JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
-            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
+            JSON_ERROR_NONE => __('No errors'),
+            JSON_ERROR_DEPTH => __('Maximum stack depth exceeded'),
+            JSON_ERROR_STATE_MISMATCH => __('Underflow or the modes mismatch'),
+            JSON_ERROR_CTRL_CHAR => __('Unexpected control character found'),
+            JSON_ERROR_SYNTAX => __('Syntax error, malformed JSON'),
+            JSON_ERROR_UTF8 => __('Malformed UTF-8 characters, possibly incorrectly encoded')
             );
             if ($message = $errors[json_last_error()])
                 return $message;
-            return "Unknown error";
+            return __("Unknown error");
         } else {
             # Doesn't look like Servies_JSON supports errors for decode()
-            return "Unknown JSON parsing error";
+            return __("Unknown JSON parsing error");
         }
     }
 }
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 89edc4285aa495f963da3d2334818de90f8bf974..105b5438d4e4c410264681554ba6ede5591efc04 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -316,7 +316,7 @@ class MailFetcher {
                     if ($source == 'delivered-to') continue;
 
                     $header['recipients'][] = array(
-                            'source' => "Email ($source)",
+                            'source' => sprintf(_S("Email (%s)"),$source),
                             'name' => $this->mime_decode(@$addr->personal),
                             'email' => strtolower($addr->mailbox).'@'.$addr->host);
                 } elseif(!$header['emailId']) {
@@ -462,7 +462,7 @@ class MailFetcher {
             // send images without a filename. For such a case, generate a
             // random filename for the image
             if (!$filename && $content_id && $part->type == 5) {
-                $filename = 'image-'.Misc::randCode(4).'.'.strtolower($part->subtype);
+                $filename = _S('image').'-'.Misc::randCode(4).'.'.strtolower($part->subtype);
             }
 
             if($filename) {
@@ -602,7 +602,8 @@ class MailFetcher {
 	    //Is the email address banned?
         if($mailinfo['email'] && TicketFilter::isBanned($mailinfo['email'])) {
 	        //We need to let admin know...
-            $ost->logWarning(__('Ticket denied'), __('Banned email').' - '.$mailinfo['email'], false);
+            $ost->logWarning(_S('Ticket denied'),
+                sprintf(_S('Banned email — %s'),$mailinfo['email']), false);
 	        return true; //Report success (moved or delete)
         }
 
@@ -684,7 +685,8 @@ class MailFetcher {
 
                 //Check the file  type
                 if(!$ost->isFileTypeAllowed($file)) {
-                    $file['error'] = 'Invalid file type (ext) for '.Format::htmlchars($file['name']);
+                    $file['error'] = sprintf(_S('Invalid file type (ext) for %s'),
+                        Format::htmlchars($file['name']));
                 }
                 elseif (@$a['data'] instanceof TnefAttachment) {
                     $file['data'] = $a['data']->getData();
@@ -729,8 +731,8 @@ class MailFetcher {
 
             // Log an error to the system logs
             $mailbox = Email::lookup($vars['emailId']);
-            $ost->logError(__('Mail Processing Exception'), sprintf(
-                __("Mailbox: %s | Error(s): %s"),
+            $ost->logError(_S('Mail Processing Exception'), sprintf(
+                _S("Mailbox: %s | Error(s): %s"),
                 $mailbox->getEmail(),
                 print_r($errors, true)
             ), false);
@@ -783,7 +785,7 @@ class MailFetcher {
 
         //Warn on excessive errors
         if($errors>$msgs) {
-            $warn=sprintf(__('Excessive errors processing emails for %1$s/%2$s. Please manually check the inbox.'),
+            $warn=sprintf(_S('Excessive errors processing emails for %1$s/%2$s. Please manually check the inbox.'),
                     $this->getHost(), $this->getUsername());
             $this->log($warn);
         }
@@ -795,7 +797,7 @@ class MailFetcher {
 
     function log($error) {
         global $ost;
-        $ost->logWarning('Mail Fetcher', $error);
+        $ost->logWarning(_S('Mail Fetcher'), $error);
     }
 
     /*
@@ -812,8 +814,8 @@ class MailFetcher {
         //We require imap ext to fetch emails via IMAP/POP3
         //We check here just in case the extension gets disabled post email config...
         if(!function_exists('imap_open')) {
-            $msg=__('osTicket requires PHP IMAP extension enabled for IMAP/POP3 email fetch to work!');
-            $ost->logWarning('Mail Fetch Error', $msg);
+            $msg=_S('osTicket requires PHP IMAP extension enabled for IMAP/POP3 email fetch to work!');
+            $ost->logWarning(_S('Mail Fetch Error'), $msg);
             return;
         }
 
@@ -851,13 +853,13 @@ class MailFetcher {
                 db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($emailId));
                 if (++$errors>=$MAXERRORS) {
                     //We've reached the MAX consecutive errors...will attempt logins at delayed intervals
-                    $msg="\n".__('osTicket is having trouble fetching emails from the following mail account').": \n".
-                        "\n".__('User').": ".$fetcher->getUsername().
-                        "\n".__('Host').": ".$fetcher->getHost().
-                        "\n".__('Error').": ".$fetcher->getLastError().
-                        "\n\n ".sprintf(__('%1$d consecutive errors. Maximum of %2$d allowed'), $errors, $MAXERRORS).
-                        "\n\n ".sprintf(__('This could be connection issues related to the mail server. Next delayed login attempt in aprox. %d minutes'),$TIMEOUT);
-                    $ost->alertAdmin(__('Mail Fetch Failure Alert'), $msg, true);
+                    $msg="\n"._S('osTicket is having trouble fetching emails from the following mail account').": \n".
+                        "\n"._S('User').": ".$fetcher->getUsername().
+                        "\n"._S('Host').": ".$fetcher->getHost().
+                        "\n"._S('Error').": ".$fetcher->getLastError().
+                        "\n\n ".sprintf(_S('%1$d consecutive errors. Maximum of %2$d allowed'), $errors, $MAXERRORS).
+                        "\n\n ".sprintf(_S('This could be connection issues related to the mail server. Next delayed login attempt in aprox. %d minutes'),$TIMEOUT);
+                    $ost->alertAdmin(_S('Mail Fetch Failure Alert'), $msg, true);
                 }
             }
         } //end while.
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 9c96403e5860b45cfcbd070b7236022c0caf1127..efcff356c753a89672f6d2937dedac59a60ce6d6 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -472,7 +472,7 @@ class Mail_Parse {
     }
 
     static function parsePriority($header=null){
-    	
+
     	if (! $header)
     		return 0;
     	// Test for normal "X-Priority: INT" style header & stringy version.
@@ -608,7 +608,7 @@ class EmailDataParser {
                     if ($source == 'delivered-to') continue;
 
                     $data['recipients'][] = array(
-                        'source' => "Email ($source)",
+                        'source' => sprintf(_S("Email (%s)"), $source),
                         'name' => trim(@$addr->personal, '"'),
                         'email' => strtolower($addr->mailbox).'@'.$addr->host);
                 } elseif(!$data['emailId']) {
diff --git a/include/class.nav.php b/include/class.nav.php
index 699d84df98c0737f63c64c009002e2c09f7b12f4..3b6a54cf9520fcb4cc200f15751f2a6c4e305925 100644
--- a/include/class.nav.php
+++ b/include/class.nav.php
@@ -100,12 +100,12 @@ class StaffNav {
     function getTabs(){
         if(!$this->tabs) {
             $this->tabs=array();
-            $this->tabs['dashboard'] = array('desc'=>__('Dashboard'),'href'=>'dashboard.php','title'=>'Staff Dashboard');
-            $this->tabs['users'] = array('desc' => __('Users'), 'href' => 'users.php', 'title' => 'User Directory');
-            $this->tabs['tickets'] = array('desc'=>__('Tickets'),'href'=>'tickets.php','title'=>'Ticket Queue');
-            $this->tabs['kbase'] = array('desc'=>__('Knowledgebase'),'href'=>'kb.php','title'=>'Knowledgebase');
+            $this->tabs['dashboard'] = array('desc'=>__('Dashboard'),'href'=>'dashboard.php','title'=>__('Staff Dashboard'));
+            $this->tabs['users'] = array('desc' => __('Users'), 'href' => 'users.php', 'title' => __('User Directory'));
+            $this->tabs['tickets'] = array('desc'=>__('Tickets'),'href'=>'tickets.php','title'=>__('Ticket Queue'));
+            $this->tabs['kbase'] = array('desc'=>__('Knowledgebase'),'href'=>'kb.php','title'=>__('Knowledgebase'));
             if (count($this->getRegisteredApps()))
-                $this->tabs['apps']=array('desc'=>__('Applications'),'href'=>'apps.php','title'=>'Applications');
+                $this->tabs['apps']=array('desc'=>__('Applications'),'href'=>'apps.php','title'=>__('Applications'));
         }
 
         return $this->tabs;
@@ -138,11 +138,11 @@ class StaffNav {
                     break;
                 case 'dashboard':
                     $subnav[]=array('desc'=>__('Dashboard'),'href'=>'dashboard.php','iconclass'=>'logs');
-                    $subnav[]=array('desc'=>__('Staff&nbsp;Directory'),'href'=>'directory.php','iconclass'=>'teams');
-                    $subnav[]=array('desc'=>__('My&nbsp;Profile'),'href'=>'profile.php','iconclass'=>'users');
+                    $subnav[]=array('desc'=>__('Staff Directory'),'href'=>'directory.php','iconclass'=>'teams');
+                    $subnav[]=array('desc'=>__('My Profile'),'href'=>'profile.php','iconclass'=>'users');
                     break;
                 case 'users':
-                    $subnav[] = array('desc' => 'User&nbsp;Directory', 'href' => 'users.php', 'iconclass' => 'teams');
+                    $subnav[] = array('desc' => 'User Directory', 'href' => 'users.php', 'iconclass' => 'teams');
                     $subnav[] = array('desc' => 'Organizations', 'href' => 'orgs.php', 'iconclass' => 'departments');
                     break;
                 case 'kbase':
@@ -151,7 +151,7 @@ class StaffNav {
                         if($staff->canManageFAQ())
                             $subnav[]=array('desc'=>__('Categories'),'href'=>'categories.php','iconclass'=>'faq-categories');
                         if($staff->canManageCannedResponses())
-                            $subnav[]=array('desc'=>__('Canned&nbsp;Responses'),'href'=>'canned.php','iconclass'=>'canned');
+                            $subnav[]=array('desc'=>__('Canned Responses'),'href'=>'canned.php','iconclass'=>'canned');
                     }
                    break;
                 case 'apps':
diff --git a/include/class.note.php b/include/class.note.php
index 4b0d36303335900a3c01f7f7c98889f41d05f2da..5443c8b37ddee1d4c971e1c0d21c353ee4375375 100644
--- a/include/class.note.php
+++ b/include/class.note.php
@@ -27,8 +27,8 @@ class QuickNoteModel extends VerySimpleModel {
 class QuickNote extends QuickNoteModel {
 
     static $types = array(
-        'U' => 'User',
-        'O' => 'Organization',
+        'U' => /* trans */ 'User',
+        'O' => /* trans */ 'Organization',
     );
     var $_staff;
 
@@ -62,7 +62,10 @@ class QuickNote extends QuickNoteModel {
     }
 
     function getIconTitle() {
-        return sprintf("%s Note", static::$types[$this->ext_id[0]]);
+        return sprintf(__(
+            // `%s` will be the type of note (`user` or `orgnaization`)
+            "%s Note"),
+            __(static::$types[$this->ext_id[0]]));
     }
 
     static function forUser($user, $org=false) {
diff --git a/include/class.organization.php b/include/class.organization.php
index 3a8a11b0260828402e7ff7b8f6d07dfcd8cd2cfe..6776e2e26d6ba324ce542f1d6ef9bc0d6fa8e25a 100644
--- a/include/class.organization.php
+++ b/include/class.organization.php
@@ -253,14 +253,14 @@ class Organization extends OrganizationModel {
                         && ($o=Organization::lookup(array('name'=>$f->getClean())))
                         && $o->id != $this->getId()) {
                 $valid = false;
-                $f->addError('Organization with the same name already exists');
+                $f->addError(__('Organization with the same name already exists'));
             }
         }
 
         if ($vars['domain']) {
             foreach (explode(',', $vars['domain']) as $d) {
                 if (!Validator::is_email('t@' . trim($d))) {
-                    $errors['domain'] = 'Enter a valid email domain, like domain.com';
+                    $errors['domain'] = __('Enter a valid email domain, like domain.com');
                 }
             }
         }
@@ -275,7 +275,7 @@ class Organization extends OrganizationModel {
                         && $team = Team::lookup(substr($vars['manager'], 1)))
                     break;
             default:
-                $errors['manager'] = 'Select a staff member or team from the list';
+                $errors['manager'] = __('Select a staff member or team from the list');
             }
         }
 
@@ -345,7 +345,7 @@ class Organization extends OrganizationModel {
         if (($field=$form->getField('name'))
                 && $field->getClean()
                 && Organization::lookup(array('name' => $field->getClean()))) {
-            $field->addError('Organization with the same name already exists');
+            $field->addError(__('Organization with the same name already exists'));
             $valid = false;
         }
 
@@ -424,16 +424,16 @@ class OrganizationForm extends DynamicForm {
     }
 
 }
-Filter::addSupportedMatches('Organization Data', function() {
+Filter::addSupportedMatches(/*trans*/ 'Organization Data', function() {
     $matches = array();
     foreach (OrganizationForm::getInstance()->getFields() as $f) {
         if (!$f->hasData())
             continue;
-        $matches['field.'.$f->get('id')] = 'Organization / '.$f->getLabel();
+        $matches['field.'.$f->get('id')] = __('Organization').' / '.$f->getLabel();
         if (($fi = $f->getImpl()) instanceof SelectionField) {
             foreach ($fi->getList()->getProperties() as $p) {
                 $matches['field.'.$f->get('id').'.'.$p->get('id')]
-                    = 'Organization / '.$f->getLabel().' / '.$p->getLabel();
+                    = __('Organization').' / '.$f->getLabel().' / '.$p->getLabel();
             }
         }
     }
diff --git a/include/class.orm.php b/include/class.orm.php
index 1d8810919a1bab31a9ca853e88162a86d9de3902..122277a80be7583eada0a2d04d1d267a9ce84fe4 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -49,7 +49,7 @@ class VerySimpleModel {
         }
         if (isset($default))
             return $default;
-        throw new OrmException(sprintf('%s: %s: Field not defined',
+        throw new OrmException(sprintf(__('%s: %s: Field not defined'),
             get_class($this), $field));
     }
     function __get($field) {
@@ -86,7 +86,7 @@ class VerySimpleModel {
             }
             else
                 throw new InvalidArgumentException(
-                    'Expecting NULL or instance of ' . $j['fkey'][0]);
+                    sprintf(__('Expecting NULL or instance of %s'), $j['fkey'][0]));
 
             // Capture the foreign key id value
             $field = $j['local'];
@@ -132,7 +132,7 @@ class VerySimpleModel {
     static function _inspect() {
         if (!static::$meta['table'])
             throw new OrmConfigurationException(
-                'Model does not define meta.table', get_called_class());
+                __('Model does not define meta.table'), get_called_class());
 
         // Break down foreign-key metadata
         foreach (static::$meta['joins'] as $field => &$j) {
@@ -141,8 +141,10 @@ class VerySimpleModel {
                 $info = $model::$meta['joins'][$key];
                 $constraint = array();
                 if (!is_array($info['constraint']))
-                    throw new OrmConfigurationException(
-                        $j['reverse'].': Reverse does not specify any constraints');
+                    throw new OrmConfigurationException(sprintf(__(
+                        // `reverse` here is the reverse of an ORM relationship
+                        '%s: Reverse does not specify any constraints'),
+                        $j['reverse']));
                 foreach ($info['constraint'] as $foreign => $local) {
                     list(,$field) = explode('.', $local);
                     $constraint[$field] = "$model.$foreign";
@@ -383,10 +385,10 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         return $this->getIterator()->offsetGet($offset);
     }
     function offsetUnset($a) {
-        throw new Exception('QuerySet is read-only');
+        throw new Exception(__('QuerySet is read-only'));
     }
     function offsetSet($a, $b) {
-        throw new Exception('QuerySet is read-only');
+        throw new Exception(__('QuerySet is read-only'));
     }
 
     function __toString() {
@@ -478,10 +480,10 @@ class ModelInstanceIterator implements Iterator, ArrayAccess {
         return $this->cache[$offset];
     }
     function offsetUnset($a) {
-        throw new Exception(sprintf('%s is read-only', get_class($this)));
+        throw new Exception(sprintf(__('%s is read-only'), get_class($this)));
     }
     function offsetSet($a, $b) {
-        throw new Exception(sprintf('%s is read-only', get_class($this)));
+        throw new Exception(sprintf(__('%s is read-only'), get_class($this)));
     }
 }
 
@@ -519,7 +521,7 @@ class InstrumentedList extends ModelInstanceIterator {
 
     function add($object, $at=false) {
         if (!$object || !$object instanceof $this->model)
-            throw new Exception('Attempting to add invalid object to list');
+            throw new Exception(__('Attempting to add invalid object to list'));
 
         $object->set($this->key, $this->id);
         $object->save();
@@ -1004,7 +1006,7 @@ class MysqlExecutor {
 
     function _bind($params) {
         if (count($params) != $this->stmt->param_count)
-            throw new Exception('Parameter count does not match query');
+            throw new Exception(__('Parameter count does not match query'));
 
         $types = '';
         $ps = array();
diff --git a/include/class.osticket.php b/include/class.osticket.php
index c2d2b5d88dc36ecb5dd29b451fe5977577b02e93..88a055504ead22b6d6ebc9118d2c04ab51c3569f 100644
--- a/include/class.osticket.php
+++ b/include/class.osticket.php
@@ -246,7 +246,7 @@ class osTicket {
         if($email) {
             $email->sendAlert($to, $subject, $message, null, array('text'=>true));
         } else {//no luck - try the system mail.
-            Mailer::sendmail($to, $subject, $message, sprintf(__('"osTicket Alerts" <%s>'),$to));
+            Mailer::sendmail($to, $subject, $message, '"'.__('osTicket Alerts').sprintf('" <%s>',$to));
         }
 
         //log the alert? Watch out for loops here.
@@ -277,8 +277,9 @@ class osTicket {
             $alert =false;
 
         $e = new Exception();
-        $bt = str_replace(ROOT_DIR, '(root)/', $e->getTraceAsString());
-        $error .= nl2br("\n\n---- Backtrace ----\n".$bt);
+        $bt = str_replace(ROOT_DIR, _S(/* `root` is a root folder */ '(root)').'/',
+            $e->getTraceAsString());
+        $error .= nl2br("\n\n---- "._S('Backtrace')." ----\n".$bt);
 
         return $this->log(LOG_ERR, $title, $error, $alert);
     }
diff --git a/include/class.page.php b/include/class.page.php
index 8980bc273b79cab5a781bc7dbe0ba9ada201c682..ec74cf5a6652dd4f662d3f6d3b906f3325d95178 100644
--- a/include/class.page.php
+++ b/include/class.page.php
@@ -105,8 +105,8 @@ class Page {
     function update($vars, &$errors) {
 
         if(!$vars['isactive'] && $this->isInUse()) {
-            $errors['err'] = 'A page currently in-use CANNOT be disabled!';
-            $errors['isactive'] = 'Page is in-use!';
+            $errors['err'] = __('A page currently in-use CANNOT be disabled!');
+            $errors['isactive'] = __('Page is in-use!');
         }
 
         if($errors || !$this->save($this->getId(), $vars, $errors))
@@ -236,18 +236,18 @@ class Page {
 
         //validate
         if($id && $id!=$vars['id'])
-            $errors['err'] = 'Internal error. Try again';
+            $errors['err'] = __('Internal error. Try again');
 
         if(!$vars['type'])
-            $errors['type'] = 'Type required';
+            $errors['type'] = __('Type is required');
 
         if(!$vars['name'])
-            $errors['name'] = 'Name required';
+            $errors['name'] = __('Name is required');
         elseif(($pid=self::getIdByName($vars['name'])) && $pid!=$id)
-            $errors['name'] = 'Name already exists';
+            $errors['name'] = __('Name already exists');
 
         if(!$vars['body'])
-            $errors['body'] = 'Page body is required';
+            $errors['body'] = __('Page body is required');
 
         if($errors) return false;
 
@@ -264,12 +264,12 @@ class Page {
             if(db_query($sql))
                 return true;
 
-            $errors['err']='Unable to update page.';
+            $errors['err']=__('Unable to update page.');
 
         } else {
             $sql='INSERT INTO '.PAGE_TABLE.' SET '.$sql.', created=NOW()';
             if (!db_query($sql) || !($id=db_insert_id())) {
-                $errors['err']='Unable to create page. Internal error';
+                $errors['err']=__('Unable to create page. Internal error');
                 return false;
             }
 
diff --git a/include/class.pop3.php b/include/class.pop3.php
deleted file mode 100644
index 2ece6077c25bb2bb1784f3e9c7a2ddd2f4794e97..0000000000000000000000000000000000000000
--- a/include/class.pop3.php
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-//No longer used. just used to clear the old file for now. Will be deleted in the upcoming versions.
-?>
diff --git a/include/class.setup.php b/include/class.setup.php
index 1e6569b522ce0723accc24dbb3103880c75d2132..98471d21a3b31373de96c54275f5a82dc9f7c8db 100644
--- a/include/class.setup.php
+++ b/include/class.setup.php
@@ -30,7 +30,8 @@ Class SetupWizard {
 
     function SetupWizard(){
         $this->errors=array();
-        $this->version_verbose = sprintf(_('osTicket %s'), THIS_VERSION);
+        $this->version_verbose = sprintf(_('osTicket %s' /* <%s> is for the version */),
+            THIS_VERSION);
 
     }
 
diff --git a/include/class.signal.php b/include/class.signal.php
index af257cd4a2dd560076a33d5a34d31d02750c9a01..bb174a9aaf01d657ff83193694a771b9ec0f55aa 100644
--- a/include/class.signal.php
+++ b/include/class.signal.php
@@ -58,9 +58,9 @@ class Signal {
         if (!isset(self::$subscribers[$signal])) self::$subscribers[$signal] = array();
         // XXX: Ensure $object if set is a class
         if ($object && !is_string($object))
-            trigger_error("Invalid object: $object: Expected class");
+            trigger_error(sprintf(_S("Invalid object: %s: Expected class"), $class));
         elseif ($check && !is_callable($check)) {
-            trigger_error("Invalid check function: Must be callable");
+            trigger_error(_S("Invalid check function: Must be callable"));
             $check = null;
         }
         self::$subscribers[$signal][] = array($object, $callable, $check);
diff --git a/include/class.sla.php b/include/class.sla.php
index 27c200cb2ea1cf687f6a9805d0fe4d2e29eeac42..4b3455bc18fd35e0b0cb37054f8b2802878016a1 100644
--- a/include/class.sla.php
+++ b/include/class.sla.php
@@ -168,7 +168,7 @@ class SLA {
             $errors['grace_period']=__('Numeric value required (in hours)');
 
         if(!$vars['name'])
-            $errors['name']=__('Name required');
+            $errors['name']=__('Name is required');
         elseif(($sid=SLA::getIdByName($vars['name'])) && $sid!=$id)
             $errors['name']=__('Name already exists');
 
@@ -196,7 +196,7 @@ class SLA {
             if(db_query($sql) && ($id=db_insert_id()))
                 return $id;
 
-            $errors['err']=__('Unable to add SLA. Internal error');
+            $errors['err']=__('Unable to add SLA. Internal error occurred');
         }
 
         return false;
diff --git a/include/class.staff.php b/include/class.staff.php
index f0ce246bc698ad784f516b0d807fa70d7b75ba35..e4250ef77c736e84d5afb5be312fc695a89cc387 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -442,35 +442,35 @@ class Staff extends AuthenticatedUser {
         $vars['lastname']=Format::striptags($vars['lastname']);
 
         if($this->getId()!=$vars['id'])
-            $errors['err']=__('Internal Error');
+            $errors['err']=__('Internal error occurred');
 
         if(!$vars['firstname'])
-            $errors['firstname']=__('First name required');
+            $errors['firstname']=__('First name is required');
 
         if(!$vars['lastname'])
-            $errors['lastname']=__('Last name required');
+            $errors['lastname']=__('Last name is required');
 
         if(!$vars['email'] || !Validator::is_email($vars['email']))
-            $errors['email']=__('Valid email required');
+            $errors['email']=__('Valid email is required');
         elseif(Email::getIdByEmail($vars['email']))
             $errors['email']=__('Already in-use as system email');
         elseif(($uid=Staff::getIdByEmail($vars['email'])) && $uid!=$this->getId())
             $errors['email']=__('Email already in-use by another staff member');
 
         if($vars['phone'] && !Validator::is_phone($vars['phone']))
-            $errors['phone']=__('Valid number required');
+            $errors['phone']=__('Valid phone number is required');
 
         if($vars['mobile'] && !Validator::is_phone($vars['mobile']))
-            $errors['mobile']=__('Valid number required');
+            $errors['mobile']=__('Valid phone number is required');
 
         if($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']) {
 
             if(!$vars['passwd1'])
-                $errors['passwd1']=__('New password required');
+                $errors['passwd1']=__('New password is required');
             elseif($vars['passwd1'] && strlen($vars['passwd1'])<6)
-                $errors['passwd1']=__('Must be at least 6 characters');
+                $errors['passwd1']=__('Password must be at least 6 characters');
             elseif($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
-                $errors['passwd2']=__('Password(s) do not match');
+                $errors['passwd2']=__('Passwords do not match');
 
             if (($rtoken = $_SESSION['_staff']['reset-token'])) {
                 $_config = new Config('pwreset');
@@ -483,7 +483,7 @@ class Staff extends AuthenticatedUser {
                         __('Invalid reset token. Logout and try again');
             }
             elseif(!$vars['cpasswd'])
-                $errors['cpasswd']=__('Current password required');
+                $errors['cpasswd']=__('Current password is required');
             elseif(!$this->cmp_passwd($vars['cpasswd']))
                 $errors['cpasswd']=__('Invalid current password!');
             elseif(!strcasecmp($vars['passwd1'], $vars['cpasswd']))
@@ -491,7 +491,7 @@ class Staff extends AuthenticatedUser {
         }
 
         if(!$vars['timezone_id'])
-            $errors['timezone_id']=__('Time zone required');
+            $errors['timezone_id']=__('Time zone selection is required');
 
         if($vars['default_signature_type']=='mine' && !$vars['signature'])
             $errors['default_signature_type'] = __("You don't have a signature");
@@ -670,7 +670,7 @@ class Staff extends AuthenticatedUser {
         $token = Misc::randCode(48); // 290-bits
 
         if (!$content)
-            return new Error('Unable to retrieve password reset email template');
+            return new Error(/* trans */ 'Unable to retrieve password reset email template');
 
         $vars = array(
             'url' => $ost->getConfig()->getBaseUrl(),
@@ -691,8 +691,8 @@ class Staff extends AuthenticatedUser {
         Signal::send('auth.pwreset.email', $this, $info);
 
         if ($info['log'])
-            $ost->logWarning(_('Staff Password Reset'), sprintf(
-             _('Password reset was attempted for staff member: %1$s<br><br>
+            $ost->logWarning(_S('Staff Password Reset'), sprintf(
+             _S('Password reset was attempted for staff member: %1$s<br><br>
                 Requested-User-Id: %2$s<br>
                 Source-Ip: %3$s<br>
                 Email-Sent-To: %4$s<br>
@@ -732,46 +732,46 @@ class Staff extends AuthenticatedUser {
 
         $error = '';
         if(!$vars['username'] || !Validator::is_username($vars['username'], $error))
-            $errors['username']=($error) ? $error : __('Username required');
+            $errors['username']=($error) ? $error : __('Username is required');
         elseif(($uid=Staff::getIdByUsername($vars['username'])) && $uid!=$id)
             $errors['username']=__('Username already in use');
 
         if(!$vars['email'] || !Validator::is_email($vars['email']))
-            $errors['email']=__('Valid email required');
+            $errors['email']=__('Valid email is required');
         elseif(Email::getIdByEmail($vars['email']))
-            $errors['email']=__('Already in-use system email');
+            $errors['email']=__('Already in use system email');
         elseif(($uid=Staff::getIdByEmail($vars['email'])) && $uid!=$id)
             $errors['email']=__('Email already in use by another staff member');
 
         if($vars['phone'] && !Validator::is_phone($vars['phone']))
-            $errors['phone']=__('Valid number required');
+            $errors['phone']=__('Valid phone number is required');
 
         if($vars['mobile'] && !Validator::is_phone($vars['mobile']))
-            $errors['mobile']=__('Valid number required');
+            $errors['mobile']=__('Valid phone number is required');
 
         if($vars['passwd1'] || $vars['passwd2'] || !$id) {
             if($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) {
-                $errors['passwd2']=__('Password(s) do not match');
+                $errors['passwd2']=__('Passwords do not match');
             }
             elseif ($vars['backend'] != 'local' || $vars['welcome_email']) {
                 // Password can be omitted
             }
             elseif(!$vars['passwd1'] && !$id) {
-                $errors['passwd1']=__('Temporary password required');
+                $errors['passwd1']=__('Temporary password is required');
                 $errors['temppasswd']=__('Required');
             } elseif($vars['passwd1'] && strlen($vars['passwd1'])<6) {
-                $errors['passwd1']=__('Must be at least 6 characters');
+                $errors['passwd1']=__('Password must be at least 6 characters');
             }
         }
 
         if(!$vars['dept_id'])
-            $errors['dept_id']=__('Department required');
+            $errors['dept_id']=__('Department is required');
 
         if(!$vars['group_id'])
-            $errors['group_id']=__('Group required');
+            $errors['group_id']=__('Group is required');
 
         if(!$vars['timezone_id'])
-            $errors['timezone_id']=__('Time zone required');
+            $errors['timezone_id']=__('Time zone selection is required');
 
         if($errors) return false;
 
@@ -817,7 +817,7 @@ class Staff extends AuthenticatedUser {
             if(db_query($sql) && ($uid=db_insert_id()))
                 return $uid;
 
-            $errors['err']=__('Unable to create user. Internal error');
+            $errors['err']=__('Unable to create user. Internal error occurred');
         }
 
         return false;
diff --git a/include/class.team.php b/include/class.team.php
index cc2648ebf2c657b15dd4cdaa30145830ddc259ce..3e5c02a9d8749cfccc28939ce53ad98582516ca9 100644
--- a/include/class.team.php
+++ b/include/class.team.php
@@ -30,7 +30,7 @@ class Team {
 
         if(!$id && !($id=$this->getId()))
             return false;
-        
+
         $sql='SELECT team.*,count(member.staff_id) as members '
             .' FROM '.TEAM_TABLE.' team '
             .' LEFT JOIN '.TEAM_MEMBER_TABLE.' member USING(team_id) '
@@ -133,7 +133,7 @@ class Team {
     function update($vars, &$errors) {
 
         //reset team lead if they're being deleted
-        if($this->getLeadId()==$vars['lead_id'] 
+        if($this->getLeadId()==$vars['lead_id']
                 && $vars['remove'] && in_array($this->getLeadId(), $vars['remove']))
             $vars['lead_id']=0;
 
@@ -197,7 +197,7 @@ class Team {
     }
 
     function getTeams( $availableOnly=false ) {
-        
+
         $teams=array();
         $sql='SELECT team_id, name FROM '.TEAM_TABLE;
         if($availableOnly) {
@@ -224,22 +224,22 @@ class Team {
         return self::getTeams(true);
     }
 
-    function create($vars, &$errors) { 
+    function create($vars, &$errors) {
         return self::save(0, $vars, $errors);
     }
 
     function save($id, $vars, &$errors) {
         if($id && $vars['id']!=$id)
             $errors['err']=__('Missing or invalid team');
-            
+
         if(!$vars['name']) {
-            $errors['name']=__('Team name required');
+            $errors['name']=__('Team name is required');
         } elseif(strlen($vars['name'])<3) {
             $errors['name']=__('Team name must be at least 3 chars.');
         } elseif(($tid=Team::getIdByName($vars['name'])) && $tid!=$id) {
             $errors['name']=__('Team name already exists');
         }
-        
+
         if($errors) return false;
 
         $sql='SET updated=NOW(),isenabled='.db_input($vars['isenabled']).
@@ -251,16 +251,16 @@ class Team {
             $sql='UPDATE '.TEAM_TABLE.' '.$sql.',lead_id='.db_input($vars['lead_id']).' WHERE team_id='.db_input($id);
             if(db_query($sql) && db_affected_rows())
                 return true;
-                    
-            $errors['err']=__('Unable to update the team. Internal error');
+
+            $errors['err']=__('Unable to update the team. Internal error occurred');
         } else {
             $sql='INSERT INTO '.TEAM_TABLE.' '.$sql.',created=NOW()';
             if(db_query($sql) && ($id=db_insert_id()))
                 return $id;
-                
-            $errors['err']=__('Unable to create the team. Internal error');
+
+            $errors['err']=__('Unable to create the team. Internal error occurred');
         }
-        
+
         return false;
     }
 }
diff --git a/include/class.template.php b/include/class.template.php
index 8c9ca7a10fb5a48b441de678c6eebdafaf3e7169..3e6dbfd2fd89a418f3a4a8f24a6512aa293abc91 100644
--- a/include/class.template.php
+++ b/include/class.template.php
@@ -170,8 +170,8 @@ class EmailTemplateGroup {
         if ($tpl=EmailTemplate::fromInitialData($name, $this))
             return $tpl;
 
-        $ost->logWarning(__('Template Fetch Error'),
-            sprintf(__('Unable to fetch "%1$s" template - id #%d'), $name, $this->getId()));
+        $ost->logWarning(_S('Template Fetch Error'),
+            sprintf(_S('Unable to fetch "%1$s" template - id #%d'), $name, $this->getId()));
         return false;
     }
 
@@ -250,7 +250,7 @@ class EmailTemplateGroup {
 
     function update($vars,&$errors) {
         if(!$vars['isactive'] && $this->isInUse())
-            $errors['isactive']=__('Template in use cannot be disabled!');
+            $errors['isactive']=__('In-use template set cannot be disabled!');
 
         if(!$this->save($this->getId(),$vars,$errors))
             return false;
@@ -317,15 +317,15 @@ class EmailTemplateGroup {
         $vars['name']=Format::striptags(trim($vars['name']));
 
         if($id && $id!=$vars['tpl_id'])
-            $errors['err']=__('Internal error. Try again');
+            $errors['err']=__('Internal error occurred. Try again');
 
         if(!$vars['name'])
-            $errors['name']=__('Name required');
+            $errors['name']=__('Name is required');
         elseif(($tid=EmailTemplateGroup::getIdByName($vars['name'])) && $tid!=$id)
             $errors['name']=__('Template name already exists');
 
         if(!$id && ($vars['tpl_id'] && !($tpl=EmailTemplateGroup::lookup($vars['tpl_id']))))
-            $errors['tpl_id']=__('Invalid template group specified');
+            $errors['tpl_id']=__('Invalid template set specified');
 
         if($errors) return false;
 
@@ -352,7 +352,7 @@ class EmailTemplateGroup {
             $sql='INSERT INTO '.EMAIL_TEMPLATE_GRP_TABLE
                 .' SET created=NOW(), '.$sql;
             if(!db_query($sql) || !($new_id=db_insert_id())) {
-                $errors['err']=__('Unable to create template. Internal error');
+                $errors['err']=__('Unable to create template. Internal error occurred');
                 return false;
             }
 
@@ -474,16 +474,16 @@ class EmailTemplate {
 
     function save($id, $vars, &$errors) {
         if(!$vars['subject'])
-            $errors['subject']='Message subject required';
+            $errors['subject']='Message subject is required';
 
         if(!$vars['body'])
-            $errors['body']='Message body required';
+            $errors['body']='Message body is required';
 
         if (!$id) {
             if (!$vars['tpl_id'])
-                $errors['tpl_id']='Template group required';
+                $errors['tpl_id']='Template set is required';
             if (!$vars['code_name'])
-                $errors['code_name']='Code name required';
+                $errors['code_name']='Code name is required';
         }
 
         if ($errors)
@@ -555,7 +555,7 @@ class EmailTemplate {
             return $templ;
         }
         raise_error("$lang/templates/$name.yaml: "
-            . _('Email templates must define both "subject" and "body" parts of the template'),
+            . _S('Email templates must define both "subject" and "body" parts of the template'),
             'InitialDataError');
         return false;
     }
diff --git a/include/class.thread.php b/include/class.thread.php
index e72e03b66d6d78ae90f4d2a8292e56eada714c9d..bcdcc0ad03515bf271a822c153bf83e58eb88b16 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -524,9 +524,10 @@ Class ThreadEntry {
             $error = $attachment['error'];
 
             if(!$error)
-                $error = sprintf(__('Unable to import attachment - %s'),$attachment['name']);
+                $error = sprintf(_S('Unable to import attachment - %s'),$attachment['name']);
 
-            $this->getTicket()->logNote(__('File Import Error'), $error, 'SYSTEM', false);
+            $this->getTicket()->logNote(_S('File Import Error'), $error,
+                _S('SYSTEM'), false);
         }
 
         return $id;
@@ -665,11 +666,10 @@ Class ThreadEntry {
             // This mail was sent by this system. It was received due to
             // some kind of mail delivery loop. It should not be considered
             // a response to an existing thread entry
-            if ($ost) $ost->log(LOG_ERR, 'Email loop detected', sprintf(
-               'It appears as though &lt;%s&gt; is being used as a forwarded or
-                fetched email account and is also being used as a user /
-                system account. Please correct the loop or seek technical
-                assistance.', $mailinfo['email']),
+            if ($ost) $ost->log(LOG_ERR, _S('Email loop detected'), sprintf(
+                _S('It appears as though &lt;%s&gt; is being used as a forwarded or fetched email account and is also being used as a user / system account. Please correct the loop or seek technical assistance.'),
+                $mailinfo['email']),
+
                 // This is quite intentional -- don't continue the loop
                 false,
                 // Force the message, even if logging is disabled
@@ -1124,7 +1124,7 @@ class Message extends ThreadEntry {
         if(!$vars || !is_array($vars) || !$vars['ticketId'])
             $errors['err'] = __('Missing or invalid data');
         elseif(!$vars['message'])
-            $errors['message'] = __('Message required');
+            $errors['message'] = __('Message content is required');
 
         if($errors) return false;
 
@@ -1193,7 +1193,7 @@ class Response extends ThreadEntry {
         if(!$vars || !is_array($vars) || !$vars['ticketId'])
             $errors['err'] = __('Missing or invalid data');
         elseif(!$vars['response'])
-            $errors['response'] = __('Response required');
+            $errors['response'] = __('Response content is required');
 
         if($errors) return false;
 
@@ -1243,7 +1243,7 @@ class Note extends ThreadEntry {
         if(!$vars || !is_array($vars) || !$vars['ticketId'])
             $errors['err'] = __('Missing or invalid data');
         elseif(!$vars['note'])
-            $errors['note'] = __('Note required');
+            $errors['note'] = __('Note content is required');
 
         if($errors) return false;
 
@@ -1279,12 +1279,13 @@ class ThreadBody /* extends SplString */ {
     function __construct($body, $type='text', $options=array()) {
         $type = strtolower($type);
         if (!in_array($type, static::$types))
-            throw new Exception($type.': Unsupported ThreadBody type');
+            throw new Exception("$type: Unsupported ThreadBody type");
         $this->body = (string) $body;
         if (strlen($this->body) > 250000) {
             $max_packet = db_get_variable('max_allowed_packet', 'global');
             // Truncate just short of the max_allowed_packet
-            $this->body = substr($this->body, $max_packet - 2048) . ' ... (truncated)';
+            $this->body = substr($this->body, $max_packet - 2048) . ' ... '
+               . _S('(truncated)');
         }
         $this->type = $type;
         $this->options = array_merge($this->options, $options);
@@ -1358,7 +1359,7 @@ class ThreadBody /* extends SplString */ {
     }
 
     function display($format=false) {
-        throw new Exception('display: Abstract dispplay() method not implemented');
+        throw new Exception('display: Abstract display() method not implemented');
     }
 
     function getSearchable() {
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 2780d478bfadf8d495a359f75a52ecd5a5225b0d..9a13107ba20e9c9281df7c25067aab62ea4de4d4 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -672,7 +672,7 @@ class Ticket {
                      $collabs[] = $c;
             }
 
-            $this->logNote('Collaborators Removed',
+            $this->logNote(_S('Collaborators Removed'),
                     implode("<br>", $collabs), $thisstaff, false);
         }
 
@@ -976,8 +976,10 @@ class Ticket {
         global $ost, $cfg;
 
         //Log the limit notice as a warning for admin.
-        $msg=sprintf(__('Max open tickets (%1$d) reached  for %2$s'), $cfg->getMaxOpenTickets(), $this->getEmail());
-        $ost->logWarning(sprintf(__('Max. Open Tickets Limit (%s)'),$this->getEmail()), $msg);
+        $msg=sprintf(_S('Maximum open tickets (%1$d) reached for %2$s'),
+            $cfg->getMaxOpenTickets(), $this->getEmail());
+        $ost->logWarning(sprintf(_S('Maximum Open Tickets Limit (%s)'),$this->getEmail()),
+            $msg);
 
         if(!$sendNotice || !$cfg->sendOverLimitNotice())
             return true;
@@ -1042,7 +1044,7 @@ class Ticket {
 
         $vars = array_merge($vars, array(
                     'message' => (string) $entry,
-                    'poster' => $poster? $poster : 'A collaborator',
+                    'poster' => $poster ?: _S('A collaborator'),
                     )
                 );
 
@@ -1134,11 +1136,12 @@ class Ticket {
 
         $this->reload();
 
-        $comments = $comments?$comments:__('Ticket assignment');
-        $assigner = $thisstaff?$thisstaff:__('SYSTEM (Auto Assignment)');
+        $comments = $comments ?: _S('Ticket assignment');
+        $assigner = $thisstaff ?: _S('SYSTEM (Auto Assignment)');
 
         //Log an internal note - no alerts on the internal note.
-        $note = $this->logNote('Ticket Assigned to '.$assignee->getName(),
+        $note = $this->logNote(
+            sprintf(_S('Ticket Assigned to %s'), $assignee->getName()),
             $comments, $assigner, false);
 
         //See if we need to send alerts
@@ -1390,7 +1393,8 @@ class Ticket {
             $this->selectSLAId();
 
         /*** log the transfer comments as internal note - with alerts disabled - ***/
-        $title=sprintf(__('Ticket transferred from %1$s to %2$s'), $currentDept, $this->getDeptName());
+        $title=sprintf(_S('Ticket transferred from %1$s to %2$s'),
+            $currentDept, $this->getDeptName());
         $comments=$comments?$comments:$title;
         $note = $this->logNote($title, $comments, $thisstaff, false);
 
@@ -1539,14 +1543,14 @@ class Ticket {
         $this->recipients = null;
 
         //Log an internal note
-        $note = sprintf('%s changed ticket ownership to %s',
+        $note = sprintf(_S('%s changed ticket ownership to %s'),
                 $thisstaff->getName(), $user->getName());
 
         //Remove the new owner from list of collaborators
         $c = Collaborator::lookup(array('userId' => $user->getId(),
                     'ticketId' => $this->getId()));
         if ($c && $c->remove())
-            $note.= ' (removed as collaborator)';
+            $note.= ' '._S('(removed as collaborator)');
 
         $this->logNote('Ticket ownership changed', $note);
 
@@ -1587,15 +1591,17 @@ class Ticket {
                 if (($user=User::fromVars($recipient)))
                     if ($c=$this->addCollaborator($user, $info, $errors))
                         $collabs[] = sprintf('%s%s',
-                                (string) $c,
-                                $recipient['source'] ? " via {$recipient['source']}" : ''
-                                );
+                            (string) $c,
+                            $recipient['source']
+                                ? " ".sprintf(_S('via %s'), $recipient['source'])
+                                : ''
+                            );
             }
             //TODO: Can collaborators add others?
             if ($collabs) {
                 //TODO: Change EndUser to name of  user.
-                $this->logNote('Collaborators added by enduser',
-                        implode("<br>", $collabs), 'EndUser', false);
+                $this->logNote(_S('Collaborators added by end user'),
+                        implode("<br>", $collabs), _S('End User'), false);
             }
         }
 
@@ -1986,11 +1992,11 @@ class Ticket {
             return false;
 
         $fields=array();
-        $fields['topicId']  = array('type'=>'int',      'required'=>1, 'error'=>__('Help topic required'));
-        $fields['slaId']    = array('type'=>'int',      'required'=>0, 'error'=>__('Select SLA'));
-        $fields['duedate']  = array('type'=>'date',     'required'=>0, 'error'=>__('Invalid date - must be MM/DD/YY'));
+        $fields['topicId']  = array('type'=>'int',      'required'=>1, 'error'=>__('Help topic selection is required'));
+        $fields['slaId']    = array('type'=>'int',      'required'=>0, 'error'=>__('Select a valid SLA'));
+        $fields['duedate']  = array('type'=>'date',     'required'=>0, 'error'=>__('Invalid date format - must be MM/DD/YY'));
 
-        $fields['note']     = array('type'=>'text',     'required'=>1, 'error'=>__('Reason for the update required'));
+        $fields['note']     = array('type'=>'text',     'required'=>1, 'error'=>__('A reason for the update is required'));
         $fields['user_id']  = array('type'=>'int',      'required'=>0, 'error'=>__('Invalid user-id'));
 
         if(!Validator::process($fields, $vars, $errors) && !$errors['err'])
@@ -2000,7 +2006,7 @@ class Ticket {
             if($this->isClosed())
                 $errors['duedate']=__('Due date can NOT be set on a closed ticket');
             elseif(!$vars['time'] || strpos($vars['time'],':')===false)
-                $errors['time']=__('Select time');
+                $errors['time']=__('Select a time from the list');
             elseif(strtotime($vars['duedate'].' '.$vars['time'])===false)
                 $errors['duedate']=__('Invalid due date');
             elseif(strtotime($vars['duedate'].' '.$vars['time'])<=time())
@@ -2027,9 +2033,9 @@ class Ticket {
             return false;
 
         if(!$vars['note'])
-            $vars['note']=sprintf(__('Ticket Updated by %s'), $thisstaff->getName());
+            $vars['note']=sprintf(_S('Ticket details updated by %s'), $thisstaff->getName());
 
-        $this->logNote(__('Ticket Updated'), $vars['note'], $thisstaff);
+        $this->logNote(_S('Ticket Updated'), $vars['note'], $thisstaff);
 
         // Decide if we need to keep the just selected SLA
         $keepSLA = ($this->getSLAId() != $vars['slaId']);
@@ -2229,8 +2235,8 @@ class Ticket {
             global $ost;
             $errors = array(
                 'errno' => 403,
-                'err' => 'This help desk is for use by authorized users only');
-            $ost->logWarning('Ticket Denied', $message, false);
+                'err' => __('This help desk is for use by authorized users only'));
+            $ost->logWarning(_S('Ticket Denied'), $message, false);
             return 0;
         };
 
@@ -2282,7 +2288,7 @@ class Ticket {
 
             //Make sure the email address is not banned
             if (TicketFilter::isBanned($vars['email'])) {
-                return $reject_ticket(sprintf(__('Banned email - %s'), $vars['email']));
+                return $reject_ticket(sprintf(_S('Banned email - %s'), $vars['email']));
             }
 
             //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL)
@@ -2293,8 +2299,8 @@ class Ticket {
                     && ($openTickets>=$cfg->getMaxOpenTickets()) ) {
 
                 $errors = array('err' => __("You've reached the maximum open tickets allowed."));
-                $ost->logWarning(sprintf(__('Ticket denied - %s'), $vars['email']),
-                        sprintf(__('Max open tickets (%1$d) reached for %2$s'),
+                $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']),
+                        sprintf(_S('Max open tickets (%1$d) reached for %2$s'),
                             $cfg->getMaxOpenTickets(), $vars['email']),
                         false);
 
@@ -2308,7 +2314,7 @@ class Ticket {
         if ($ticket_filter
                 && ($filter=$ticket_filter->shouldReject())) {
             return $reject_ticket(
-                sprintf(__('Ticket rejected (%s) by filter "%s"'),
+                sprintf(_S('Ticket rejected (%s) by filter "%s"'),
                     $vars['email'], $filter->getName()));
         }
 
@@ -2322,24 +2328,24 @@ class Ticket {
 
         $id=0;
         $fields=array();
-        $fields['message']  = array('type'=>'*',     'required'=>1, 'error'=>__('Message required'));
+        $fields['message']  = array('type'=>'*',     'required'=>1, 'error'=>__('Message content is required'));
         switch (strtolower($origin)) {
             case 'web':
-                $fields['topicId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Select help topic'));
+                $fields['topicId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Select a help topic'));
                 break;
             case 'staff':
-                $fields['deptId']   = array('type'=>'int',  'required'=>1, 'error'=>__('Department required'));
-                $fields['topicId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Topic required'));
-                $fields['duedate']  = array('type'=>'date', 'required'=>0, 'error'=>__('Invalid date - must be MM/DD/YY'));
+                $fields['deptId']   = array('type'=>'int',  'required'=>0, 'error'=>__('Department selection is required'));
+                $fields['topicId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Help topic selection is required'));
+                $fields['duedate']  = array('type'=>'date', 'required'=>0, 'error'=>__('Invalid date format - must be MM/DD/YY'));
             case 'api':
-                $fields['source']   = array('type'=>'string', 'required'=>1, 'error'=>__('Indicate source'));
+                $fields['source']   = array('type'=>'string', 'required'=>1, 'error'=>__('Indicate ticket source'));
                 break;
             case 'email':
-                $fields['emailId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Email unknown'));
+                $fields['emailId']  = array('type'=>'int',  'required'=>1, 'error'=>__('Unknown system email'));
                 break;
             default:
                 # TODO: Return error message
-                $errors['err']=$errors['origin'] = __('Invalid origin given');
+                $errors['err']=$errors['origin'] = __('Invalid ticket origin given');
         }
 
         if(!Validator::process($fields, $vars, $errors) && !$errors['err'])
@@ -2348,7 +2354,7 @@ class Ticket {
         //Make sure the due date is valid
         if($vars['duedate']) {
             if(!$vars['time'] || strpos($vars['time'],':')===false)
-                $errors['time']=__('Select time');
+                $errors['time']=__('Select a time from the list');
             elseif(strtotime($vars['duedate'].' '.$vars['time'])===false)
                 $errors['duedate']=__('Invalid due date');
             elseif(strtotime($vars['duedate'].' '.$vars['time'])<=time())
@@ -2375,7 +2381,7 @@ class Ticket {
                     // are still acceptable
                     if (!Organization::forDomain($domain)) {
                         return $reject_ticket(
-                            sprintf('Ticket rejected (%s) (unregistered client)',
+                            sprintf(_S('Ticket rejected (%s) (unregistered client)'),
                                 $vars['email']));
                     }
                 }
@@ -2383,7 +2389,7 @@ class Ticket {
                 $user_form = UserForm::getUserForm()->getForm($vars);
                 if (!$user_form->isValid($field_filter('user'))
                         || !($user=User::fromVars($user_form->getClean())))
-                    $errors['user'] = 'Incomplete client information';
+                    $errors['user'] = __('Incomplete client information');
             }
         }
 
@@ -2537,7 +2543,7 @@ class Ticket {
             //TODO: Can collaborators add others?
             if ($collabs) {
                 //TODO: Change EndUser to name of  user.
-                $ticket->logNote(sprintf('Collaborators for %s organization added',
+                $ticket->logNote(sprintf(_S('Collaborators for %s organization added'),
                         $org->getName()),
                     implode("<br>", $collabs), $org->getName(), false);
             }
@@ -2560,9 +2566,9 @@ class Ticket {
             // Auto assign staff or team - auto assignment based on filter
             // rules. Both team and staff can be assigned
             if ($vars['staffId'])
-                 $ticket->assignToStaff($vars['staffId'], __('Auto Assignment'));
+                 $ticket->assignToStaff($vars['staffId'], _S('Auto Assignment'));
             if ($vars['teamId'])
-                $ticket->assignToTeam($vars['teamId'], __('Auto Assignment'));
+                $ticket->assignToTeam($vars['teamId'], _S('Auto Assignment'));
         }
 
         /**********   double check auto-response  ************/
@@ -2619,15 +2625,15 @@ class Ticket {
         if(!$thisstaff || !$thisstaff->canCreateTickets()) return false;
 
         if($vars['source'] && !in_array(strtolower($vars['source']),array('email','phone','other')))
-            $errors['source']=sprintf(__('Invalid source - %s'),Format::htmlchars($vars['source']));
+            $errors['source']=sprintf(__('Invalid source given - %s'),Format::htmlchars($vars['source']));
 
         if (!$vars['uid']) {
             //Special validation required here
             if (!$vars['email'] || !Validator::is_email($vars['email']))
-                $errors['email'] = __('Valid email required');
+                $errors['email'] = __('Valid email address is required');
 
             if (!$vars['name'])
-                $errors['name'] = __('Name required');
+                $errors['name'] = __('Name is required');
         }
 
         if (!$thisstaff->canAssignTickets())
@@ -2656,12 +2662,12 @@ class Ticket {
 
         // Not assigned...save optional note if any
         if (!$vars['assignId'] && $vars['note']) {
-            $ticket->logNote(__('New Ticket'), $vars['note'], $thisstaff, false);
+            $ticket->logNote(_S('New Ticket'), $vars['note'], $thisstaff, false);
         }
         else {
             // Not assignment and no internal note - log activity
-            $ticket->logActivity(__('New Ticket by Staff'),
-                sprintf(__('Ticket created by staff - %s'), $thisstaff->getName()));
+            $ticket->logActivity(_S('New Ticket by Staff'),
+                sprintf(_S('Ticket created by staff - %s'), $thisstaff->getName()));
         }
 
         $ticket->reload();
@@ -2729,7 +2735,8 @@ class Ticket {
         if(($res=db_query($sql)) && db_num_rows($res)) {
             while(list($id)=db_fetch_row($res)) {
                 if(($ticket=Ticket::lookup($id)) && $ticket->markOverdue())
-                    $ticket->logActivity(__('Ticket Marked Overdue'), __('Ticket flagged as overdue by the system.'));
+                    $ticket->logActivity(_S('Ticket Marked Overdue'),
+                        _S('Ticket flagged as overdue by the system.'));
             }
         } else {
             //TODO: Trigger escalation on already overdue tickets - make sure last overdue event > grace_period.
diff --git a/include/class.topic.php b/include/class.topic.php
index cf9608148f9809b871cceb3cf19662657ccba644..6a616d1c794857f9164d34f6c8c1b6bcd3145721 100644
--- a/include/class.topic.php
+++ b/include/class.topic.php
@@ -304,17 +304,17 @@ class Topic {
         $vars['topic']=Format::striptags(trim($vars['topic']));
 
         if($id && $id!=$vars['id'])
-            $errors['err']=__('Internal error. Try again');
+            $errors['err']=__('Internal error occurred. Try again');
 
         if(!$vars['topic'])
-            $errors['topic']=__('Help topic required');
+            $errors['topic']=__('Help topic name is required');
         elseif(strlen($vars['topic'])<5)
-            $errors['topic']=__('Topic is too short. 5 chars minimum');
+            $errors['topic']=__('Topic is too short. Five characters minimum');
         elseif(($tid=self::getIdByName($vars['topic'], $vars['topic_pid'])) && $tid!=$id)
             $errors['topic']=__('Topic already exists');
 
         if (!is_numeric($vars['dept_id']))
-            $errors['dept_id']=__('You must select a department');
+            $errors['dept_id']=__('Department selection is required');
 
         if($errors) return false;
 
@@ -363,7 +363,7 @@ class Topic {
             if (db_query($sql) && ($id = db_insert_id()))
                 $rv = $id;
             else
-                $errors['err']=__('Unable to create the topic. Internal error');
+                $errors['err']=__('Unable to create the topic. Internal error occurred');
         }
         if (!$cfg || $cfg->getTopicSortMode() == 'a') {
             static::updateSortOrder();
diff --git a/include/class.upgrader.php b/include/class.upgrader.php
index a92420dd786c178c4efb9326f90e3685514838a8..3dad00b6a34e5ccc1a4bb27026f105aedf31b9ed 100644
--- a/include/class.upgrader.php
+++ b/include/class.upgrader.php
@@ -215,7 +215,7 @@ class StreamUpgrader extends SetupWizard {
     function onError($error) {
         global $ost, $thisstaff;
 
-        $subject = '['.$this->name.']: '.__('Upgrader Error');
+        $subject = '['.$this->name.']: '._S('Upgrader Error');
         $ost->logError($subject, $error);
         $this->setError($error);
         $this->upgrader->setState('aborted');
@@ -232,7 +232,8 @@ class StreamUpgrader extends SetupWizard {
         if($email) {
             $email->sendAlert($thisstaff->getEmail(), $subject, $error);
         } else {//no luck - try the system mail.
-            Mailer::sendmail($thisstaff->getEmail(), $subject, $error, sprintf(__('"osTicket Alerts"<%s>'), $thisstaff->getEmail()));
+            Mailer::sendmail($thisstaff->getEmail(), $subject, $error,
+                '"'._S('osTicket Alerts')."\" <{$thisstaff->getEmail()}>");
         }
 
     }
@@ -278,7 +279,7 @@ class StreamUpgrader extends SetupWizard {
 
     function getNextVersion() {
         if(!$patch=$this->getNextPatch())
-            return '(Latest)';
+            return __('(Latest)');
 
         $info = $this->readPatchInfo($patch);
         return $info['version'];
@@ -361,8 +362,8 @@ class StreamUpgrader extends SetupWizard {
             return false; //Nothing to do.
 
         $this->log(
-                sprintf(__('Upgrader - %s (task pending).'), $this->getShash()),
-                sprintf(__('The %s task reports there is work to do'),
+                sprintf(_S('Upgrader - %s (task pending).'), $this->getShash()),
+                sprintf(_S('The %s task reports there is work to do'),
                     get_class($task))
                 );
         if(!($max_time = ini_get('max_execution_time')))
@@ -405,11 +406,11 @@ class StreamUpgrader extends SetupWizard {
             $shash = substr($phash, 9, 8);
 
             //Log the patch info
-            $logMsg = sprintf(__("Patch %s applied successfully "), $phash);
+            $logMsg = sprintf(_S("Patch %s applied successfully "), $phash);
             if(($info = $this->readPatchInfo($patch)) && $info['version'])
                 $logMsg.= ' ('.$info['version'].') ';
 
-            $this->log(sprintf(__("Upgrader - %s applied"), $shash), $logMsg);
+            $this->log(sprintf(_S("Upgrader - %s applied"), $shash), $logMsg);
             $this->signature = $shash; //Update signature to the *new* HEAD
             $this->phash = $phash;
 
@@ -450,12 +451,12 @@ class StreamUpgrader extends SetupWizard {
 
         //We have a cleanup script  ::XXX: Don't abort on error?
         if($this->load_sql_file($file, $this->getTablePrefix(), false, true)) {
-            $this->log(sprintf(__("Upgrader - %s cleanup"), $this->phash),
-                sprintf(__("Applied cleanup script %s"), $file));
+            $this->log(sprintf(_S("Upgrader - %s cleanup"), $this->phash),
+                sprintf(_S("Applied cleanup script %s"), $file));
             return 0;
         }
 
-        $this->log(__('Upgrader'), sprintf(__("%s: Unable to process cleanup file"),
+        $this->log(_S('Upgrader'), sprintf(_S("%s: Unable to process cleanup file"),
                         $this->phash));
         return 0;
     }
diff --git a/include/class.user.php b/include/class.user.php
index d15b5d424d03f4a1d01301ba4640dca2915a20d1..d7f56c42e0a9bfda542e351fe21dc5834f8328c4 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -198,7 +198,7 @@ class User extends UserModel {
         if (($field=$form->getField('email'))
                 && $field->getClean()
                 && User::lookup(array('emails__address'=>$field->getClean()))) {
-            $field->addError('Email is assigned to another user');
+            $field->addError(__('Email is assigned to another user'));
             $valid = false;
         }
 
@@ -335,7 +335,7 @@ class User extends UserModel {
     function getAccountStatus() {
 
         if (!($account=$this->getAccount()))
-            return 'Guest';
+            return __('Guest');
 
         return (string) $account->getStatus();
     }
@@ -351,7 +351,7 @@ class User extends UserModel {
 
     static function importCsv($stream, $defaults=array()) {
         //Read the header (if any)
-        $headers = array('name' => 'Full Name', 'email' => 'Email Address');
+        $headers = array('name' => __('Full Name'), 'email' => __('Email Address'));
         $uform = UserForm::getUserForm();
         $all_fields = $uform->getFields();
         $named_fields = array();
@@ -361,7 +361,7 @@ class User extends UserModel {
                 $named_fields[] = $f;
 
         if (!($data = fgetcsv($stream, 1000, ",")))
-            return 'Whoops. Perhaps you meant to send some CSV records';
+            return __('Whoops. Perhaps you meant to send some CSV records');
 
         if (Validator::is_email($data[1])) {
             $has_header = false; // We don't have an header!
@@ -375,7 +375,8 @@ class User extends UserModel {
                             mb_strtolower($f->get('name')), mb_strtolower($f->get('label'))))) {
                         $found = true;
                         if (!$f->get('name'))
-                            return $h.': Field must have `variable` set to be imported';
+                            return sprintf(__(
+                                '%s: Field must have `variable` set to be imported'), $h);
                         $headers[$f->get('name')] = $f->get('label');
                         break;
                     }
@@ -391,7 +392,7 @@ class User extends UserModel {
                         break;
                     }
                     else {
-                        return $h.': Unable to map header to a user field';
+                        return sprintf(__('%s: Unable to map header to a user field'), $h);
                     }
                 }
             }
@@ -399,7 +400,7 @@ class User extends UserModel {
 
         // 'name' and 'email' MUST be in the headers
         if (!isset($headers['name']) || !isset($headers['email']))
-            return 'CSV file must include `name` and `email` columns';
+            return __('CSV file must include `name` and `email` columns');
 
         if (!$has_header)
             fseek($stream, 0);
@@ -426,14 +427,17 @@ class User extends UserModel {
                 // Skip empty rows
                 continue;
             elseif (count($data) != count($headers))
-                return 'Bad data. Expected: '.implode(', ', $headers);
+                return sprintf(__('Bad data. Expected: %s'), implode(', ', $headers));
             // Validate according to field configuration
             $i = 0;
             foreach ($headers as $h => $label) {
                 $f = $fields[$h];
                 $T = $f->parse($data[$i]);
                 if ($f->validateEntry($T) && $f->errors())
-                    return $label.': Invalid data: '.implode(', ', $f->errors());
+                    return sprintf(__(
+                        /* 1 will be a field label, and 2 will be error messages */
+                        '%1$s: Invalid data: %2$s'),
+                        $label, implode(', ', $f->errors()));
                 // Convert to database format
                 $data[$i] = $f->to_database($T);
                 $i++;
@@ -448,7 +452,8 @@ class User extends UserModel {
         foreach ($users as $u) {
             $vars = array_combine($keys, $u);
             if (!static::fromVars($vars))
-                return 'Unable to import user: '.print_r($vars, true);
+                return sprintf(__('Unable to import user: %s'),
+                    print_r($vars, true));
         }
 
         return count($users);
@@ -464,7 +469,7 @@ class User extends UserModel {
             rewind($stream);
         }
         else {
-            return 'Unable to parse submitted users';
+            return __('Unable to parse submitted users');
         }
 
         return User::importCsv($stream, $extra);
@@ -484,7 +489,7 @@ class User extends UserModel {
                         && ($u=User::lookup(array('emails__address'=>$f->getClean())))
                         && $u->id != $this->getId()) {
                 $valid = false;
-                $f->addError('Email is assigned to another user');
+                $f->addError(__('Email is assigned to another user'));
             }
         }
 
@@ -567,16 +572,16 @@ class PersonsName {
     var $name;
 
     static $formats = array(
-        'first' => array("First", 'getFirst'),
-        'last' => array("Last", 'getLast'),
-        'full' => array("First Last", 'getFull'),
-        'legal' => array("First M. Last", 'getLegal'),
-        'lastfirst' => array("Last, First", 'getLastFirst'),
-        'formal' => array("Mr. Last", 'getFormal'),
-        'short' => array("First L.", 'getShort'),
-        'shortformal' => array("F. Last", 'getShortFormal'),
-        'complete' => array("Mr. First M. Last Sr.", 'getComplete'),
-        'original' => array('-- As Entered --', 'getOriginal'),
+        'first' => array(     /*trans*/ "First", 'getFirst'),
+        'last' => array(      /*trans*/ "Last", 'getLast'),
+        'full' => array(      /*trans*/ "First Last", 'getFull'),
+        'legal' => array(     /*trans*/ "First M. Last", 'getLegal'),
+        'lastfirst' => array( /*trans*/ "Last, First", 'getLastFirst'),
+        'formal' => array(    /*trans*/ "Mr. Last", 'getFormal'),
+        'short' => array(     /*trans*/ "First L.", 'getShort'),
+        'shortformal' => array(/*trans*/ "F. Last", 'getShortFormal'),
+        'complete' => array(  /*trans*/ "Mr. First M. Last Sr.", 'getComplete'),
+        'original' => array(  /*trans*/ '-- As Entered --', 'getOriginal'),
     );
 
     function __construct($name, $format=null) {
@@ -863,7 +868,8 @@ class UserAccount extends UserAccountModel {
         $content = Page::lookup(Page::getIdByType($template));
 
         if (!$email ||  !$content)
-            return new Error($template.': Unable to retrieve template');
+            return new Error(sprintf(_S('%s: Unable to retrieve template'),
+                $template));
 
         $vars = array(
             'url' => $ost->getConfig()->getBaseUrl(),
@@ -906,23 +912,23 @@ class UserAccount extends UserAccountModel {
 
 
         if (!$thisstaff) {
-            $errors['err'] = 'Access Denied';
+            $errors['err'] = __('Access Denied');
             return false;
         }
 
         // TODO: Make sure the username is unique
 
         if (!$vars['timezone_id'])
-            $errors['timezone_id'] = 'Time zone required';
+            $errors['timezone_id'] = __('Time zone selection is required');
 
         // Changing password?
         if ($vars['passwd1'] || $vars['passwd2']) {
             if (!$vars['passwd1'])
-                $errors['passwd1'] = 'New password required';
+                $errors['passwd1'] = __('New password is required');
             elseif ($vars['passwd1'] && strlen($vars['passwd1'])<6)
-                $errors['passwd1'] = 'Must be at least 6 characters';
+                $errors['passwd1'] = __('Must be at least 6 characters');
             elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
-                $errors['passwd2'] = 'Password(s) do not match';
+                $errors['passwd2'] = __('Passwords do not match');
         }
 
         if ($errors) return false;
@@ -983,11 +989,11 @@ class UserAccount extends UserAccountModel {
         if ((!$vars['backend'] || $vars['backend'] != 'client')
                 && !isset($vars['sendemail'])) {
             if (!$vars['passwd1'])
-                $errors['passwd1'] = 'Temp. password required';
+                $errors['passwd1'] = 'Temporary password required';
             elseif ($vars['passwd1'] && strlen($vars['passwd1'])<6)
                 $errors['passwd1'] = 'Must be at least 6 characters';
             elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
-                $errors['passwd2'] = 'Password(s) do not match';
+                $errors['passwd2'] = 'Passwords do not match';
         }
 
         if ($errors) return false;
@@ -1054,14 +1060,14 @@ class UserAccountStatus {
     function __toString() {
 
         if ($this->isLocked())
-            return 'Locked (Administrative)';
+            return __('Locked (Administrative)');
 
         if (!$this->isConfirmed())
-            return 'Locked (Pending Activation)';
+            return __('Locked (Pending Activation)');
 
         // ... Other flags here (password reset, etc).
 
-        return 'Active (Registered)';
+        return __('Active (Registered)');
     }
 }
 
diff --git a/include/class.validator.php b/include/class.validator.php
index 1c46373d1b3aad3ddc1d847961e4d759b28ca911..c14f910743f85b72be0ab65b97af64c48354ffb3 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -112,7 +112,7 @@ class Validator {
                 break;
             case 'password':
                 if(strlen($this->input[$k])<5)
-                    $this->errors[$k]=$field['error'].' (5 chars min)';
+                    $this->errors[$k]=$field['error'].' '.__('(Five characters min)');
                 break;
             case 'username':
                 $error = '';
@@ -191,9 +191,9 @@ class Validator {
 
     function is_username($username, &$error='') {
         if (strlen($username)<2)
-            $error = 'At least two (2) characters';
+            $error = __('Username must have at least two (2) characters');
         elseif (!preg_match('/^[\p{L}\d._-]+$/u', $username))
-            $error = 'Username contains invalid characters';
+            $error = __('Username contains invalid characters');
         return $error == '';
     }
 
diff --git a/include/class.variable.php b/include/class.variable.php
index 00777077daf26edb2bdbd479f921dc36619d9b5e..41bcb619e5587ddce96dce8bdb16d1e5aec7994b 100644
--- a/include/class.variable.php
+++ b/include/class.variable.php
@@ -116,7 +116,7 @@ class VariableReplacer {
             return $this->variables[$parts[0]];
 
         //Unknown object or variable - leavig it alone.
-        $this->setError(sprintf(__('Unknown obj for "%s" tag '), $var));
+        $this->setError(sprintf(__('Unknown object for "%s" tag'), $var));
         return false;
     }
 
diff --git a/include/client/accesslink.inc.php b/include/client/accesslink.inc.php
index f40eb7efc236f2cb05fb091913144ca985385787..44c2135af16dd98836c4a96e42fc1c2ec9561b60 100644
--- a/include/client/accesslink.inc.php
+++ b/include/client/accesslink.inc.php
@@ -5,13 +5,18 @@ $email=Format::input($_POST['lemail']?$_POST['lemail']:$_GET['e']);
 $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']);
 
 if ($cfg->isClientEmailVerificationRequired())
-    $button = "Email Access Link";
+    $button = __("Email Access Link");
 else
-    $button = "View Ticket";
+    $button = __("View Ticket");
 ?>
-<h1>Check Ticket Status</h1>
-<p>Please provide us with your email address and a ticket number, and an access
-link will be emailed to you.</p>
+<h1><?php echo __('Check Ticket Status'); ?></h1>
+<p><?php
+echo __('Please provide your email address and a ticket number.');
+if ($cfg->isClientEmailVerificationRequired())
+    echo ' '.__('An access link will be emailed to you.');
+else
+    echo ' '.__('This will sign you in to view your ticket.');
+?></p>
 <form action="login.php" method="post" id="clientLogin">
     <?php csrf_token(); ?>
 <div style="display:table-row">
@@ -19,13 +24,13 @@ link will be emailed to you.</p>
     <strong><?php echo Format::htmlchars($errors['login']); ?></strong>
     <br>
     <div>
-        <label for="email">E-Mail Address:
-        <input id="email" placeholder="e.g. john.doe@osticket.com" type="text"
+        <label for="email"><?php echo __('E-Mail Address'); ?>:
+        <input id="email" placeholder="<?php echo __('e.g. john.doe@osticket.com'); ?>" type="text"
             name="lemail" size="30" value="<?php echo $email; ?>"></label>
     </div>
     <div>
-        <label for="ticketno">Ticket Number:</label><br/>
-        <input id="ticketno" type="text" name="lticket" placeholder="e.g. 051243"
+        <label for="ticketno"><?php echo __('Ticket Number'); ?>:</label><br/>
+        <input id="ticketno" type="text" name="lticket" placeholder="<?php echo __('e.g. 051243'); ?>"
             size="30" value="<?php echo $ticketid; ?>"></td>
     </div>
     <p>
@@ -34,17 +39,19 @@ link will be emailed to you.</p>
     </div>
     <div style="display:table-cell;padding-left: 2em;padding-right:90px;">
 <?php if ($cfg && $cfg->getClientRegistrationMode() !== 'disabled') { ?>
-        Have an account with us?
-        <a href="login.php">Sign In</a> <?php
+        <?pho echo __('Have an account with us?'); ?>
+        <a href="login.php"><?php echo __('Sign In'); ?></a> <?php
     if ($cfg->isClientRegistrationEnabled()) { ?>
-        or <a href="account.php?do=create">register for an account</a> <?php
-    } ?> to access all your tickets.
-<?php
-} ?>
+<?php echo sprintf(__('or %s register for an account %s to access all your tickets.'),
+    '<a href="account.php?do=create">','</a>');
+    }
+}?>
     </div>
 </div>
 </form>
 <br>
 <p>
-If this is your first time contacting us or you've lost the ticket number, please <a href="open.php">open a new ticket</a>.
+<?php echo sprintf(
+__("If this is your first time contacting us or you've lost the ticket number, please %s open a new ticket %s"),
+    '<a href="open.php">','</a>'); ?>
 </p>
diff --git a/include/client/edit.inc.php b/include/client/edit.inc.php
index e01b2df4938ecde09b38b2db5747cb54d78d85f4..6f364db394f3acaff7c52557764108802578b63e 100644
--- a/include/client/edit.inc.php
+++ b/include/client/edit.inc.php
@@ -5,7 +5,7 @@ if(!defined('OSTCLIENTINC') || !$thisclient || !$ticket || !$ticket->checkUserAc
 ?>
 
 <h1>
-    Editing Ticket #<?php echo $ticket->getNumber(); ?>
+    <?php echo sprintf(__('Editing Ticket #%s'), $ticket->getNumber()); ?>
 </h1>
 
 <form action="tickets.php" method="post">
diff --git a/include/client/faq-category.inc.php b/include/client/faq-category.inc.php
index 01ee2689cc5ceb4a974d842821b9c9f85c50fc6b..5a17e2176b75349d231bf22a00f50c02f39d88c3 100644
--- a/include/client/faq-category.inc.php
+++ b/include/client/faq-category.inc.php
@@ -29,6 +29,6 @@ if(($res=db_query($sql)) && db_num_rows($res)) {
          </div>
          <p><a class="back" href="index.php">&laquo; '.__('Go Back').'</a></p>';
 }else {
-    echo '<strong>'.__('Category does not have any FAQs.').' <a href="index.php">'.__('Back To Index').'</a></strong>';
+    echo '<strong>'.__('This category does not have any FAQs.').' <a href="index.php">'.__('Back To Index').'</a></strong>';
 }
 ?>
diff --git a/include/client/footer.inc.php b/include/client/footer.inc.php
index 9f38d4110999de32142f02e5e64d209fabb4e78f..45588e7c22aa61fa6f2257c80f25b7bfc55acf86 100644
--- a/include/client/footer.inc.php
+++ b/include/client/footer.inc.php
@@ -2,7 +2,7 @@
     </div>
     <div id="footer">
         <p>Copyright &copy; <?php echo date('Y'); ?> <?php echo (string) $ost->company ?: 'osTicket.com'; ?> - All rights reserved.</p>
-        <a id="poweredBy" href="http://osticket.com" target="_blank"><?php echo _('Helpdesk software - powered by osTicket'); ?></a>
+        <a id="poweredBy" href="http://osticket.com" target="_blank"><?php echo __('Helpdesk software - powered by osTicket'); ?></a>
     </div>
 <div id="overlay"></div>
 <div id="loading">
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index 8427b45b3e4f7561fefd7febaa38b57c2d0a70de..086ff99d8af06c40faae54336fbf9eb8b34aa633 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -1,5 +1,6 @@
 <?php
-$title=($cfg && is_object($cfg) && $cfg->getTitle())?$cfg->getTitle():'osTicket :: Support Ticket System';
+$title=($cfg && is_object($cfg) && $cfg->getTitle())
+    ? $cfg->getTitle() : 'osTicket :: '.__('Support Ticket System');
 $signin_url = ROOT_PATH . "login.php"
     . ($thisclient ? "?e=".urlencode($thisclient->getEmail()) : "");
 $signout_url = ROOT_PATH . "logout.php?auth=".$ost->getLinkToken();
@@ -42,7 +43,8 @@ header("Content-Type: text/html; charset=UTF-8\r\n");
     <div id="container">
         <div id="header">
             <a id="logo" href="<?php echo ROOT_PATH; ?>index.php"
-            title="Support Center"><img src="<?php echo ROOT_PATH; ?>logo.php" border=0 alt="<?php
+            title="<?php echo __('Support Center'); ?>"><img src="<?php
+                echo ROOT_PATH; ?>logo.php" border=0 alt="<?php
                 echo $ost->getConfig()->getTitle(); ?>"
                 style="height: 5em"></a>
             <p>
diff --git a/include/client/login.inc.php b/include/client/login.inc.php
index 654f6e18f858420e5f3f8bf64162b630b3cda2c3..263d74e661ea0a691012de12b4635b88c22a27a6 100644
--- a/include/client/login.inc.php
+++ b/include/client/login.inc.php
@@ -50,11 +50,11 @@ if (count($ext_bks)) {
 }
 if ($cfg && $cfg->isClientRegistrationEnabled()) {
     if (count($ext_bks)) echo '<hr style="width:70%"/>'; ?>
-    <?php echo _('Not yet registered?'); ?> <a href="account.php?do=create"><?php echo _('Create an account'); ?></a>
+    <?php echo __('Not yet registered?'); ?> <a href="account.php?do=create"><?php echo __('Create an account'); ?></a>
     <br/>
     <div style="margin-top: 5px;">
-    <b><?php echo _("I'm an agent"); ?></b> —
-    <a href="<?php echo ROOT_PATH; ?>scp"><?php echo _('sign in here'); ?></a>
+    <b><?php echo __("I'm an agent"); ?></b> —
+    <a href="<?php echo ROOT_PATH; ?>scp"><?php echo __('sign in here'); ?></a>
     </div>
 <?php } ?>
     </div>
@@ -63,7 +63,7 @@ if ($cfg && $cfg->isClientRegistrationEnabled()) {
 <br>
 <p>
 <?php if ($cfg && !$cfg->isClientLoginRequired()) {
-    echo sprintf(__('If this is your first time contacting us or you\'ve lost the ticket number, please %1$s open a new ticket %2$s'),
+    echo sprintf(__('If this is your first time contacting us or you\'ve lost the ticket number, please %s open a new ticket %s'),
         '<a href="open.php">', '</a>');
 } ?>
 </p>
diff --git a/include/client/profile.inc.php b/include/client/profile.inc.php
index 8586c3976f1a117c4887b44670e905c1ee073b8f..f500e1cb935e0a05a835793c3c22a9fc44b37a4e 100644
--- a/include/client/profile.inc.php
+++ b/include/client/profile.inc.php
@@ -1,10 +1,7 @@
-<?php
-
-?>
-<h1>Manage Your Profile Information</h1>
-<p>
-Use the forms below to update the information we have on file for your
-account
+<h1><?php echo __('Manage Your Profile Information'); ?></h1>
+<p><?php echo __(
+'Use the forms below to update the information we have on file for your account'
+); ?>
 </p>
 <form action="profile.php" method="post">
   <?php csrf_token(); ?>
@@ -19,14 +16,14 @@ if ($acct = $thisclient->getAccount()) {
 ?>
 <tr>
     <td colspan="2">
-        <div><hr><h3>Preferences</h3>
+        <div><hr><h3><?php echo __('Preferences'); ?></h3>
         </div>
     </td>
 </tr>
-    <td>Time Zone:</td>
+    <td><?php echo __('Time Zone'); ?>:</td>
     <td>
         <select name="timezone_id" id="timezone_id">
-            <option value="0">&mdash; Select Time Zone &mdash;</option>
+            <option value="0">&mdash; <?php echo __('Select Time Zone'); ?> &mdash;</option>
             <?php
             $sql='SELECT id, offset,timezone FROM '.TIMEZONE_TABLE.' ORDER BY id';
             if(($res=db_query($sql)) && db_num_rows($res)){
@@ -42,24 +39,25 @@ if ($acct = $thisclient->getAccount()) {
 </tr>
 <tr>
     <td width="180">
-       Daylight Saving:
+        <?php echo __('Daylight Saving') ?>:
     </td>
     <td>
         <input type="checkbox" name="dst" value="1" <?php echo $info['dst']?'checked="checked"':''; ?>>
-        Observe daylight saving
-        <em>(Current Time: <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['dst']); ?></strong>)</em>
+        <?php echo __('Observe daylight saving'); ?>
+        <em>(<?php __('Current Time'); ?>:
+            <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['dst']); ?></strong>)</em>
     </td>
 </tr>
 <?php if ($acct->isPasswdResetEnabled()) { ?>
 <tr>
     <td colspan=2">
-        <div><hr><h3>Access Credentials</h3></div>
+        <div><hr><h3><?php echo __('Access Credentials'); ?></h3></div>
     </td>
 </tr>
 <?php if (!isset($_SESSION['_client']['reset-token'])) { ?>
 <tr>
     <td width="180">
-        Current Password:
+        <?php echo __('Current Password'); ?>:
     </td>
     <td>
         <input type="password" size="18" name="cpasswd" value="<?php echo $info['cpasswd']; ?>">
@@ -69,7 +67,7 @@ if ($acct = $thisclient->getAccount()) {
 <?php } ?>
 <tr>
     <td width="180">
-        New Password:
+        <?php echo __('New Password'); ?>:
     </td>
     <td>
         <input type="password" size="18" name="passwd1" value="<?php echo $info['passwd1']; ?>">
@@ -78,7 +76,7 @@ if ($acct = $thisclient->getAccount()) {
 </tr>
 <tr>
     <td width="180">
-        Confirm New Password:
+        <?php echo __('Confirm New Password'); ?>:
     </td>
     <td>
         <input type="password" size="18" name="passwd2" value="<?php echo $info['passwd2']; ?>">
diff --git a/include/client/pwreset.login.php b/include/client/pwreset.login.php
index c2bc7e39935259b38c560bf1ccd9ee34a05c6ee1..f30be3d59472fece4c1276a99275240b47d52090 100644
--- a/include/client/pwreset.login.php
+++ b/include/client/pwreset.login.php
@@ -3,11 +3,10 @@ if(!defined('OSTCLIENTINC')) die('Access Denied');
 
 $userid=Format::input($_POST['userid']);
 ?>
-<h1>Forgot My Password</h1>
-<p>
-Enter your username or email address again in the form below and press the
-<strong>Login</strong> to access your account and reset your password.
-
+<h1><?php echo __('Forgot My Password'); ?></h1>
+<p><?php echo __(
+'Enter your username or email address again in the form below and press the <strong>Login</strong> to access your account and reset your password.');
+?>
 <form action="pwreset.php" method="post" id="clientLogin">
     <div style="width:50%;display:inline-block">
     <?php csrf_token(); ?>
@@ -16,7 +15,7 @@ Enter your username or email address again in the form below and press the
     <strong><?php echo Format::htmlchars($banner); ?></strong>
     <br>
     <div>
-        <label for="username">Username:</label>
+        <label for="username"><?php echo __('Username'); ?>:</label>
         <input id="username" type="text" name="userid" size="30" value="<?php echo $userid; ?>">
     </div>
     <p>
diff --git a/include/client/pwreset.request.php b/include/client/pwreset.request.php
index 28922c8d2a9d6028ab18ec533ea7be9873c847ec..94d59360c2742b1c93250ef92c5fdcf302e174f4 100644
--- a/include/client/pwreset.request.php
+++ b/include/client/pwreset.request.php
@@ -3,11 +3,10 @@ if(!defined('OSTCLIENTINC')) die('Access Denied');
 
 $userid=Format::input($_POST['userid']);
 ?>
-<h1>Forgot My Password</h1>
-<p>
-Enter your username or email address in the form below and press the
-<strong>Send Email</strong> button to have a password reset link sent to
-your email account on file.
+<h1><?php echo __('Forgot My Password'); ?></h1>
+<p><?php echo __(
+'Enter your username or email address in the form below and press the <strong>Send Email</strong> button to have a password reset link sent to your email account on file.');
+?>
 
 <form action="pwreset.php" method="post" id="clientLogin">
     <div style="width:50%;display:inline-block">
@@ -16,7 +15,7 @@ your email account on file.
     <strong><?php echo Format::htmlchars($banner); ?></strong>
     <br>
     <div>
-        <label for="username">Username:</label>
+        <label for="username"><?php echo __('Username'); ?>:</label>
         <input id="username" type="text" name="userid" size="30" value="<?php echo $userid; ?>">
     </div>
     <p>
diff --git a/include/client/pwreset.sent.php b/include/client/pwreset.sent.php
index c76f50957ecc56ec8a2946a26d729e364d332968..91c4720bceeda0ed5f4d0229156b3ee04497d8ea 100644
--- a/include/client/pwreset.sent.php
+++ b/include/client/pwreset.sent.php
@@ -1,13 +1,11 @@
-<h1>Forgot My Password</h1>
-<p>
-Enter your username or email address in the form below and press the
-<strong>Send Email</strong> button to have a password reset link sent to
-your email account on file.
+<h1><?php echo __('Forgot My Password'); ?></h1>
+<p><?php echo __(
+'Enter your username or email address in the form below and press the <strong>Send Email</strong> button to have a password reset link sent to your email account on file.');
+?>
 
 <form action="pwreset.php" method="post" id="clientLogin">
-    <div style="width:50%;display:inline-block">
-    We have sent you a reset email to the email address you have on file for
-    your account. If you do not receive the email or cannot reset your
-    password, please ...
+<div style="width:50%;display:inline-block"><?php echo __(
+    'We have sent you a reset email to the email address you have on file for your account. If you do not receive the email or cannot reset your password, please submit a ticket to have your account unlocked.'
+); ?>
     </div>
 </form>
diff --git a/include/client/register.confirm.inc.php b/include/client/register.confirm.inc.php
index a0628c0bcd287ed760cc95d48b44f8b1dae380bd..daa7e9a05311f794e941a496889c14d6f1572574 100644
--- a/include/client/register.confirm.inc.php
+++ b/include/client/register.confirm.inc.php
@@ -6,12 +6,12 @@
 echo Format::display($body); ?>
 </p>
 <?php } else { ?>
-<h1>Account Registration</h1>
+<h1><?php echo __('Account Registration'); ?></h1>
 <p>
-<strong>Thanks for registering for an account.</strong>
+<strong><?php echo __('Thanks for registering for an account.'); ?></strong>
 </p>
-<p>
-We've just sent you an email to the address you entered. Please follow the
-link in the email to confirm your account and gain access to your tickets.
+<p><?php echo __(
+"We've just sent you an email to the address you entered. Please follow the link in the email to confirm your account and gain access to your tickets."
+); ?>
 </p>
 <?php } ?>
diff --git a/include/client/register.confirmed.inc.php b/include/client/register.confirmed.inc.php
index 5bba31e8c539699fa2834be37c03a86a3cca30e6..5c68718c7a1e4c2f6aa019a085644de5c05b9670 100644
--- a/include/client/register.confirmed.inc.php
+++ b/include/client/register.confirmed.inc.php
@@ -6,13 +6,13 @@
 echo Format::display($body); ?>
 </p>
 <?php } else { ?>
-<h1>Account Registration</h1>
+<h1><?php echo __('Account Registration'); ?></h1>
 <p>
-<strong>Thanks for registering for an account.</strong>
+<strong><?php echo __('Thanks for registering for an account.'); ?></strong>
 </p>
-<p>
-You've confirmed your email address and successfully activated your account.
-You may proceed to check on previously opened tickets or open a new ticket.
+<p><?php echo __(
+"You've confirmed your email address and successfully activated your account.  You may proceed to check on previously opened tickets or open a new ticket."
+); ?>
 </p>
-<p><em>Your friendly support center</em></p>
+<p><em><?php echo __('Your friendly support center'); ?></em></p>
 <?php } ?>
diff --git a/include/client/register.inc.php b/include/client/register.inc.php
index 9c43bdf0542d4c442f8960d9b813150b4819c8dc..44f9fa22b5c3508228b74cad971e411c8c90aa0c 100644
--- a/include/client/register.inc.php
+++ b/include/client/register.inc.php
@@ -16,10 +16,10 @@ if (isset($user) && $user instanceof ClientCreateRequest) {
 $info = Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
-<h1>Account Registration</h1>
-<p>
-Use the forms below to create or update the information we have on file for
-your account
+<h1><?php echo __('Account Registration'); ?></h1>
+<p><?php echo __(
+'Use the forms below to create or update the information we have on file for your account'
+); ?>
 </p>
 <form action="account.php" method="post">
   <?php csrf_token(); ?>
@@ -33,11 +33,11 @@ your account
 ?>
 <tr>
     <td colspan="2">
-        <div><hr><h3>Preferences</h3>
+        <div><hr><h3><?php echo __('Preferences'); ?></h3>
         </div>
     </td>
 </tr>
-    <td>Time Zone:</td>
+    <td><?php echo __('Time Zone'); ?>:</td>
     <td>
         <select name="timezone_id" id="timezone_id">
             <?php
@@ -55,23 +55,24 @@ your account
 </tr>
 <tr>
     <td width="180">
-       Daylight Saving:
+        <?php echo __('Daylight Saving'); ?>:
     </td>
     <td>
         <input type="checkbox" name="dst" value="1" <?php echo $info['dst']?'checked="checked"':''; ?>>
-        Observe daylight saving
-        <em>(Current Time: <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['dst']); ?></strong>)</em>
+        <?php echo __('Observe daylight saving'); ?>
+        <em>(<?php echo __('Current Time'); ?>:
+            <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['dst']); ?></strong>)</em>
     </td>
 </tr>
 <tr>
     <td colspan=2">
-        <div><hr><h3>Access Credentials</h3></div>
+        <div><hr><h3><?php echo __('Access Credentials'); ?></h3></div>
     </td>
 </tr>
 <?php if ($info['backend']) { ?>
 <tr>
     <td width="180">
-        Login With:
+        <?php echo __('Login With'); ?>:
     </td>
     <td>
         <input type="hidden" name="backend" value="<?php echo $info['backend']; ?>"/>
@@ -87,7 +88,7 @@ your account
 <?php } else { ?>
 <tr>
     <td width="180">
-        Create a Password:
+        <?php echo __('Create a Password'); ?>:
     </td>
     <td>
         <input type="password" size="18" name="passwd1" value="<?php echo $info['passwd1']; ?>">
@@ -96,7 +97,7 @@ your account
 </tr>
 <tr>
     <td width="180">
-        Confirm New Password:
+        <?php echo __('Confirm New Password'); ?>:
     </td>
     <td>
         <input type="password" size="18" name="passwd2" value="<?php echo $info['passwd2']; ?>">
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index 320c17f01296f48cfdf900c3f53f3dd0d9b46b50..60d94cbc784dccedfe5e3f5bf72b72bff0790470 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -13,12 +13,13 @@ if ($thisclient && $thisclient->isGuest()
 
 <div id="msg_info">
     <i class="icon-compass icon-2x pull-left"></i>
-    <strong>Looking for your other tickets?</strong></br>
+    <strong><?php echo __('Looking for your other tickets?'); ?></strong></br>
     <a href="<?php echo ROOT_PATH; ?>login.php?e=<?php
         echo urlencode($thisclient->getEmail());
-        ?>" style="text-decoration:underline">Sign in</a> or
-    <a href="account.php?do=create" style="text-decoration:underline">register for an account</a>
-    for the best experience on our help desk.</div>
+    ?>" style="text-decoration:underline"><?php echo __('Sign In'); ?></a> or
+    <?php echo sprintf(__('or %s register for an account %s for the best experience on our help desk.'),
+        '<a href="account.php?do=create" style="text-decoration:underline">','</a>'); ?>
+    </div>
 
 <?php } ?>
 
@@ -171,7 +172,7 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) {
                 if($ticket->isClosed()) {
                     $msg='<b>'.__('Ticket will be reopened on message post').'</b>';
                 } else {
-                    $msg=__('To best assist you, please be specific and detailed');
+                    $msg=__('To best assist you, we request that you be specific and detailed');
                 }
                 ?>
                 <span id="msg"><em><?php echo $msg; ?> </em></span><font class="error">*&nbsp;<?php echo $errors['message']; ?></font>
diff --git a/kb/file.php b/kb/file.php
index b06b256a35a6ebdd9c40137f9fec0b6a2f797343..bdd59b528163bca041e521b7c3651c2e4dced03d 100644
--- a/kb/file.php
+++ b/kb/file.php
@@ -1,9 +1,9 @@
 <?php
 /*********************************************************************
     file.php
-    
+
     Simply downloads the file...on hash validation as follows;
-    
+
     * Hash must be 64 chars long.
     * First 32 chars is the perm. file hash
     * Next 32 chars  is md5(file_id.session_id().file_hash)
@@ -24,7 +24,7 @@ $h=trim($_GET['h']);
 if(!$h  || strlen($h)!=64  //32*2
         || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
         || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    die('Unknown or invalid file. #'.Format::htmlchars($_GET['h']));
+    die(__('Unknown or invalid attachment'));
 
 $file->download();
 ?>
diff --git a/l.php b/l.php
index b6a47ff84cdd95ed8501556cc75a8f73b63a2258..a0520a8cbba31e26cd743e3e9546aebd329e0131 100644
--- a/l.php
+++ b/l.php
@@ -18,11 +18,11 @@ require 'secure.inc.php';
 
 # PHP < 5.4.7 will not handle a URL like //host.tld/path correctly
 if (!($url=trim($_GET['url'])))
-    Http::response(422, 'Invalid URL');
+    Http::response(422, __('Invalid URL'));
 
 $check = (strpos($url, '//') === 0) ? 'http:' . $url : $url;
 if (!Validator::is_url($check) || !$ost->validateLinkToken($_GET['auth']))
-    Http::response(403, 'URL link not authorized');
+    Http::response(403, __('URL link not authorized'));
 elseif (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false)
     Http::redirect($url);
 ?>
diff --git a/login.php b/login.php
index 9b3d42a876cbf5891a6ca9dd8e43b1244eaaac79..9e3c550ad1b92a749c90a57bf8cbc41820317b52 100644
--- a/login.php
+++ b/login.php
@@ -33,7 +33,7 @@ else
 $suggest_pwreset = false;
 if ($_POST && isset($_POST['luser'])) {
     if (!$_POST['luser'])
-        $errors['err'] = 'Valid username or email address is required';
+        $errors['err'] = __('Valid username or email address is required');
     elseif (($user = UserAuthenticationBackend::process($_POST['luser'],
             $_POST['lpasswd'], $errors))) {
         if ($user instanceof ClientCreateRequest) {
@@ -105,7 +105,7 @@ elseif ($user = UserAuthenticationBackend::processSignOn($errors, false)) {
             $inc = 'register.inc.php';
         }
         else {
-            $errors['err'] = _('Access Denied. Contact your help desk administrator to have an account registered for you');
+            $errors['err'] = __('Access Denied. Contact your help desk administrator to have an account registered for you');
             // fall through to show login page again
         }
     }
diff --git a/pages/index.php b/pages/index.php
index f646858352e9cb8e34b16300f9e6713b6930f392..ab50a1c586d5793301fdcb0246842c31eba95ec2 100644
--- a/pages/index.php
+++ b/pages/index.php
@@ -41,10 +41,10 @@ while (list($id, $name) = db_fetch_row($res)) {
 }
 
 if (!$page_id || !($page = Page::lookup($page_id)))
-    Http::response(404, 'Page Not Found');
+    Http::response(404, __('Page Not Found'));
 
 if (!$page->isActive() || $page->getType() != 'other')
-    Http::response(404, 'Page Not Found');
+    Http::response(404, __('Page Not Found'));
 
 require(CLIENTINC_DIR.'header.inc.php');
 
diff --git a/pwreset.php b/pwreset.php
index 2b63aabf63477ab6818d965138b548d244aa9630..e37e4d264bab3aa20484be28a65613d63e6dcd5d 100644
--- a/pwreset.php
+++ b/pwreset.php
@@ -10,25 +10,24 @@ require_once(INCLUDE_DIR.'class.client.php');
 $inc = 'pwreset.request.php';
 if($_POST) {
     if (!$ost->checkCSRFToken()) {
-        Http::response(400, 'Valid CSRF Token Required');
+        Http::response(400, __('Valid CSRF Token Required'));
         exit;
     }
     switch ($_POST['do']) {
         case 'sendmail':
             if (($acct=ClientAccount::lookupByUsername($_POST['userid']))) {
                 if (!$acct->isPasswdResetEnabled()) {
-                    $banner = 'Password reset is not enabled for your account. '
-                        .'Contact your administrator';
+                    $banner = __('Password reset is not enabled for your account. Contact your administrator');
                 }
                 elseif ($acct->sendResetEmail()) {
                     $inc = 'pwreset.sent.php';
                 }
                 else
-                    $banner = 'Unable to send reset email. Internal error';
+                    $banner = __('Unable to send reset email. Internal error');
             }
             else
-                $banner = 'Unable to verify username '
-                    .Format::htmlchars($_POST['userid']);
+                $banner = sprintf(__('Unable to verify username: %s'),
+                    Format::htmlchars($_POST['userid']));
             break;
         case 'reset':
             $inc = 'pwreset.login.php';
@@ -43,7 +42,7 @@ if($_POST) {
     }
 }
 elseif ($_GET['token']) {
-    $banner = 'Re-enter your username or email';
+    $banner = __('Re-enter your username or email');
     $inc = 'pwreset.login.php';
     $_config = new Config('pwreset');
     if (($id = $_config->get($_GET['token']))
@@ -71,10 +70,10 @@ elseif ($_GET['token']) {
         Http::redirect('index.php');
 }
 elseif ($cfg->allowPasswordReset()) {
-    $banner = 'Enter your username or email address below';
+    $banner = __('Enter your username or email address below');
 }
 else {
-    $_SESSION['_staff']['auth']['msg']='Password resets are disabled';
+    $_SESSION['_staff']['auth']['msg']=__('Password resets are disabled');
     return header('Location: index.php');
 }
 
diff --git a/scp/attachment.php b/scp/attachment.php
index 28b9a185b4df488674d9157a13292cefb39bbc60..5b2e043037ed747b35507cd77ff426c7855bf9c4 100644
--- a/scp/attachment.php
+++ b/scp/attachment.php
@@ -17,14 +17,14 @@ require('staff.inc.php');
 require_once(INCLUDE_DIR.'class.attachment.php');
 
 //Basic checks
-if(!$thisstaff || !$_GET['id'] || !$_GET['h'] 
-        || !($attachment=Attachment::lookup($_GET['id'])) 
+if(!$thisstaff || !$_GET['id'] || !$_GET['h']
+        || !($attachment=Attachment::lookup($_GET['id']))
         || !($file=$attachment->getFile()))
-    die('Unknown attachment!');
+    die(__('Unknown or invalid attachment'));
 
 //Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!!
 $vhash=md5($attachment->getFileId().session_id().strtolower($file->getKey()));
-if(strcasecmp(trim($_GET['h']),$vhash) || !($ticket=$attachment->getTicket()) || !$ticket->checkStaffAccess($thisstaff)) die('Access Denied');
+if(strcasecmp(trim($_GET['h']),$vhash) || !($ticket=$attachment->getTicket()) || !$ticket->checkStaffAccess($thisstaff)) die(__('Access Denied'));
 
 //Download the file..
 $file->download();
diff --git a/scp/autocron.php b/scp/autocron.php
index 85e3cfbbb34c55f8085580daac7bd1fdd4e2c0b6..611cbbc4d029b856cdf76dd9dfc98a3e35354ce8 100644
--- a/scp/autocron.php
+++ b/scp/autocron.php
@@ -46,7 +46,7 @@ $thisstaff = null; //Clear staff obj to avoid false credit internal notes & auto
 Cron::TicketMonitor(); //Age tickets: We're going to age tickets regardless of cron settings.
 if($cfg && $cfg->isAutoCronEnabled()) { //ONLY fetch tickets if autocron is enabled!
     Cron::MailFetcher();  //Fetch mail.
-    $ost->logDebug('Auto Cron', 'Mail fetcher cron call ['.$caller.']');
+    $ost->logDebug(_S('Auto Cron'), sprintf(_S('Mail fetcher cron call [%s]'), $caller));
 }
 
 $_SESSION['lastcroncall']=time();
diff --git a/scp/file.php b/scp/file.php
index 68197cc566cf05f707d7d0d458b7097422b7b8ae..97687de0f0bb0a341ce895298f587891a9c179c0 100644
--- a/scp/file.php
+++ b/scp/file.php
@@ -1,9 +1,9 @@
 <?php
 /*********************************************************************
     file.php
-    
+
     Simply downloads the file...on hash validation as follows;
-    
+
     * Hash must be 64 chars long.
     * First 32 chars is the perm. file hash
     * Next 32 chars  is md5(file_id.session_id().file_hash)
@@ -24,7 +24,7 @@ $h=trim($_GET['h']);
 if(!$h  || strlen($h)!=64  //32*2
         || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
         || strcasecmp($file->getDownloadHash(), $h)) //next 32 is file id + session hash.
-    die('Unknown or invalid file. #'.Format::htmlchars($_GET['h']));
+    Http::response(404, __('Unknown or invalid file'));
 
 $file->download();
 ?>
diff --git a/scp/forms.php b/scp/forms.php
index 245ed33712b80c508ad47c68ee0d4b225265c820..cb5bdf322710167c50422c62b0b0b9d39d5fe358 100644
--- a/scp/forms.php
+++ b/scp/forms.php
@@ -4,7 +4,7 @@ require_once(INCLUDE_DIR."/class.dynamic_forms.php");
 
 $form=null;
 if($_REQUEST['id'] && !($form=DynamicForm::lookup($_REQUEST['id'])))
-    $errors['err']='Unknown or invalid dynamic form ID.';
+    $errors['err']=__('Unknown or invalid dynamic form ID.');
 
 if($_POST) {
     $fields = array('title', 'notes', 'instructions');
@@ -15,7 +15,7 @@ if($_POST) {
         case 'update':
             foreach ($fields as $f)
                 if (in_array($f, $required) && !$_POST[$f])
-                    $errors[$f] = sprintf('%s is required',
+                    $errors[$f] = sprintf(__('%s is required'),
                         mb_convert_case($f, MB_CASE_TITLE));
                 elseif (isset($_POST[$f]))
                     $form->set($f, $_POST[$f]);
@@ -48,14 +48,13 @@ if($_POST) {
                     }
                 }
                 if (in_array($field->get('name'), $names))
-                    $field->addError('Field variable name is not unique', 'name');
+                    $field->addError(__('Field variable name is not unique'), 'name');
                 if (preg_match('/[.{}\'"`; ]/u', $field->get('name')))
-                    $field->addError('Invalid character in variable name. Please use letters and numbers only.', 'name');
+                    $field->addError(__('Invalid character in variable name. Please use letters and numbers only.'), 'name');
                 // Subject (Issue Summary) must always have data
                 if ($form->get('type') == 'T' && $field->get('name') == 'subject') {
                     if (($f = $field->getField(false)->getImpl()) && !$f->hasData())
-                        $field->addError('The issue summary must be a field '
-                            .'that supports user input, such as short answer',
+                        $field->addError(__('The issue summary must be a field that supports user input, such as short answer'),
                             'type');
                 }
                 if ($field->get('name'))
@@ -64,7 +63,7 @@ if($_POST) {
                     $form_fields[] = $field;
                 else
                     # notrans (not shown)
-                    $errors["field-$id"] = 'Field has validation errors';
+                    $errors["field-$id"] = __('Field has validation errors');
                 // Keep track of the last sort number
                 $max_sort = max($max_sort, $field->get('sort'));
             }
@@ -82,7 +81,7 @@ if($_POST) {
 
         case 'mass_process':
             if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one API key';
+                $errors['err'] = __('You must select at least one form');
             } else {
                 $count = count($_POST['ids']);
                 switch(strtolower($_POST['a'])) {
@@ -93,11 +92,11 @@ if($_POST) {
                                 $i++;
                         }
                         if ($i && $i==$count)
-                            $msg = 'Selected custom forms deleted successfully';
+                            $msg = __('Selected custom forms deleted successfully');
                         elseif ($i > 0)
-                            $warn = "$i of $count selected forms deleted";
+                            $warn = sprintf(__('%1$d of %1$d selected forms deleted'), $i, $count);
                         elseif (!$errors['err'])
-                            $errors['err'] = 'Unable to delete selected custom forms';
+                            $errors['err'] = __('Unable to delete selected custom forms');
                         break;
                 }
             }
@@ -135,9 +134,9 @@ if($_POST) {
         }
     }
     if ($errors)
-        $errors['err'] = 'Unable to commit form. Check validation errors';
+        $errors['err'] = __('Unable to commit form. Check validation errors');
     else
-        $msg = 'Custom form successfully updated';
+        $msg = __('Custom form successfully updated');
 }
 
 $page='dynamic-forms.inc.php';
diff --git a/scp/helptopics.php b/scp/helptopics.php
index 461601c6469310ba56b58ff33d94464c8d58d184..8c41c1047136fa5d46e3ebac981cfd9fa6e0c8a7 100644
--- a/scp/helptopics.php
+++ b/scp/helptopics.php
@@ -117,7 +117,7 @@ if($_POST){
             }
             break;
         default:
-            $errors['err']=__('Unknown command/action');
+            $errors['err']=__('Unknown action');
             break;
     }
     if ($id or $topic) {
diff --git a/scp/image.php b/scp/image.php
index f10fcd6e9039817022330ee87aa00009127888a2..4c4ddbfe6da36e21588c0359b96924c365fba64b 100644
--- a/scp/image.php
+++ b/scp/image.php
@@ -25,7 +25,7 @@ $h=trim($_GET['h']);
 if(!$h  || strlen($h)!=64  //32*2
         || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
         || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    Http::response(404, 'Unknown or invalid file');
+    Http::response(404, __('Unknown or invalid file'));
 
 if ($_GET['s'] && is_numeric($_GET['s']))
     $file->display($_GET['s']);
diff --git a/scp/l.php b/scp/l.php
index f05349be04db6204b5f2de494908a31ea19cfa02..ec4705a0f2763101c2ac2b1b96c3af174793316a 100644
--- a/scp/l.php
+++ b/scp/l.php
@@ -18,11 +18,11 @@ require_once 'staff.inc.php';
 
 # PHP < 5.4.7 will not handle a URL like //host.tld/path correctly
 if (!($url=trim($_GET['url'])))
-    Http::response(422, 'Invalid URL');
+    Http::response(422, __('Invalid URL'));
 
 $check = (strpos($url, '//') === 0) ? 'http:' . $url : $url;
 if (!Validator::is_url($check) || !$ost->validateLinkToken($_GET['auth']))
-    Http::response(403, 'URL link not authorized');
+    Http::response(403, __('URL link not authorized'));
 elseif (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false)
     Http::redirect($url);
 ?>
diff --git a/scp/lists.php b/scp/lists.php
index 57ffad7a26374d13768da9e826a25f6252a5ec7a..36c5d7b9bfe4aa4f87ed3a404965a628e44be3fa 100644
--- a/scp/lists.php
+++ b/scp/lists.php
@@ -4,7 +4,7 @@ require_once(INCLUDE_DIR."/class.dynamic_forms.php");
 
 $list=null;
 if($_REQUEST['id'] && !($list=DynamicList::lookup($_REQUEST['id'])))
-    $errors['err']='Unknown or invalid dynamic list ID.';
+    $errors['err']=__('Unknown or invalid dynamic list ID.');
 
 if ($list)
     $form = $list->getForm();
@@ -21,11 +21,11 @@ if($_POST) {
                 elseif (isset($_POST[$f]))
                     $list->set($f, $_POST[$f]);
             if ($errors)
-                $errors['err'] = 'Unable to update custom list. Correct any error(s) below and try again.';
+                $errors['err'] = __('Unable to update custom list. Correct any error(s) below and try again.');
             elseif ($list->save(true))
-                $msg = 'Custom list updated successfully';
+                $msg = __('Custom list updated successfully');
             else
-                $errors['err'] = 'Unable to update custom list. Unknown internal error';
+                $errors['err'] = __('Unable to update custom list. Unknown internal error');
 
             foreach ($list->getAllItems() as $item) {
                 $id = $item->get('id');
@@ -71,16 +71,16 @@ if($_POST) {
                     }
                 }
                 if (in_array($field->get('name'), $names))
-                    $field->addError('Field variable name is not unique', 'name');
+                    $field->addError(__('Field variable name is not unique'), 'name');
                 if (preg_match('/[.{}\'"`; ]/u', $field->get('name')))
-                    $field->addError('Invalid character in variable name. Please use letters and numbers only.', 'name');
+                    $field->addError(__('Invalid character in variable name. Please use letters and numbers only.'), 'name');
                 if ($field->get('name'))
                     $names[] = $field->get('name');
                 if ($field->isValid())
                     $field->save();
                 else
                     # notrans (not shown)
-                    $errors["field-$id"] = 'Field has validation errors';
+                    $errors["field-$id"] = __('Field has validation errors');
                 // Keep track of the last sort number
                 $max_sort = max($max_sort, $field->get('sort'));
             }
@@ -88,7 +88,7 @@ if($_POST) {
         case 'add':
             foreach ($fields as $f)
                 if (in_array($f, $required) && !$_POST[$f])
-                    $errors[$f] = sprintf('%s is required',
+                    $errors[$f] = sprintf(__('%s is required'),
                         mb_convert_case($f, MB_CASE_TITLE));
             $list = DynamicList::create(array(
                 'name'=>$_POST['name'],
@@ -101,20 +101,20 @@ if($_POST) {
             ));
 
             if ($errors)
-                $errors['err'] = 'Unable to create custom list. Correct any error(s) below and try again.';
+                $errors['err'] = __('Unable to create custom list. Correct any error(s) below and try again.');
             elseif (!$list->save(true))
-                $errors['err'] = 'Unable to create custom list: Unknown internal error';
+                $errors['err'] = __('Unable to create custom list: Unknown internal error');
 
             $form->set('type', 'L'.$list->get('id'));
             if (!$errors && !$form->save(true))
-                $errors['err'] = 'Unable to create properties for custom list: Unknown internal error';
+                $errors['err'] = __('Unable to create properties for custom list: Unknown internal error');
             else
-                $msg = 'Custom list added successfully';
+                $msg = __('Custom list added successfully');
             break;
 
         case 'mass_process':
             if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one API key';
+                $errors['err'] = __('You must select at least one custom list');
             } else {
                 $count = count($_POST['ids']);
                 switch(strtolower($_POST['a'])) {
@@ -125,12 +125,11 @@ if($_POST) {
                                 $i++;
                         }
                         if ($i && $i==$count)
-                            $msg = 'Selected custom lists deleted successfully';
+                            $msg = __('Selected custom lists deleted successfully');
                         elseif ($i > 0)
-                            $warn = "$i of $count selected lists deleted";
+                            $warn = sprintf(__('%1$d or %2$d selected lists deleted'), $i, $count);
                         elseif (!$errors['err'])
-                            $errors['err'] = 'Unable to delete selected custom lists'
-                                .' &mdash; they may be in use on a custom form';
+                            $errors['err'] = __('Unable to delete selected custom lists — they may be in use on a custom form');
                         break;
                 }
             }
diff --git a/scp/logs.php b/scp/logs.php
index c4e09ff3fe502c25b34f3e60633af6b91b462899..2205e695043e5d34ec060191f1511bb152f50614 100644
--- a/scp/logs.php
+++ b/scp/logs.php
@@ -39,7 +39,7 @@ if($_POST){
             }
             break;
         default:
-            $errors['err']=__('Unknown command/action');
+            $errors['err']=__('Unknown action');
             break;
     }
 }
diff --git a/scp/orgs.php b/scp/orgs.php
index 373864afd09b30f321af48d20890ea197d32538b..833e87c318471b873ae8f3d174cf980b3a73c36a 100644
--- a/scp/orgs.php
+++ b/scp/orgs.php
@@ -23,22 +23,21 @@ if ($_POST) {
     switch ($_REQUEST['a']) {
     case 'import-users':
         if (!$org) {
-            $errors['err'] = 'Organization ID must be specified for import';
+            $errors['err'] = __('Organization ID must be specified for import');
             break;
         }
         $status = User::importFromPost($_FILES['import'] ?: $_POST['pasted'],
             array('org_id'=>$org->getId()));
         if (is_numeric($status))
-            $msg = "Successfully imported $status clients";
+            $msg = sprintf(__("Successfully imported %d clients"), $status);
         else
             $errors['err'] = $status;
         break;
     case 'remove-users':
         if (!$org)
-            $errors['err'] = ' Trying to remove users from unknown
-                 organization';
+            $errors['err'] = __('Trying to remove users from unknown organization');
         elseif (!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-            $errors['err'] = 'You must select at least one user to remove';
+            $errors['err'] = __('You must select at least one user to remove');
         } else {
             $i = 0;
             foreach ($_POST['ids'] as $k=>$v) {
@@ -47,25 +46,25 @@ if ($_POST) {
             }
             $num = count($_POST['ids']);
             if ($i && $i == $num)
-                $msg = 'Selected users removed successfully';
+                $msg = __('Selected users removed successfully');
             elseif ($i > 0)
-                $warn = "$i of $num selected users removed";
+                $warn = sprintf(__('%1$d or %2$d selected users removed'), $i, $count);
             elseif (!$errors['err'])
-                $errors['err'] = 'Unable to remove selected users';
+                $errors['err'] = __('Unable to remove selected users');
         }
         break;
     default:
-        $errors['err'] = 'Unknown action';
+        $errors['err'] = __('Unknown action');
     }
 } elseif ($_REQUEST['a'] == 'export') {
     require_once(INCLUDE_DIR.'class.export.php');
     $ts = strftime('%Y%m%d');
     if (!($token=$_REQUEST['qh']))
-        $errors['err'] = 'Query token required';
+        $errors['err'] = __('Query token required');
     elseif (!($query=$_SESSION['orgs_qs_'.$token]))
-        $errors['err'] = 'Query token not found';
-    elseif (!Export::saveOrganizations($query, "organizations-$ts.csv", 'csv'))
-        $errors['err'] = 'Internal error: Unable to export results';
+        $errors['err'] = __('Query token not found');
+    elseif (!Export::saveOrganizations($query, __('organizations')."-$ts.csv", 'csv'))
+        $errors['err'] = __('Internal error: Unable to export results');
 }
 
 $page = $org? 'org-view.inc.php' : 'orgs.inc.php';
diff --git a/scp/pages.php b/scp/pages.php
index 5f3747b5e1c789db43e2db2c3e77bd3e2b39102c..c63072db06cfa1fa35ea8a8a300da971546a1df0 100644
--- a/scp/pages.php
+++ b/scp/pages.php
@@ -18,14 +18,14 @@ require_once(INCLUDE_DIR.'class.page.php');
 
 $page = null;
 if($_REQUEST['id'] && !($page=Page::lookup($_REQUEST['id'])))
-   $errors['err']='Unknown or invalid page';
+   $errors['err']=__('Unknown or invalid page');
 
 if($_POST) {
     switch(strtolower($_POST['do'])) {
         case 'add':
             if(($pageId=Page::create($_POST, $errors))) {
                 $_REQUEST['a'] = null;
-                $msg='Page added successfully';
+                $msg=__('Page added successfully');
                 // Attach inline attachments from the editor
                 if (isset($_POST['draft_id'])
                         && ($draft = Draft::lookup($_POST['draft_id']))
@@ -34,13 +34,13 @@ if($_POST) {
                         $draft->getAttachmentIds($_POST['response']), true);
                 Draft::deleteForNamespace('page');
             } elseif(!$errors['err'])
-                $errors['err'] = 'Unable to add page. Try again!';
+                $errors['err'] = __('Unable to add page. Try again!');
         break;
         case 'update':
             if(!$page)
-                $errors['err'] = 'Invalid or unknown page';
+                $errors['err'] = __('Invalid or unknown page');
             elseif($page->update($_POST, $errors)) {
-                $msg='Page updated successfully';
+                $msg=__('Page updated successfully');
                 $_REQUEST['a']=null; //Go back to view
                 // Attach inline attachments from the editor
                 if (isset($_POST['draft_id'])
@@ -52,13 +52,13 @@ if($_POST) {
                 }
                 Draft::deleteForNamespace('page.'.$page->getId());
             } elseif(!$errors['err'])
-                $errors['err'] = 'Unable to update page. Try again!';
+                $errors['err'] = __('Unable to update page. Try again!');
             break;
         case 'mass_process':
             if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one page.';
+                $errors['err'] = __('You must select at least one page.');
             } elseif(array_intersect($_POST['ids'], $cfg->getDefaultPages()) && strcasecmp($_POST['a'], 'enable')) {
-                 $errors['err'] = 'One or more of the selected pages is in-use and CANNOT be disabled/deleted.';
+                 $errors['err'] = __('One or more of the selected pages is in-use and CANNOT be disabled/deleted.');
             } else {
                 $count=count($_POST['ids']);
                 switch(strtolower($_POST['a'])) {
@@ -67,11 +67,11 @@ if($_POST) {
                             .' WHERE id IN ('.implode(',', db_input($_POST['ids'])).')';
                         if(db_query($sql) && ($num=db_affected_rows())) {
                             if($num==$count)
-                                $msg = 'Selected pages enabled';
+                                $msg = __('Selected pages enabled');
                             else
-                                $warn = "$num of $count selected pages enabled";
+                                $warn = sprintf(__('%1$d of %2$d selected pages enabled'), $num, $count);;
                         } else {
-                            $errors['err'] = 'Unable to enable selected pages';
+                            $errors['err'] = __('Unable to enable selected pages');
                         }
                         break;
                     case 'disable':
@@ -82,11 +82,11 @@ if($_POST) {
                         }
 
                         if($i && $i==$count)
-                            $msg = 'Selected pages disabled';
+                            $msg = __('Selected pages disabled');
                         elseif($i>0)
-                            $warn = "$num of $count selected pages disabled";
+                            $warn = sprintf(__('%1$d of %2$d selected pages disabled'), $i, $count);
                         elseif(!$errors['err'])
-                            $errors['err'] = 'Unable to disable selected pages';
+                            $errors['err'] = __('Unable to disable selected pages');
                         break;
                     case 'delete':
                         $i=0;
@@ -96,19 +96,19 @@ if($_POST) {
                         }
 
                         if($i && $i==$count)
-                            $msg = 'Selected pages deleted successfully';
+                            $msg = __('Selected pages deleted successfully');
                         elseif($i>0)
-                            $warn = "$i of $count selected pages deleted";
+                            $warn = sprintf(__('%1$d of %2$d selected pages deleted'), $i, $count);
                         elseif(!$errors['err'])
-                            $errors['err'] = 'Unable to delete selected pages';
+                            $errors['err'] = __('Unable to delete selected pages');
                         break;
                     default:
-                        $errors['err']='Unknown action - get technical help.';
+                        $errors['err']=__('Unknown action - get technical help.');
                 }
             }
             break;
         default:
-            $errors['err']='Unknown action/command';
+            $errors['err']=__('Unknown action');
             break;
     }
 }
diff --git a/scp/plugins.php b/scp/plugins.php
index 44dda73b80897b668caafe38638c163321a31e64..ee8e8bf87276ac5c96fda08b3fcb48dab4c923b0 100644
--- a/scp/plugins.php
+++ b/scp/plugins.php
@@ -3,7 +3,7 @@ require('admin.inc.php');
 require_once(INCLUDE_DIR."/class.plugin.php");
 
 if($_REQUEST['id'] && !($plugin=Plugin::lookup($_REQUEST['id'])))
-    $errors['err']='Unknown or invalid plugin ID.';
+    $errors['err']=__('Unknown or invalid plugin ID.');
 
 if($_POST) {
     switch(strtolower($_POST['do'])) {
@@ -14,7 +14,7 @@ if($_POST) {
         break;
     case 'mass_process':
         if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-            $errors['err'] = 'You must select at least one plugin';
+            $errors['err'] = __('You must select at least one plugin');
         } else {
             $count = count($_POST['ids']);
             switch(strtolower($_POST['a'])) {
@@ -44,7 +44,7 @@ if($_POST) {
         break;
     case 'install':
         if ($ost->plugins->install($_POST['install_path']))
-            $msg = 'Plugin successfully installed';
+            $msg = __('Plugin successfully installed');
         break;
     }
 }
diff --git a/scp/pwreset.php b/scp/pwreset.php
index f5eed25fc0ed98e37cfa4d18dfc098c858bffe77..5fef286df2fcf218c8aa0edecbb6537097eea9a3 100644
--- a/scp/pwreset.php
+++ b/scp/pwreset.php
@@ -30,22 +30,22 @@ require_once(INCLUDE_DIR.'class.csrf.php');
 $tpl = 'pwreset.php';
 if($_POST) {
     if (!$ost->checkCSRFToken()) {
-        Http::response(400, 'Valid CSRF Token Required');
+        Http::response(400, __('Valid CSRF Token Required'));
         exit;
     }
     switch ($_POST['do']) {
         case 'sendmail':
             if (($staff=Staff::lookup($_POST['userid']))) {
                 if (!$staff->hasPassword()) {
-                    $msg = 'Unable to reset password. Contact your administrator';
+                    $msg = __('Unable to reset password. Contact your administrator');
                 }
                 elseif (!$staff->sendResetEmail()) {
                     $tpl = 'pwreset.sent.php';
                 }
             }
             else
-                $msg = 'Unable to verify username '
-                    .Format::htmlchars($_POST['userid']);
+                $msg = sprintf(__('Unable to verify username %s'),
+                    Format::htmlchars($_POST['userid']));
             break;
         case 'newpasswd':
             // TODO: Compare passwords
@@ -62,7 +62,7 @@ if($_POST) {
     }
 }
 elseif ($_GET['token']) {
-    $msg = 'Please enter your username or email';
+    $msg = __('Please enter your username or email');
     $_config = new Config('pwreset');
     if (($id = $_config->get($_GET['token']))
             && ($staff = Staff::lookup($id)))
@@ -72,10 +72,10 @@ elseif ($_GET['token']) {
         header('Location: index.php');
 }
 elseif ($cfg->allowPasswordReset()) {
-    $msg = 'Enter your username or email address below';
+    $msg = __('Enter your username or email address below');
 }
 else {
-    $_SESSION['_staff']['auth']['msg']='Password resets are disabled';
+    $_SESSION['_staff']['auth']['msg']=__('Password resets are disabled');
     return header('Location: index.php');
 }
 define("OSTSCPINC",TRUE); //Make includes happy!
diff --git a/scp/staff.php b/scp/staff.php
index 8156c5e159f267e53c740bada32827e14b0f93e5..da823a5841efe2ddccde63a9fd39453225367b5f 100644
--- a/scp/staff.php
+++ b/scp/staff.php
@@ -92,7 +92,7 @@ if($_POST){
             }
             break;
         default:
-            $errors['err']=__('Unknown action/command');
+            $errors['err']=__('Unknown action');
             break;
     }
 }
diff --git a/scp/teams.php b/scp/teams.php
index 4a1f2c709e5e07073395dc488ca9ee768c760cfa..f78dfe1f0b185526d8e92e2dd5f1337357b80893 100644
--- a/scp/teams.php
+++ b/scp/teams.php
@@ -17,7 +17,7 @@ require('admin.inc.php');
 
 $team=null;
 if($_REQUEST['id'] && !($team=Team::lookup($_REQUEST['id'])))
-    $errors['err']=__('Unknown or invalid team ID.');
+    $errors['err']=__('Unknown or invalid team.');
 
 if($_POST){
     switch(strtolower($_POST['do'])){
@@ -27,7 +27,7 @@ if($_POST){
             }elseif($team->update($_POST,$errors)){
                 $msg=__('Team updated successfully');
             }elseif(!$errors['err']){
-                $errors['err']=__('Unable to update team. Correct any error(s) below and try again!');
+                $errors['err']=__('Unable to update team. Correct any error(s) below and try again.');
             }
             break;
         case 'create':
diff --git a/scp/templates.php b/scp/templates.php
index 5ceee2b89da8765fcea60de3122a68bad3479f8a..9f31365863ba09ca43c395b5e73f00b6708a855e 100644
--- a/scp/templates.php
+++ b/scp/templates.php
@@ -19,10 +19,10 @@ include_once(INCLUDE_DIR.'class.template.php');
 $template=null;
 if($_REQUEST['tpl_id'] &&
         !($template=EmailTemplateGroup::lookup($_REQUEST['tpl_id'])))
-    $errors['err']=__('Unknown or invalid template group ID.');
+    $errors['err']=__('Unknown or invalid template set.');
 elseif($_REQUEST['id'] &&
         !($template=EmailTemplate::lookup($_REQUEST['id'])))
-    $errors['err']=__('Unknown or invalid template ID.');
+    $errors['err']=__('Unknown or invalid template.');
 elseif($_REQUEST['default_for']) {
     $sql = 'SELECT id FROM '.EMAIL_TEMPLATE_TABLE
         .' WHERE tpl_id='.db_input($cfg->getDefaultTemplateId())
@@ -35,7 +35,7 @@ if($_POST){
     switch(strtolower($_POST['do'])){
         case 'updatetpl':
             if(!$template){
-                $errors['err']=__('Unknown or invalid template');
+                $errors['err']=__('Unknown or invalid template.');
             }elseif($template->update($_POST,$errors)){
                 $msg=__('Message template updated successfully');
                 // Drop drafts for this template for ALL users
diff --git a/scp/tickets.php b/scp/tickets.php
index bb7635d88cff19e0fd7dc2e9481090d66026bb55..7dac90f67c2a4b5295d691c59edf2f12cd3a9a6d 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -45,7 +45,6 @@ if($_POST && !$errors):
         //More coffee please.
         $errors=array();
         $lock=$ticket->getLock(); //Ticket lock if any
-        $statusKeys=array('open'=>'Open','Reopen'=>'Open','Close'=>'Closed');
         switch(strtolower($_POST['a'])):
         case 'reply':
             if(!$thisstaff->canPostReply())
diff --git a/scp/upgrade.php b/scp/upgrade.php
index f077c7e4f1d701a4728a9df026113d28b68b3c90..6ee00329120083d1932b0d5a3cd3197f4b36c517 100644
--- a/scp/upgrade.php
+++ b/scp/upgrade.php
@@ -77,8 +77,8 @@ switch(strtolower($upgrader->getState())) {
 
 $nav = new AdminNav($thisstaff);
 $nav->setTabActive('dashboard');
-$nav->addSubMenu(array('desc'=>'Upgrader',
-                           'title'=>'Upgrader',
+$nav->addSubMenu(array('desc'=>__('Upgrader'),
+                           'title'=>__('Upgrader'),
                            'href'=>'upgrade.php',
                            'iconclass'=>'preferences'),
                         true);
diff --git a/scp/users.php b/scp/users.php
index c6606a8be9737de524f8a3cb6a72eafe184bd2df..052e20d8bda6ec2bce0836888dd787b80ff76ab7 100644
--- a/scp/users.php
+++ b/scp/users.php
@@ -18,53 +18,53 @@ require_once INCLUDE_DIR.'class.note.php';
 
 $user = null;
 if ($_REQUEST['id'] && !($user=User::lookup($_REQUEST['id'])))
-    $errors['err'] = 'Unknown or invalid user ID.';
+    $errors['err'] = __('Unknown or invalid user.');
 
 if ($_POST) {
     switch(strtolower($_REQUEST['do'])) {
         case 'update':
             if (!$user) {
-                $errors['err']='Unknown or invalid user.';
+                $errors['err']=__('Unknown or invalid user.');
             } elseif(($acct = $user->getAccount())
                     && !$acct->update($_POST, $errors)) {
-                 $errors['err']='Unable to update user account information';
+                 $errors['err']=__('Unable to update user account information');
             } elseif($user->updateInfo($_POST, $errors)) {
-                $msg='User updated successfully';
+                $msg=__('User updated successfully');
                 $_REQUEST['a'] = null;
             } elseif(!$errors['err']) {
-                $errors['err']='Unable to update user profile. Correct any error(s) below and try again!';
+                $errors['err']=__('Unable to update user profile. Correct any error(s) below and try again!');
             }
             break;
         case 'create':
             $form = UserForm::getUserForm()->getForm($_POST);
             if (($user = User::fromForm($form))) {
-                $msg = Format::htmlchars($user->getName()).' added successfully';
+                $msg = Format::htmlchars(sprintf(__('%s added successfully'), $user->getName()));
                 $_REQUEST['a'] = null;
             } elseif (!$errors['err']) {
-                $errors['err'] = 'Unable to add user. Correct any error(s) below and try again.';
+                $errors['err'] = __('Unable to add user. Correct any error(s) below and try again.');
             }
             break;
         case 'confirmlink':
             if (!$user || !$user->getAccount())
-                $errors['err'] = 'Unknown or invalid user account';
+                $errors['err'] = __('Unknown or invalid user account');
             elseif ($user->getAccount()->isConfirmed())
-                $errors['err'] = 'Account is already confirmed';
+                $errors['err'] = __('Account is already confirmed');
             elseif ($user->getAccount()->sendConfirmEmail())
-                $msg = 'Account activation email sent to '.$user->getEmail();
+                $msg = sprintf(__('Account activation email sent to %s'),$user->getEmail());
             else
-                $errors['err'] = 'Unable to send account activation email - try again!';
+                $errors['err'] = __('Unable to send account activation email - try again!');
             break;
         case 'pwreset':
             if (!$user || !$user->getAccount())
-                $errors['err'] = 'Unknown or invalid user account';
+                $errors['err'] = __('Unknown or invalid user account');
             elseif ($user->getAccount()->sendResetEmail())
-                $msg = 'Account password reset email sent to '.$user->getEmail();
+                $msg = sprintf(__('Account password reset email sent to %s'),$user->getEmail());
             else
-                $errors['err'] = 'Unable to send account password reset email - try again!';
+                $errors['err'] = __('Unable to send account password reset email - try again!');
             break;
         case 'mass_process':
             if (!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
-                $errors['err'] = 'You must select at least one user member.';
+                $errors['err'] = __('You must select at least one user.');
             } else {
                 $errors['err'] = "Coming soon!";
             }
@@ -72,23 +72,24 @@ if ($_POST) {
         case 'import-users':
             $status = User::importFromPost($_FILES['import'] ?: $_POST['pasted']);
             if (is_numeric($status))
-                $msg = "Successfully imported $status clients";
+                $msg = sprintf(_N('Successfully imported %1$d client.', 'Successfully imported %1$d clients.', $status),
+                   $status);
             else
                 $errors['err'] = $status;
             break;
         default:
-            $errors['err'] = 'Unknown action/command';
+            $errors['err'] = __('Unknown action');
             break;
     }
 } elseif($_REQUEST['a'] == 'export') {
     require_once(INCLUDE_DIR.'class.export.php');
     $ts = strftime('%Y%m%d');
     if (!($token=$_REQUEST['qh']))
-        $errors['err'] = 'Query token required';
+        $errors['err'] = __('Query token required');
     elseif (!($query=$_SESSION['users_qs_'.$token]))
-        $errors['err'] = 'Query token not found';
-    elseif (!Export::saveUsers($query, "users-$ts.csv", 'csv'))
-        $errors['err'] = 'Internal error: Unable to dump query results';
+        $errors['err'] = __('Query token not found');
+    elseif (!Export::saveUsers($query, __("users")."-$ts.csv", 'csv'))
+        $errors['err'] = __('Internal error: Unable to dump query results');
 }
 
 $page = $user? 'user-view.inc.php' : 'users.inc.php';
diff --git a/setup/ajax.php b/setup/ajax.php
index 97e45daddc88ece9cd65e24ea71dfb9f0d7ac8b9..ad1e18432b705b4c7377f7557d6559cc2a2ba448 100644
--- a/setup/ajax.php
+++ b/setup/ajax.php
@@ -17,7 +17,7 @@
 require('setup.inc.php');
 
 if(!defined('INCLUDE_DIR'))
-    Http::response(500, 'Server configuration error');
+    Http::response(500, __('Server configuration error'));
 require_once INCLUDE_DIR.'/class.dispatcher.php';
 require_once INCLUDE_DIR.'/class.ajax.php';
 
diff --git a/setup/cli/modules/i18n.php b/setup/cli/modules/i18n.php
index 3c044660a670800a7e49f4f23e7804463d00059b..c3c77668ec7e3956a175cfab424cbb0097fe434d 100644
--- a/setup/cli/modules/i18n.php
+++ b/setup/cli/modules/i18n.php
@@ -151,7 +151,7 @@ class i18n_Compiler extends Module {
                     case '#':
                         $text = ltrim($T[1], '# ');
                     }
-                    $string['comment'] = $text;
+                    $string['comments'][] = $text;
                     break;
                 case T_WHITESPACE:
                     // noop
@@ -178,8 +178,9 @@ class i18n_Compiler extends Module {
                 }
                 $args['forms'][] = $string['form'];
                 $args['line'] = $string['line'];
-                if (isset($string['comment']))
-                    $args['comments'][] = $string['comment'];
+                if (isset($string['comments']))
+                    $args['comments'] = array_merge(
+                        @$args['comments'] ?: array(), $string['comments']);
             }
 
             switch ($T[0]) {
@@ -231,8 +232,9 @@ class i18n_Compiler extends Module {
                     // Find the next textual token
                     list($S, $T) = $this->__read_next_string($tokens);
                     $string = array('forms'=>array($S['form']), 'line'=>$S['line']);
-                    if (isset($S['comment']))
-                        $string['comments'][] = $S['comment'];
+                    if (isset($S['comments']))
+                        $string['comments'] = array_merge(
+                            @$string['comments'] ?: array(), $S['comments']);
                     $T_funcs[] = $string;
                 }
                 break;
@@ -293,8 +295,8 @@ class i18n_Compiler extends Module {
             if ($c = @$S['comments']) {
                 foreach ($c as $comment) {
                     foreach (explode("\n", $comment) as $line) {
-                        $line = trim($line);
-                        print "#. {$line}\n";
+                        if ($line = trim($line))
+                            print "#. {$line}\n";
                     }
                 }
             }
@@ -320,7 +322,7 @@ class i18n_Compiler extends Module {
 
     function _make_pot() {
         error_reporting(E_ALL);
-        $funcs = array('__'=>1, '_N'=>2);
+        $funcs = array('__'=>1, '_S'=>1, '_N'=>2, '_SN'=>2);
         function get_osticket_root_path() { return ROOT_DIR; }
         require_once(ROOT_DIR.'setup/test/tests/class.test.php');
         $files = Test::getAllScripts();
@@ -334,6 +336,8 @@ class i18n_Compiler extends Module {
                     // Transation of non-constant
                     continue;
                 $primary = $forms[0];
+                // Normalize the $primary string
+                $primary = preg_replace(array("`\\\(['$])`", '`(?<!\\\)"`'), array("$1", '\"'), $primary);
                 if (!isset($strings[$primary])) {
                     $strings[$primary] = array('forms' => $forms);
                 }
diff --git a/setup/inc/file-perm.inc.php b/setup/inc/file-perm.inc.php
index efb0ea0140ca62a66d42c06c988a80e88b5be008..025c6a2176899cf52314a3587a4c682a03cdf973 100644
--- a/setup/inc/file-perm.inc.php
+++ b/setup/inc/file-perm.inc.php
@@ -6,7 +6,7 @@ if(!defined('SETUPINC')) die('Kwaheri!');
             <div id="intro">
             <p> <?php
             echo sprintf(
-                 __('osTicket installer requires ability to write to the configuration file <b>%s</b>'),
+                 __('osTicket installer requires ability to write to the configuration file %s'),
                  '<b>include/ost-config.php</b>');?>
              </p>
             </div>
diff --git a/setup/inc/install-done.inc.php b/setup/inc/install-done.inc.php
index 269371f01066bea5ecde2563ed49ced868bb8303..f79e89f4808f1501d6c658dba4366fe16b12cae8 100644
--- a/setup/inc/install-done.inc.php
+++ b/setup/inc/install-done.inc.php
@@ -11,6 +11,7 @@ $url=URL;
         <?php echo __('Change permission of ost-config.php to remove write access as shown below.');?>
         <ul>
             <li><b><?php echo __('CLI');?></b>:<br><i>chmod 0664  include/ost-config.php</i></li>
+            <li><b><?php echo __('Windows PowerShell');?></b>:<br><i>icacls include/ost-config.php /grant 'Everyone:(OI)(CI)F'</i></li>
             <li><b><?php echo __('FTP');?></b>:<br><?php echo __('Using WS_FTP this would be right hand clicking on the file, selecting chmod, and then remove write access');?></li>
             <li><b><?php echo __('Cpanel');?></b>:<br><?php echo __('Click on the file, select change permission, and then remove write access.');?></li>
         </ul>
diff --git a/setup/inc/install.inc.php b/setup/inc/install.inc.php
index bf2f007a9f07b5edc7da0ecebf5849f0ce36b1c5..daa1170b233b8d4584153fd089e857c9f40fa794 100644
--- a/setup/inc/install.inc.php
+++ b/setup/inc/install.inc.php
@@ -27,7 +27,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array('prefix'=>'ost_','dbho
                     <font class="error"><?php echo $errors['email']; ?></font>
                 </div>
                 <div class="row">
-                    <label><?php echo _('Primary Language');?>:</label>
+                    <label><?php echo __('Primary Language');?>:</label>
 <?php $langs = Internationalization::availableLanguages(); ?>
                 <select name="lang_id">
 <?php foreach($langs as $l) {
diff --git a/setup/inc/ost-sampleconfig.php b/setup/inc/ost-sampleconfig.php
index 8a1f3b98eed8b51f6cbd535a8c181bebb5b7f312..6421abbd48c9f90d035930390173405b2c06d768 100644
--- a/setup/inc/ost-sampleconfig.php
+++ b/setup/inc/ost-sampleconfig.php
@@ -4,7 +4,7 @@
 
     Static osTicket configuration file. Mainly useful for mysql login info.
     Created during installation process and shouldn't change even on upgrades.
-   
+
     Peter Rotich <peter@osticket.com>
     Copyright (c)  2006-2010 osTicket
     http://www.osticket.com
@@ -36,7 +36,7 @@ define('ADMIN_EMAIL','%ADMIN-EMAIL');
 
 #Mysql Login info
 define('DBTYPE','mysql');
-define('DBHOST','%CONFIG-DBHOST'); 
+define('DBHOST','%CONFIG-DBHOST');
 define('DBNAME','%CONFIG-DBNAME');
 define('DBUSER','%CONFIG-DBUSER');
 define('DBPASS','%CONFIG-DBPASS');
diff --git a/setup/inc/subscribe.inc.php b/setup/inc/subscribe.inc.php
index 94745beed055e9d2bb0cf01027e1a1d44c37b58b..e60fd275fda1117e914e17d20ba5842d04b278a0 100644
--- a/setup/inc/subscribe.inc.php
+++ b/setup/inc/subscribe.inc.php
@@ -8,7 +8,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$_SESSION['info'];
         <?php echo __("It's important to keep your installation up to date. Get announcements, security updates and alerts delivered directly to you!");?>
         <br><br>
         <form action="install.php" method="post">
-            <input type="hidden" name="s" value="subscribe">        
+            <input type="hidden" name="s" value="subscribe">
                 <div class="row">
                     <label><?php echo __('Full Name');?>:</label>
                     <input type="text" name="name" size="30" value="<?php echo $info['name']; ?>">
@@ -23,11 +23,11 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$_SESSION['info'];
                 <div class="row">
                     <strong><?php echo __("I'd like to receive the following notifications");?>: <font color="red"><?php echo $errors['notify']; ?></font></strong>
                     <label style="width:500px">
-                        <input style="position:relative; top:4px; margin-right:10px" 
+                        <input style="position:relative; top:4px; margin-right:10px"
                             type="checkbox" name="news" value="1" <?php echo (!isset($info['news']) || $info['news'])?'checked="checked"':''; ?> >
                             <?php echo __('News &amp; Announcements');?></label>
                     <label style="width:500px">
-                        <input style="position:relative; top:4px; margin-right:10px"  
+                        <input style="position:relative; top:4px; margin-right:10px"
                             type="checkbox" name="alerts" value="1" <?php echo (!isset($info['alerts']) || $info['alerts'])?'checked="checked"':''; ?>>
                             <?php echo __('Security Alerts');?></label>
                 </div>