Visman 8 years ago
parent
commit
44bb5dc6ca
51 changed files with 1495 additions and 150 deletions
  1. 1 1
      app/Controllers/Primary.php
  2. 5 0
      app/Controllers/Routing.php
  3. 46 1
      app/Core/Mail.php
  4. 1 1
      app/Models/Actions/LoadUserFromCookie.php
  5. 1 1
      app/Models/Pages/Admin/Statistics.php
  6. 173 15
      app/Models/Pages/Auth.php
  7. 5 73
      app/Models/User.php
  8. 69 4
      app/Models/UserMapper.php
  9. 11 26
      app/lang/English/login.po
  10. 12 0
      app/lang/English/mail/activate_email.tpl
  11. 9 0
      app/lang/English/mail/banned_email_change.tpl
  12. 9 0
      app/lang/English/mail/banned_email_post.tpl
  13. 9 0
      app/lang/English/mail/banned_email_register.tpl
  14. 14 0
      app/lang/English/mail/change_password.tpl
  15. 9 0
      app/lang/English/mail/dupe_email_change.tpl
  16. 9 0
      app/lang/English/mail/dupe_email_register.tpl
  17. 13 0
      app/lang/English/mail/form_email.tpl
  18. 10 0
      app/lang/English/mail/form_pmsn.tpl
  19. 1 0
      app/lang/English/mail/index.html
  20. 11 0
      app/lang/English/mail/new_reply.tpl
  21. 18 0
      app/lang/English/mail/new_reply_full.tpl
  22. 9 0
      app/lang/English/mail/new_report.tpl
  23. 11 0
      app/lang/English/mail/new_topic.tpl
  24. 18 0
      app/lang/English/mail/new_topic_full.tpl
  25. 12 0
      app/lang/English/mail/new_user.tpl
  26. 12 0
      app/lang/English/mail/rename.tpl
  27. 12 0
      app/lang/English/mail/welcome.tpl
  28. 376 0
      app/lang/English/profile.po
  29. 11 26
      app/lang/Russian/login.po
  30. 12 0
      app/lang/Russian/mail/activate_email.tpl
  31. 9 0
      app/lang/Russian/mail/banned_email_change.tpl
  32. 9 0
      app/lang/Russian/mail/banned_email_post.tpl
  33. 9 0
      app/lang/Russian/mail/banned_email_register.tpl
  34. 14 0
      app/lang/Russian/mail/change_password.tpl
  35. 9 0
      app/lang/Russian/mail/dupe_email_change.tpl
  36. 9 0
      app/lang/Russian/mail/dupe_email_register.tpl
  37. 13 0
      app/lang/Russian/mail/form_email.tpl
  38. 10 0
      app/lang/Russian/mail/form_pmsn.tpl
  39. 8 0
      app/lang/Russian/mail/index.html
  40. 11 0
      app/lang/Russian/mail/new_reply.tpl
  41. 18 0
      app/lang/Russian/mail/new_reply_full.tpl
  42. 9 0
      app/lang/Russian/mail/new_report.tpl
  43. 11 0
      app/lang/Russian/mail/new_topic.tpl
  44. 18 0
      app/lang/Russian/mail/new_topic_full.tpl
  45. 12 0
      app/lang/Russian/mail/new_user.tpl
  46. 12 0
      app/lang/Russian/mail/rename.tpl
  47. 12 0
      app/lang/Russian/mail/welcome.tpl
  48. 376 0
      app/lang/Russian/profile.po
  49. 2 2
      app/templates/login.tpl
  50. 0 0
      app/templates/login/forget.tpl
  51. 15 0
      app/templates/login/password.tpl

+ 1 - 1
app/Controllers/Primary.php

@@ -46,7 +46,7 @@ class Primary
             exit;
         }
 
-        if (($banned = $this->c->get('CheckBans')->check($this->c->get('user'))) !== null) {
+        if (($banned = $this->c->get('CheckBans')->check()) !== null) {
             return $this->c->get('Ban')->ban($banned);
         }
     }

+ 5 - 0
app/Controllers/Routing.php

@@ -36,8 +36,13 @@ class Routing
             // вход
             $r->add('GET', '/login', 'Auth:login', 'Login');
             $r->add('POST', '/login', 'Auth:loginPost');
+            // забыли пароль
             $r->add('GET', '/login/forget', 'Auth:forget', 'Forget');
             $r->add('POST', '/login/forget', 'Auth:forgetPost');
+            // смена пароля
+            $r->add('GET', '/login/{email}/{key}', 'Auth:changePass', 'ChangePassword');
+            $r->add('POST', '/login/{email}/{key}', 'Auth:changePassPost');
+
             // регистрация
             if ($config['o_regs_allow'] == '1') {
                 $r->add('GET', '/registration', 'Registration:reg', 'Registration'); //????

+ 46 - 1
app/Core/Mail.php

@@ -4,6 +4,16 @@ namespace ForkBB\Core;
 
 class Mail
 {
+    /**
+     * @var string
+     */
+    protected $folder;
+
+    /**
+     * @var string
+     */
+    protected $language;
+
     /**
      * Валидация email
      * @param mixed $email
@@ -12,7 +22,42 @@ class Mail
     public function valid($email)
     {
         return is_string($email)
-            && strlen($email) < 255
+            && strlen($email) <= 80
             && preg_match('%^.+@.+$%D', $email);
     }
+
+    /**
+     * Установка папки для поиска шаблонов писем
+     * @param string $folder
+     * @return Mail
+     */
+    public function setFolder($folder)
+    {
+        $this->folder = $folder;
+        return $this;
+    }
+
+    /**
+     * Установка языка для поиска шаблонов писем
+     * @param string $language
+     * @return Mail
+     */
+    public function setLanguage($language)
+    {
+        $this->language = $language;
+        return $this;
+    }
+
+    /**
+     * Отправка письма
+     * @param string $email
+     * @param string $tpl
+     * @param array $data
+     * @return bool
+     */
+    public function send($email, $tpl, array $data)
+    {
+        var_dump($data);
+        return true;
+    }
 }

+ 1 - 1
app/Models/Actions/LoadUserFromCookie.php

@@ -78,7 +78,7 @@ class LoadUserFromCookie
             }
             // Special case: We've timed out, but no other user has browsed the forums since we timed out
             if ($user->isLogged && $user->logged < time() - $this->config['o_timeout_visit']) {
-                $this->mapper->updateLastVisit($user->id, $user->logged);
+                $this->mapper->updateLastVisit($user);
                 $user->lastVisit = $user->logged;
             }
         }

+ 1 - 1
app/Models/Pages/Admin/Statistics.php

@@ -40,7 +40,7 @@ class Statistics extends Admin
         $this->c->get('Lang')->load('admin_index');
         $this->data = [];
         $this->titles[] = __('Server statistics');
-        $this->data['isAdmin'] = $this->c->get('user')['g_id'] == PUN_ADMIN;
+        $this->data['isAdmin'] = $this->c->get('user')->isAdmin;
         $this->data['linkInfo'] = $this->c->get('Router')->link('AdminInfo');
 
         // Get the server load averages (if possible)

+ 173 - 15
app/Models/Pages/Auth.php

@@ -31,12 +31,15 @@ class Auth extends Page
      */
     public function logout($args)
     {
-        $user = $this->c->get('user');
-
         $this->c->get('Lang')->load('login');
 
         if ($this->c->get('Csrf')->check($args['token'], 'Logout', $args)) {
-            $user->logout();
+            $user = $this->c->get('user');
+
+            $this->c->get('UserCookie')->deleteUserCookie();
+            $this->c->get('Online')->delete($user);
+            $this->c->get('UserMapper')->updateLastVisit($user);
+
             return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Logout redirect'));
         }
 
@@ -48,12 +51,12 @@ class Auth extends Page
      * @param array $args
      * @return Page
      */
-    public function login($args)
+    public function login(array $args)
     {
         $this->c->get('Lang')->load('login');
 
-        if (! isset($args['_name'])) {
-            $args['_name'] = '';
+        if (! isset($args['_username'])) {
+            $args['_username'] = '';
         }
         if (! isset($args['_redirect'])) {
             $args['_redirect'] = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
@@ -64,7 +67,7 @@ class Auth extends Page
             __('Login'),
         ];
         $this->data = [
-            'name' => $args['_name'],
+            'username' => $args['_username'],
             'formAction' => $this->c->get('Router')->link('Login'),
             'formToken' => $this->c->get('Csrf')->create('Login'),
             'forgetLink' => $this->c->get('Router')->link('Forget'),
@@ -86,7 +89,7 @@ class Auth extends Page
     {
         $this->c->get('Lang')->load('login');
 
-        $name = $this->c->get('Request')->postStr('name', '');
+        $username = $this->c->get('Request')->postStr('username', '');
         $password = $this->c->get('Request')->postStr('password', '');
         $token = $this->c->get('Request')->postStr('token');
         $save = $this->c->get('Request')->postStr('save');
@@ -95,7 +98,7 @@ class Auth extends Page
         $redirect = $this->c->get('Router')->validate($redirect, 'Index');
 
         $args = [
-            '_name' => $name,
+            '_username' => $username,
             '_redirect' => $redirect,
             '_save' => $save,
         ];
@@ -105,14 +108,12 @@ class Auth extends Page
             return $this->login($args);
         }
 
-        if (empty($name) || empty($password)) {
+        if (empty($username) || empty($password)) {
             $this->iswev['v'][] = __('Wrong user/pass');
             return $this->login($args);
         }
 
-        $result = $this->c->get('user')->login($name, $password, ! empty($save));
-
-        if (false === $result) {
+        if (! $this->loginProcess($username, $password, ! empty($save))) {
             $this->iswev['v'][] = __('Wrong user/pass');
             return $this->login($args);
         }
@@ -120,16 +121,74 @@ class Auth extends Page
         return $this->c->get('Redirect')->setUrl($redirect)->setMessage(__('Login redirect'));
     }
 
+    /**
+     * Вход на форум
+     * @param string $username
+     * @param string $password
+     * @param bool $save
+     * @return bool
+     */
+    protected function loginProcess($username, $password, $save)
+    {
+        $user = $this->c->get('UserMapper')->getUser($username, 'username');
+        if (null == $user) {
+            return false;
+        }
+
+        $authorized = false;
+        $hash = $user->password;
+        $update = [];
+
+        // For FluxBB by Visman 1.5.10.74 and above
+        if (strlen($hash) == 40) {
+            if (hash_equals($hash, sha1($password . $this->c->getParameter('SALT1')))) {
+                $hash = password_hash($password, PASSWORD_DEFAULT);
+                $update['password'] = $hash;
+                $authorized = true;
+            }
+        } else {
+            $authorized = password_verify($password, $hash);
+        }
+
+        if (! $authorized) {
+            return false;
+        }
+
+        // Update the status if this is the first time the user logged in
+        if ($user->isUnverified) {
+            $update['group_id'] = (int) $this->config['o_default_user_group'];
+        }
+
+        // перезаписываем ip админа и модератора - Visman
+        if ($user->isAdmMod
+            && $this->config['o_check_ip']
+            && $user->registrationIp != $this->c->get('user')->ip
+        ) {
+            $update['registration_ip'] = $this->c->get('user')->ip;
+        }
+
+        // изменения юзера в базе
+        $this->c->get('UserMapper')->updateUser($user->id, $update);
+        // обновления кэша
+        if (isset($update['group_id'])) {
+            $this->c->get('users_info update');
+        }
+        $this->c->get('Online')->delete($this->c->get('user'));
+        $this->c->get('UserCookie')->setUserCookie($user->id, $hash, $save);
+
+        return true;
+    }
+
     /**
      * Подготовка данных для страницы восстановления пароля
      * @param array $args
      * @return Page
      */
-    public function forget($args)
+    public function forget(array $args)
     {
         $this->c->get('Lang')->load('login');
 
-        $this->nameTpl = 'forget';
+        $this->nameTpl = 'login/forget';
         $this->onlinePos = 'forget';
 
         if (! isset($args['_email'])) {
@@ -174,7 +233,106 @@ class Auth extends Page
             return $this->forget($args);
         }
 
+        $user = $this->c->get('UserMapper')->getUser($email, 'email');
+        if (null == $user) {
+            $this->iswev['v'][] = __('Invalid email');
+            return $this->forget($args);
+        }
+
+        if (! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
+            $this->iswev['e'][] = __('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60));
+            return $this->forget($args);
+        }
+
+        $mail->setFolder($this->c->getParameter('DIR_LANG'))
+            ->setLanguage($user->language);
+
+        $key = 'p' . $this->c->get('Secury')->randomPass(75);
+        $link = $this->c->get('Router')->link('ChangePassword', ['email' => $email, 'key' => $key]);
+        $data = ['key' => $key, 'link' => $link];
+
+        if ($mail->send($email, 'change_password.tpl', $data)) {
+            $this->c->get('UserMapper')->updateUser($user->id, ['activate_string' => $key, 'last_email_sent' => time()]);
+            return $this->c->get('Message')->message(__('Forget mail', $this->config['o_admin_email']), false, 200);
+        } else {
+            return $this->c->get('Message')->message(__('Error mail', $this->config['o_admin_email']), true, 200);
+        }
+    }
+
+    /**
+     * Подготовка данных для формы изменения пароля
+     * @param array $args
+     * @return Page
+     */
+    public function changePass(array $args)
+    {
+        $this->nameTpl = 'login/password';
+        $this->onlinePos = 'password';
+
+        // что-то пошло не так
+        if (! $this->c->get('Mail')->valid($args['email'])
+            || ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
+            || empty($user->activateString)
+            || $user->activateString{0} !== 'p'
+            || ! hash_equals($user->activateString, $args['key'])
+        ) {
+            return $this->c->get('Message')->message(__('Bad request'), false);
+        }
+
+        $this->c->get('Lang')->load('login');
+        $this->c->get('Lang')->load('profile');
+
+        $this->titles = [
+            __('Change pass'),
+        ];
+        $this->data = [
+            'formAction' => $this->c->get('Router')->link('ChangePassword', $args),
+            'formToken' => $this->c->get('Csrf')->create('ChangePassword', $args),
+        ];
+
+        return $this;
+    }
+
+    /**
+     * Смена пароля
+     * @param array $args
+     * @return Page
+     */
+    public function changePassPost(array $args)
+    {
+        $token = $this->c->get('Request')->postStr('token');
+        $password = $this->c->get('Request')->postStr('password', '');
+        $password2 = $this->c->get('Request')->postStr('password2', '');
+
+        $this->c->get('Lang')->load('login');
+
+        // что-то пошло не так
+        if (! $this->c->get('Mail')->valid($args['email'])
+            || ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
+            || empty($user->activateString)
+            || $user->activateString{0} !== 'p'
+            || ! hash_equals($user->activateString, $args['key'])
+        ) {
+            return $this->c->get('Message')->message(__('Bad request'), false);
+        }
+
+        if (! $this->c->get('Csrf')->check($token, 'ChangePassword', $args)) {
+            $this->iswev['e'][] = __('Bad token');
+            return $this->changePass($args);
+        }
+        if (mb_strlen($password) < 6) {
+            $this->iswev['v'][] = __('Pass too short');
+            return $this->changePass($args);
+        }
+        if ($password !== $password2) {
+            $this->iswev['v'][] = __('Pass not match');
+            return $this->changePass($args);
+        }
 
+        $this->c->get('UserMapper')->updateUser($user->id, ['password' => password_hash($password, PASSWORD_DEFAULT), 'activate_string' => null]);
 
+        $this->c->get('Lang')->load('profile');
+        $this->iswev['s'][] = __('Pass updated');
+        return $this->login([]);
     }
 }

+ 5 - 73
app/Models/User.php

@@ -56,6 +56,11 @@ class User extends AbstractModel
         return $data;
     }
 
+    protected function getIsUnverified()
+    {
+        return $this->groupId == PUN_UNVERIFIED;
+    }
+
     protected function getIsGuest()
     {
         return $this->id < 2 || empty($this->gId) || $this->gId == PUN_GUEST;
@@ -102,77 +107,4 @@ class User extends AbstractModel
             return $this->data['style'];
         }
     }
-
-    /**
-     * Выход
-     */
-    public function logout()
-    {
-        if ($this->isGuest) {
-            return;
-        }
-
-        $this->userCookie->deleteUserCookie();
-        $this->c->get('Online')->delete($this);
-        // Update last_visit (make sure there's something to update it with)
-        if ($this->isLogged) {
-            $this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$this->logged.' WHERE id='.$this->id) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
-        }
-    }
-
-    /**
-     * Вход
-     * @param string $name
-     * @param string $password
-     * @param bool $save
-     * @return mixed
-     */
-    public function login($name, $password, $save)
-    {
-        $result = $this->db->query('SELECT u.id, u.group_id, u.username, u.password, u.registration_ip, g.g_moderator FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id WHERE u.username=\''.$this->db->escape($name).'\'') or error('Unable to fetch user info', __FILE__, __LINE__, $this->db->error());
-        $user = $this->db->fetch_assoc($result);
-        $this->db->free_result($result);
-
-        if (empty($user['id'])) {
-            return false;
-        }
-
-        $authorized = false;
-        // For FluxBB by Visman 1.5.10.74 and above
-        if (strlen($user['password']) == 40) {
-            if (hash_equals($user['password'], sha1($password . $this->c->getParameter('SALT1')))) {
-                $authorized = true;
-
-                $user['password'] = password_hash($password, PASSWORD_DEFAULT);
-                $this->db->query('UPDATE '.$this->db->prefix.'users SET password=\''.$this->db->escape($user['password']).'\' WHERE id='.$user['id']) or error('Unable to update user password', __FILE__, __LINE__, $this->db->error());
-            }
-        } else {
-            $authorized = password_verify($password, $user['password']);
-        }
-
-        if (! $authorized) {
-            return false;
-        }
-
-        // Update the status if this is the first time the user logged in
-        if ($user['group_id'] == PUN_UNVERIFIED)
-        {
-            $this->db->query('UPDATE '.$this->db->prefix.'users SET group_id='.$this->config['o_default_user_group'].' WHERE id='.$user['id']) or error('Unable to update user status', __FILE__, __LINE__, $this->db->error());
-
-            $this->c->get('users_info update');
-        }
-
-        // перезаписываем ip админа и модератора - Visman
-        if ($this->config['o_check_ip'] == '1' && $user['registration_ip'] != $this->ip)
-        {
-            if ($user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1')
-                $this->db->query('UPDATE '.$this->db->prefix.'users SET registration_ip=\''.$this->db->escape($this->ip).'\' WHERE id='.$user['id']) or error('Unable to update user IP', __FILE__, __LINE__, $this->db->error());
-        }
-
-        $this->c->get('Online')->delete($this);
-
-        $this->c->get('UserCookie')->setUserCookie($user['id'], $user['password'], $save);
-
-        return $user['id'];
-    }
 }

+ 69 - 4
app/Models/UserMapper.php

@@ -77,14 +77,79 @@ class UserMapper
 
     /**
      * Обновляет время последнего визита для конкретного пользователя
+     * @param User $user
+     */
+    public function updateLastVisit(User $user)
+    {
+        if ($user->isLogged) {
+            $this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$user->logged.' WHERE id='.$user->id) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
+        }
+    }
+
+    /**
+     * Получение пользователя по условию
+     * @param int|string
+     * @param string $field
+     * @return null|User
+     */
+    public function getUser($value, $field = 'id')
+    {
+        switch ($field) {
+            case 'id':
+                $where = 'u.id=' . (int) $value;
+                break;
+            case 'username':
+                $where = 'u.username=\'' . $this->db->escape($value) . '\'';
+                break;
+            case 'email':
+                $where = 'u.email=\'' . $this->db->escape($value) . '\'';
+                break;
+            default:
+                return null;
+        }
+        $result = $this->db->query('SELECT u.*, g.* FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'groups AS g ON u.group_id=g.g_id WHERE '.$where) or error('Unable to fetch user information', __FILE__, __LINE__, $this->db->error());
+
+        // найдено несколько пользователей
+        if ($this->db->num_rows($result) !== 1) {
+            return null;
+        }
+
+        $user = $this->db->fetch_assoc($result);
+        $this->db->free_result($result);
+
+        // найден гость
+        if ($user['id'] == 1) {
+            return null;
+        }
+
+        return new User($user, $this->c);
+    }
+
+    /**
+     * Обновить данные юзера
      * @param int $id
-     * @param int $time
+     * @param array $update
      */
-    public function updateLastVisit($id, $time)
+    public function updateUser($id, array $update)
     {
         $id = (int) $id;
-        $time = (int) $time;
-        $this->db->query('UPDATE '.$this->db->prefix.'users SET last_visit='.$time.' WHERE id='.$id) or error('Unable to update user visit data', __FILE__, __LINE__, $this->db->error());
+        if ($id < 2 || empty($update)) {
+            return;
+        }
+
+        $set = [];
+        foreach ($update as $field => $value) {
+            if (! is_string($field) || (null !== $value && ! is_int($value) && ! is_string($value))) {
+                return;
+            }
+            if (null === $value) {
+                $set[] = $field . '= NULL';
+            } else {
+                $set[] = $field . '=' . (is_int($value) ? $value : '\'' . $this->db->escape($value) . '\'');
+            }
+        }
+
+        $this->db->query('UPDATE '.$this->db->prefix.'users SET '.implode(', ', $set).' WHERE id='.$id) or error('Unable to update user data', __FILE__, __LINE__, $this->db->error());
     }
 
 }

+ 11 - 26
app/lang/English/login.po

@@ -12,12 +12,6 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Language: en\n"
 
-msgid "Login errors"
-msgstr "Login error"
-
-msgid "Login errors info"
-msgstr "The following error needs to be corrected before you can login:"
-
 msgid "Wrong user/pass"
 msgstr "Wrong username and/or password."
 
@@ -30,38 +24,29 @@ msgstr "Logged in successfully. Redirecting …"
 msgid "Logout redirect"
 msgstr "Logged out. Redirecting …"
 
-msgid "No email match"
-msgstr "There is no user registered with the email address"
-
 msgid "Request pass"
 msgstr "Request password"
 
-msgid "Request pass legend"
-msgstr "Enter the email address with which you registered"
-
 msgid "Request pass info"
-msgstr "A new password together with a link to activate the new password will be sent to that address."
+msgstr "An email will be sent to the specified address with instructions on how to change your password."
 
 msgid "Not registered"
 msgstr "Not registered yet?"
 
-msgid "Login legend"
-msgstr "Enter your username and password below"
-
 msgid "Remember me"
 msgstr "Remember me"
 
-msgid "Login info"
-msgstr "If you have not registered or have forgotten your password click on the appropriate link below."
-
-msgid "New password errors"
-msgstr "Password request error"
-
-msgid "New passworderrors info"
-msgstr "The following error needs to be corrected before a new password can be sent:"
-
 msgid "Forget mail"
-msgstr "An email has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at"
+msgstr "An email has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
+
+msgid "Error mail"
+msgstr "When sending email there was an error. Try later or contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
 
 msgid "Email flood"
 msgstr "This account has already requested a password reset in the past hour. Please wait %s minutes before requesting a new password again."
+
+msgid "Pass too short"
+msgstr "Passwords must be at least 6 characters long."
+
+msgid "Pass not match"
+msgstr "Passwords do not match."

+ 12 - 0
app/lang/English/mail/activate_email.tpl

@@ -0,0 +1,12 @@
+Subject: Change email address requested
+
+Hello <username>,
+
+You have requested to have a new email address assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your email address you should just ignore this message. Only if you visit the activation page below will your email address be changed. In order for the activation page to work, you must be logged in to the forum.
+
+To change your email address, please visit the following page:
+<activation_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/banned_email_change.tpl

@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' changed to banned email address: <email>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/banned_email_post.tpl

@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' posted with banned email address: <email>
+
+Post URL: <post_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/banned_email_register.tpl

@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' registered with banned email address: <email>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 14 - 0
app/lang/English/mail/change_password.tpl

@@ -0,0 +1,14 @@
+Subject: New password requested
+
+Hello <username>,
+
+You have requested to have a new password assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your password you should just ignore this message. Only if you visit the activation page below will your password be changed.
+
+Your new password is: <new_password>
+
+To change your password, please visit the following page:
+<activation_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/dupe_email_change.tpl

@@ -0,0 +1,9 @@
+Subject: Alert - Duplicate email detected
+
+User '<username>' changed to an email address that also belongs to: <dupe_list>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/dupe_email_register.tpl

@@ -0,0 +1,9 @@
+Subject: Alert - Duplicate email detected
+
+User '<username>' registered with an email address that also belongs to: <dupe_list>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 13 - 0
app/lang/English/mail/form_email.tpl

@@ -0,0 +1,13 @@
+Subject: <mail_subject>
+
+<sender> from <board_title> has sent you a message. You can reply to <sender> by replying to this email.
+
+The message reads as follows:
+-----------------------------------------------------------------------
+
+<mail_message>
+
+-----------------------------------------------------------------------
+
+--
+<board_mailer> Mailer

+ 10 - 0
app/lang/English/mail/form_pmsn.tpl

@@ -0,0 +1,10 @@
+Subject: New personal message: <mail_subject>
+
+Hello, <user>!
+
+<sender> from <board_title> has sent you a personal message.
+The message is located at <message_url>
+
+-- 
+<board_mailer> Mailer
+(Do not reply to this message)

+ 1 - 0
app/lang/English/mail/index.html

@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>

+ 11 - 0
app/lang/English/mail/new_reply.tpl

@@ -0,0 +1,11 @@
+Subject: Reply to topic: '<topic_subject>'
+
+<replier> has replied to the topic '<topic_subject>' to which you are subscribed. There may be more new replies, but this is the only notification you will receive until you visit the board again.
+
+The post is located at <post_url>
+
+You can unsubscribe by going to <unsubscribe_url> and clicking the Unsubscribe link at the bottom of the page.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 18 - 0
app/lang/English/mail/new_reply_full.tpl

@@ -0,0 +1,18 @@
+Subject: Reply to topic: '<topic_subject>'
+
+<replier> has replied to the topic '<topic_subject>' to which you are subscribed. There may be more new replies, but this is the only notification you will receive until you visit the board again.
+
+The post is located at <post_url>
+
+The message reads as follows:
+-----------------------------------------------------------------------
+
+<message>
+
+-----------------------------------------------------------------------
+
+You can unsubscribe by going to <unsubscribe_url> and clicking the Unsubscribe link at the bottom of the page.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 9 - 0
app/lang/English/mail/new_report.tpl

@@ -0,0 +1,9 @@
+Subject: Report(<forum_id>) - '<topic_subject>'
+
+User '<username>' has reported the following message: <post_url>
+
+Reason: <reason>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 11 - 0
app/lang/English/mail/new_topic.tpl

@@ -0,0 +1,11 @@
+Subject: New topic in forum: '<forum_name>'
+
+<poster> has posted a new topic '<topic_subject>' in the forum '<forum_name>', to which you are subscribed.
+
+The topic is located at <topic_url>
+
+You can unsubscribe by going to <unsubscribe_url> and clicking the Unsubscribe link at the bottom of the page.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 18 - 0
app/lang/English/mail/new_topic_full.tpl

@@ -0,0 +1,18 @@
+Subject: New topic in forum: '<forum_name>'
+
+<poster> has posted a new topic '<topic_subject>' in the forum '<forum_name>', to which you are subscribed.
+
+The topic is located at <topic_url>
+
+The message reads as follows:
+-----------------------------------------------------------------------
+
+<message>
+
+-----------------------------------------------------------------------
+
+You can unsubscribe by going to <unsubscribe_url> and clicking the Unsubscribe link at the bottom of the page.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 12 - 0
app/lang/English/mail/new_user.tpl

@@ -0,0 +1,12 @@
+Subject: Alert - New registration
+
+User '<username>' registered in the forums at <base_url>
+
+User profile: <profile_url>
+
+To administer this account, please visit the following page:
+<admin_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 12 - 0
app/lang/English/mail/rename.tpl

@@ -0,0 +1,12 @@
+Subject: User account renamed
+
+During an upgrade to the forums at <base_url> it was determined your username is too similar to an existing user. Your username has been changed accordingly.
+
+Old username: <old_username>
+New username: <new_username>
+
+We apologise for any inconvenience caused.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 12 - 0
app/lang/English/mail/welcome.tpl

@@ -0,0 +1,12 @@
+Subject: Welcome to <board_title>!
+
+Thank you for registering in the forums at <base_url>. Your account details are:
+
+Username: <username>
+Password: <password>
+
+Login at <login_url> to activate the account.
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)

+ 376 - 0
app/lang/English/profile.po

@@ -0,0 +1,376 @@
+#
+msgid ""
+msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Project-Id-Version: ForkBB\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
+"Last-Translator: \n"
+"Language-Team: ForkBB <mio.visman@yandex.ru>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en\n"
+
+msgid "Profile menu"
+msgstr "Profile menu"
+
+msgid "Section essentials"
+msgstr "Essentials"
+
+msgid "Section personal"
+msgstr "Personal"
+
+msgid "Section messaging"
+msgstr "Messaging"
+
+msgid "Section personality"
+msgstr "Personality"
+
+msgid "Section display"
+msgstr "Display"
+
+msgid "Section privacy"
+msgstr "Privacy"
+
+msgid "Section admin"
+msgstr "Administration"
+
+msgid "Username and pass legend"
+msgstr "Enter your username and password"
+
+msgid "Personal details legend"
+msgstr "Enter your personal details"
+
+msgid "Contact details legend"
+msgstr "Enter your messaging details"
+
+msgid "User activity"
+msgstr "User activity"
+
+msgid "Paginate info"
+msgstr "Enter the number of topics and posts you wish to view on each page."
+
+msgid "Pass key bad"
+msgstr "The specified password activation key was incorrect or has expired. Please re-request a new password. If that fails, contact the forum administrator at"
+
+msgid "Pass updated"
+msgstr "Your password has been updated. You can now login with your new password."
+
+msgid "Pass updated redirect"
+msgstr "Password updated. Redirecting …"
+
+msgid "Wrong pass"
+msgstr "Wrong old password."
+
+msgid "Change pass"
+msgstr "Change password"
+
+msgid "Change pass legend"
+msgstr "Enter and confirm your new password"
+
+msgid "Old pass"
+msgstr "Old password"
+
+msgid "New pass"
+msgstr "New password"
+
+msgid "Confirm new pass"
+msgstr "Confirm new password"
+
+msgid "Pass info"
+msgstr "Passwords must be at least 6 characters long. Passwords are case sensitive."
+
+msgid "Email key bad"
+msgstr "The specified email activation key was incorrect or has expired. Please re-request change of email address. If that fails, contact the forum administrator at"
+
+msgid "Email updated"
+msgstr "Your email address has been updated."
+
+msgid "Activate email sent"
+msgstr "An email has been sent to the specified address with instructions on how to activate the new email address. If it doesn\"t arrive you can contact the forum administrator at"
+
+msgid "Email legend"
+msgstr "Enter your new email address"
+
+msgid "Email instructions"
+msgstr "An email will be sent to your new address with an activation link. You must click the link in the email you receive to activate the new address."
+
+msgid "Change email"
+msgstr "Change email address"
+
+msgid "New email"
+msgstr "New email"
+
+msgid "Avatars disabled"
+msgstr "The administrator has disabled avatar support."
+
+msgid "Too large ini"
+msgstr "The selected file was too large to upload. The server didn\"t allow the upload."
+
+msgid "Partial upload"
+msgstr "The selected file was only partially uploaded. Please try again."
+
+msgid "No tmp directory"
+msgstr "PHP was unable to save the uploaded file to a temporary location."
+
+msgid "No file"
+msgstr "You did not select a file for upload."
+
+msgid "Bad type"
+msgstr "The file you tried to upload is not of an allowed type. Allowed types are gif, jpeg and png."
+
+msgid "Too wide or high"
+msgstr "The file you tried to upload is wider and/or higher than the maximum allowed"
+
+msgid "Too large"
+msgstr "The file you tried to upload is larger than the maximum allowed"
+
+msgid "pixels"
+msgstr "pixels"
+
+msgid "bytes"
+msgstr "bytes"
+
+msgid "Move failed"
+msgstr "The server was unable to save the uploaded file. Please contact the forum administrator at"
+
+msgid "Unknown failure"
+msgstr "An unknown error occurred. Please try again."
+
+msgid "Avatar upload redirect"
+msgstr "Avatar uploaded. Redirecting …"
+
+msgid "Avatar deleted redirect"
+msgstr "Avatar deleted. Redirecting …"
+
+msgid "Avatar desc"
+msgstr "An avatar is a small image that will be displayed under your username in your posts. It must not be any bigger than"
+
+msgid "Upload avatar"
+msgstr "Upload avatar"
+
+msgid "Upload avatar legend"
+msgstr "Enter an avatar file to upload"
+
+msgid "Delete avatar"
+msgstr "Delete avatar"
+
+msgid "File"
+msgstr "File"
+
+msgid "Upload"
+msgstr "Upload"
+
+msgid "Forbidden title"
+msgstr "The title you entered contains a forbidden word. You must choose a different title."
+
+msgid "Profile redirect"
+msgstr "Profile updated. Redirecting …"
+
+msgid "Users profile"
+msgstr "%s\"s profile"
+
+msgid "Username info"
+msgstr "Username: %s"
+
+msgid "Email info"
+msgstr "Email: %s"
+
+msgid "Posts info"
+msgstr "Posts: %s"
+
+msgid "Registered info"
+msgstr "Registered: %s"
+
+msgid "Last post info"
+msgstr "Last post: %s"
+
+msgid "Last visit info"
+msgstr "Last visit: %s"
+
+msgid "Show posts"
+msgstr "Show all posts"
+
+msgid "Show topics"
+msgstr "Show all topics"
+
+msgid "Show subscriptions"
+msgstr "Show all subscriptions"
+
+msgid "Realname"
+msgstr "Real name"
+
+msgid "Location"
+msgstr "Location"
+
+msgid "Website"
+msgstr "Website"
+
+msgid "Invalid website URL"
+msgstr "The website URL you entered is invalid."
+
+msgid "Website not allowed"
+msgstr "You are not allowed to add a website to your profile yet."
+
+msgid "Jabber"
+msgstr "Jabber"
+
+msgid "ICQ"
+msgstr "ICQ"
+
+msgid "MSN"
+msgstr "Microsoft Account"
+
+msgid "AOL IM"
+msgstr "AOL IM"
+
+msgid "Yahoo"
+msgstr "Yahoo! Messenger"
+
+msgid "Avatar"
+msgstr "Avatar"
+
+msgid "Signature"
+msgstr "Signature"
+
+msgid "Sig max size"
+msgstr "Max length: %s characters / Max lines: %s"
+
+msgid "Avatar legend"
+msgstr "Set your avatar display options"
+
+msgid "Avatar info"
+msgstr "An avatar is a small image that will be displayed with all your posts. You can upload an avatar by clicking the link below."
+
+msgid "Change avatar"
+msgstr "Change avatar"
+
+msgid "Signature legend"
+msgstr "Compose your signature"
+
+msgid "Signature info"
+msgstr "A signature is a small piece of text that is attached to your posts. In it, you can enter just about anything you like. Perhaps you would like to enter your favourite quote or your star sign. It\"s up to you! In your signature you can use BBCode if it is allowed in this particular forum. You can see the features that are allowed/enabled listed below whenever you edit your signature."
+
+msgid "Sig preview"
+msgstr "Current signature preview:"
+
+msgid "No sig"
+msgstr "No signature currently stored in profile."
+
+msgid "Signature quote/code/list/h"
+msgstr "The quote, code, hr, size, audio, video, list, spoiler, and heading BBCodes are not allowed in signatures."
+
+msgid "Topics per page"
+msgstr "Topics"
+
+msgid "Posts per page"
+msgstr "Posts"
+
+msgid "Leave blank"
+msgstr "Leave blank to use forum default."
+
+msgid "Subscription legend"
+msgstr "Set your subscription options"
+
+msgid "Notify full"
+msgstr "Include a plain text version of new posts in subscription notification emails."
+
+msgid "Auto notify full"
+msgstr "Automatically subscribe to every topic you post in."
+
+msgid "Show smilies"
+msgstr "Show smilies as graphic icons."
+
+msgid "Show images"
+msgstr "Show images in posts."
+
+msgid "Show images sigs"
+msgstr "Show images in user signatures."
+
+msgid "Show avatars"
+msgstr "Show user avatars in posts."
+
+msgid "Show sigs"
+msgstr "Show user signatures."
+
+msgid "Style legend"
+msgstr "Select your preferred style"
+
+msgid "Styles"
+msgstr "Styles"
+
+msgid "Admin note"
+msgstr "Admin note"
+
+msgid "Pagination legend"
+msgstr "Enter your pagination options"
+
+msgid "Post display legend"
+msgstr "Set your options for viewing posts"
+
+msgid "Post display info"
+msgstr "If you are on a slow connection, disabling these options, particularly showing images in posts and signatures, will make pages load faster."
+
+msgid "Instructions"
+msgstr "When you update your profile, you will be redirected back to this page."
+
+msgid "Group membership legend"
+msgstr "Choose user group"
+
+msgid "Save"
+msgstr "Save"
+
+msgid "Set mods legend"
+msgstr "Set moderator access"
+
+msgid "Moderator in info"
+msgstr "Choose which forums this user should be allowed to moderate. Note: This only applies to moderators. Administrators always have full permissions in all forums."
+
+msgid "Update forums"
+msgstr "Update forums"
+
+msgid "Delete ban legend"
+msgstr "Delete (administrators only) or ban user"
+
+msgid "Delete user"
+msgstr "Delete user"
+
+msgid "Ban user"
+msgstr "Ban user"
+
+msgid "Confirm delete legend"
+msgstr "Important: read before deleting user"
+
+msgid "Confirm delete user"
+msgstr "Confirm delete user"
+
+msgid "Confirmation info"
+msgstr "Please confirm that you want to delete the user"
+
+msgid "Delete warning"
+msgstr "Warning! Deleted users and/or posts cannot be restored. If you choose not to delete the posts made by this user, the posts can only be deleted manually at a later time."
+
+msgid "Delete posts"
+msgstr "Delete any posts and topics this user has made."
+
+msgid "Delete"
+msgstr "Delete"
+
+msgid "User delete redirect"
+msgstr "User deleted. Redirecting …"
+
+msgid "User promote redirect"
+msgstr "User promoted. Redirecting …"
+
+msgid "Group membership redirect"
+msgstr "Group membership saved. Redirecting …"
+
+msgid "Update forums redirect"
+msgstr "Forum moderator rights updated. Redirecting …"
+
+msgid "Ban redirect"
+msgstr "Redirecting …"
+
+msgid "No delete admin message"
+msgstr "Administrators cannot be deleted. In order to delete this user, you must first move him/her to a different user group."

+ 11 - 26
app/lang/Russian/login.po

@@ -12,12 +12,6 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Language: ru\n"
 
-msgid "Login errors"
-msgstr "Ошибки входа на форум"
-
-msgid "Login errors info"
-msgstr "Следующие ошибки необходимо исправить, чтобы войти на форум:"
-
 msgid "Wrong user/pass"
 msgstr "Неверное имя и/или пароль. Имя и пароль чувствительны к регистру!"
 
@@ -30,38 +24,29 @@ msgstr "Успешный вход. Переадресация &hellip;"
 msgid "Logout redirect"
 msgstr "Выход произведён. Переадресация &hellip;"
 
-msgid "No email match"
-msgstr "На форуме нет пользователя с почтовым адресом"
-
 msgid "Request pass"
 msgstr "Восстановление пароля"
 
-msgid "Request pass legend"
-msgstr "Введите почтовый адрес, на который вы регистрировались"
-
 msgid "Request pass info"
-msgstr "Новый пароль и ссылка для активации будут высланы на указанный адрес."
+msgstr "Инструкция по смене пароля будет выслана на указанный адрес."
 
 msgid "Not registered"
 msgstr "Ещё не зарегистрированы?"
 
-msgid "Login legend"
-msgstr "Введите имя пользователя и пароль"
-
 msgid "Remember me"
 msgstr "Запомнить меня"
 
-msgid "Login info"
-msgstr "Если вы ещё не зарегистрированы или забыли пароль, кликните на подходящей ссылке ниже."
-
-msgid "New password errors"
-msgstr "Ошибки при запросе пароля"
-
-msgid "New passworderrors info"
-msgstr "Следующие ошибки нужно исправит, чтобы получить новый пароль:"
-
 msgid "Forget mail"
-msgstr "Письмо с инструкцией по изменению пароля было выслано на указанный вами почтовый адрес. Если вы не получите его, свяжитесь с администрацией форума, используя почтовый адрес"
+msgstr "Письмо с инструкцией по изменению пароля было выслано на указанный вами почтовый адрес. Если вы не получите его, свяжитесь с администрацией форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
+
+msgid "Error mail"
+msgstr "При отправки письма возникла ошибка. Попробуйте позже или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
 
 msgid "Email flood"
 msgstr "Для этой учетной записи недавно уже запрашивали новый пароль. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
+
+msgid "Pass too short"
+msgstr "Пароль должен состоять минимум из 6 символов."
+
+msgid "Pass not match"
+msgstr "Пароли не совпадают."

+ 12 - 0
app/lang/Russian/mail/activate_email.tpl

@@ -0,0 +1,12 @@
+Subject: Запрос на смену e-mail
+
+Здравствуйте <username>,
+
+Кто-то, возможно вы, сделал запрос на смену e-mail вашего аккаунта на <base_url>. Если это не вы или если вы не хотите менять e-mail, просто проигнорируйте это письмо. Ваш регистрационный e-mail поменяется только если вы посетите активационную ссылку. Чтобы активационная ссылка сработала, необходимо зарегистрироваться на форуме.
+
+Чтобы поменять адрес e-mail, пожалуйста пройдите по этой ссылке:
+<activation_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/banned_email_change.tpl

@@ -0,0 +1,9 @@
+Subject: Внимание - Обнаружен забаненный адрес email
+
+Пользователь '<username>' изменил адрес email на забаненный: <email>
+
+Адрес профиля пользователя: <profile_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/banned_email_post.tpl

@@ -0,0 +1,9 @@
+Subject: Внимание - Обнаружен забаненный адрес email
+
+Пользователь '<username>' оставил сообщение с указанием забаненного адреса email: <email>
+
+Адрес сообщения: <post_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/banned_email_register.tpl

@@ -0,0 +1,9 @@
+Subject: Внимание - Обнаружен забаненный адрес email
+
+Пользователь '<username>' зарегистрировался с указанием забаненного адреса email: <email>
+
+Адрес профиля пользователя: <profile_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 14 - 0
app/lang/Russian/mail/change_password.tpl

@@ -0,0 +1,14 @@
+Subject: Запрос на смену пароля
+
+Здравствуйте <username>,
+
+Кто-то, возможно вы, сделал запрос на смену пароля аккаунта на форуме <base_url>. Если это не вы или если вы не хотите менять пароль, просто проигнорируйте это письмо. Ваш пароль изменится только если вы посетите активационную ссылку.
+
+Ваш новый пароль: <new_password>
+
+Чтобы установить этот пароль, пожалуйста пройдите по этой ссылке:
+<activation_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/dupe_email_change.tpl

@@ -0,0 +1,9 @@
+Subject: Внимание - Обнаружено повторение адреса email
+
+Пользователь '<username>' изменил адрес email на принадлежащий также: <dupe_list>
+
+Адрес профиля пользователя: <profile_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/dupe_email_register.tpl

@@ -0,0 +1,9 @@
+Subject: Внимание - Обнаружено повторение адреса email
+
+Пользователь '<username>' зарегистрировался с указанием адреса email на принадлежащий также: <dupe_list>
+
+Адрес профиля пользователя: <profile_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 13 - 0
app/lang/Russian/mail/form_email.tpl

@@ -0,0 +1,13 @@
+Subject: <mail_subject>
+
+<sender> с форума <board_title> послал вам сообщение. Вы можете ответить <sender> напрямую на его e-mail, просто ответив на письмо.
+
+Само сообщение:
+-----------------------------------------------------------------------
+
+<mail_message>
+
+-----------------------------------------------------------------------
+
+--
+Отправитель <board_mailer>

+ 10 - 0
app/lang/Russian/mail/form_pmsn.tpl

@@ -0,0 +1,10 @@
+Subject: Новое личное сообщение: <mail_subject>
+
+Здравствуйте, <user>!
+
+Участник <sender> форума <board_title> отправил Вам личное сообщение.
+Сообщение можно прочитать по адресу <message_url>
+
+-- 
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 8 - 0
app/lang/Russian/mail/index.html

@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>

+ 11 - 0
app/lang/Russian/mail/new_reply.tpl

@@ -0,0 +1,11 @@
+Subject: Ответ в теме: '<topic_subject>'
+
+<replier> ответил в теме '<topic_subject>', на которую вы подписаны. Возможно есть и другие ответы, мы всего лишь рассылаем извещения о том, что стоит посетить форум снова.
+
+Адрес сообщения <post_url>
+
+Вы можете снять подписку с темы перейдя по этой ссылке <unsubscribe_url> и нажав 'Отказаться от подписки' внизу страницы.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 18 - 0
app/lang/Russian/mail/new_reply_full.tpl

@@ -0,0 +1,18 @@
+Subject: Ответ в теме: '<topic_subject>'
+
+<replier> ответил в теме '<topic_subject>', на которую вы подписаны. Возможно есть и другие ответы, мы всего лишь рассылаем извещения о том, что стоит посетить форум снова.
+
+Адрес сообщения <post_url>
+
+Само сообщение:
+-----------------------------------------------------------------------
+
+<message>
+
+-----------------------------------------------------------------------
+
+Вы можете снять подписку с темы перейдя по этой ссылке <unsubscribe_url> и нажав 'Отказаться от подписки' внизу страницы.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 9 - 0
app/lang/Russian/mail/new_report.tpl

@@ -0,0 +1,9 @@
+Subject: Сигнал(<forum_id>) - '<topic_subject>'
+
+Пользователь '<username>' отправил сигнал на сообщение: <post_url>
+
+Причина: <reason>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 11 - 0
app/lang/Russian/mail/new_topic.tpl

@@ -0,0 +1,11 @@
+Subject: Новая тема в разделе: '<forum_name>'
+
+<poster> создал новую тему '<topic_subject>' в разделе '<forum_name>', на который вы подписаны.
+
+Адрес новой темы <topic_url>
+
+Вы можете снять подписку с раздела перейдя по этой ссылке <unsubscribe_url> и нажав 'Отказаться от подписки' внизу страницы.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 18 - 0
app/lang/Russian/mail/new_topic_full.tpl

@@ -0,0 +1,18 @@
+Subject: Новая тема в разделе: '<forum_name>'
+
+<poster> создал новую тему '<topic_subject>' в разделе '<forum_name>', на который вы подписаны.
+
+Адрес новой темы <topic_url>
+
+Само сообщение:
+-----------------------------------------------------------------------
+
+<message>
+
+-----------------------------------------------------------------------
+
+Вы можете снять подписку с раздела перейдя по этой ссылке <unsubscribe_url> и нажав 'Отказаться от подписки' внизу страницы.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 12 - 0
app/lang/Russian/mail/new_user.tpl

@@ -0,0 +1,12 @@
+Subject: Внимание - Новая регистрация
+
+Пользователь '<username>' зарегистрировался на форуме по адресу <base_url>
+
+Адрес профиля пользователя: <profile_url>
+
+Для управления этой учетной записью, пожалуйста, посетите следующую страницу:
+<admin_url>
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 12 - 0
app/lang/Russian/mail/rename.tpl

@@ -0,0 +1,12 @@
+Subject: Учетная запись пользователя переименована
+
+Во время обновления форума по адресу <base_url> было решено, что Ваше имя пользователя слишком похоже на имя другого участника форума. Ваше имя пользователя было изменено.
+
+Старое имя: <old_username>
+Новое имя: <new_username>
+
+Мы приносим извинения за это неудобство.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 12 - 0
app/lang/Russian/mail/welcome.tpl

@@ -0,0 +1,12 @@
+Subject: Добро пожаловать на <board_title>!
+
+Добро пожаловать на форум по адресу <base_url>. Детали вашего аккаунта:
+
+Пользователь: <username>
+Пароль: <password>
+
+Залогиньтесь на странице <login_url> чтобы активировать аккаунт.
+
+--
+Отправитель <board_mailer>
+(Не отвечайте на это сообщение)

+ 376 - 0
app/lang/Russian/profile.po

@@ -0,0 +1,376 @@
+#
+msgid ""
+msgstr ""
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Project-Id-Version: ForkBB\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
+"Last-Translator: \n"
+"Language-Team: ForkBB <mio.visman@yandex.ru>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ru\n"
+
+msgid "Profile menu"
+msgstr "Профиль"
+
+msgid "Section essentials"
+msgstr "Основное"
+
+msgid "Section personal"
+msgstr "Личное"
+
+msgid "Section messaging"
+msgstr "Пейджеры"
+
+msgid "Section personality"
+msgstr "Аватара/подпись"
+
+msgid "Section display"
+msgstr "Вид форума"
+
+msgid "Section privacy"
+msgstr "Приватность"
+
+msgid "Section admin"
+msgstr "Модерирование"
+
+msgid "Username and pass legend"
+msgstr "Настройка имени пользователя и пароля"
+
+msgid "Personal details legend"
+msgstr "Настройка персональных данных"
+
+msgid "Contact details legend"
+msgstr "Настройка контактных данных"
+
+msgid "User activity"
+msgstr "Активность пользователя"
+
+msgid "Paginate info"
+msgstr "Укажите число тем и сообщений, выводимых на страницу."
+
+msgid "Pass key bad"
+msgstr "Указанный ключ активации пароля неверен или истек срок его действия. Пожалуйста, повторно запросите новый пароль. Если ничего не получится, то свяжитесь с администрацией; почтовый адрес для связи"
+
+msgid "Pass updated"
+msgstr "Ваш пароль изменён. Вы можете войти на форум с новым паролем."
+
+msgid "Pass updated redirect"
+msgstr "Пароль изменён. Переадресация &hellip;"
+
+msgid "Wrong pass"
+msgstr "Ошибка в старом пароле."
+
+msgid "Change pass"
+msgstr "Смена пароля"
+
+msgid "Change pass legend"
+msgstr "Введите и подтвердите новый пароль"
+
+msgid "Old pass"
+msgstr "Старый пароль"
+
+msgid "New pass"
+msgstr "Новый пароль"
+
+msgid "Confirm new pass"
+msgstr "Ещё раз"
+
+msgid "Pass info"
+msgstr "Пароль должен состоять минимум из 6 символов. Пароль чувствителен к регистру вводимых букв."
+
+msgid "Email key bad"
+msgstr "Указанный ключ активации почтового адреса неверен или истек срок его действия. Пожалуйста, повторно запросите смену почтового адреса. Если ничего не получится, то свяжитесь с администрацией; почтовый адрес для связи"
+
+msgid "Email updated"
+msgstr "Ваш почтовый адрес изменён."
+
+msgid "Activate email sent"
+msgstr "На указанный почтовый адрес было отправлено письмо с инструкциями по активации новой почты. Если вы не получите письмо, то свяжитесь с администрацией; почтовый адрес для связи"
+
+msgid "Email legend"
+msgstr "Ввод нового почтового адреса"
+
+msgid "Email instructions"
+msgstr "На новый почтовый адрес будет отправлено письмо со ссылкой для активации. Вы должны будете перейти по ссылке, указанной в письме, для завершения процедуры изменения параметров."
+
+msgid "Change email"
+msgstr "Изменение почтового адреса"
+
+msgid "New email"
+msgstr "Новый почтовый адрес"
+
+msgid "Avatars disabled"
+msgstr "Администратор выключил использование аватар."
+
+msgid "Too large ini"
+msgstr "Выбранный файл слишком велик для загрузки. Сервер отклонил загрузку."
+
+msgid "Partial upload"
+msgstr "Выбранный файл был загружен частично. Пожалуйста, повторите попытку."
+
+msgid "No tmp directory"
+msgstr "PHP не может сохранить загруженный файл по временному адресу."
+
+msgid "No file"
+msgstr "Не выбран файл для загрузки."
+
+msgid "Bad type"
+msgstr "Загрузка файла с используемым расширением запрещена. Разрешенные расширения: gif, jpeg и png."
+
+msgid "Too wide or high"
+msgstr "Выбранный файл превышает максимально допустимые размеры"
+
+msgid "Too large"
+msgstr "Выбранный файл больше максимально допустимых размеров"
+
+msgid "pixels"
+msgstr "точек"
+
+msgid "bytes"
+msgstr "байт"
+
+msgid "Move failed"
+msgstr "Сервер не смог сохранить загруженный файл. Свяжитесь с администрацией; почтовый адрес для связи"
+
+msgid "Unknown failure"
+msgstr "Произошла неизвестная ошибка. Пожалуйста, повторите попытку."
+
+msgid "Avatar upload redirect"
+msgstr "Аватара загружена. Переадресация &hellip;"
+
+msgid "Avatar deleted redirect"
+msgstr "Аватара удалена. Переадресация &hellip;"
+
+msgid "Avatar desc"
+msgstr "Аватара это маленькая картинка, которая будет выводиться возле каждого вашего сообщения. Она должна быть не больше чем"
+
+msgid "Upload avatar"
+msgstr "Загрузка аватары"
+
+msgid "Upload avatar legend"
+msgstr "Укажите файл с аватарой"
+
+msgid "Delete avatar"
+msgstr "Удалить аватару"
+
+msgid "File"
+msgstr "Файл"
+
+msgid "Upload"
+msgstr "Загрузить"
+
+msgid "Forbidden title"
+msgstr "В вашем титуле содержится запрещенное слово. Вы должны внести изменение."
+
+msgid "Profile redirect"
+msgstr "Профиль обновлен. Переадресация &hellip;"
+
+msgid "Users profile"
+msgstr "Профиль пользователя %s"
+
+msgid "Username info"
+msgstr "Пользователь: %s"
+
+msgid "Email info"
+msgstr "Email: %s"
+
+msgid "Posts info"
+msgstr "Сообщений: %s"
+
+msgid "Registered info"
+msgstr "Дата регистрации: %s"
+
+msgid "Last post info"
+msgstr "Последнее сообщение: %s"
+
+msgid "Last visit info"
+msgstr "Последний визит: %s"
+
+msgid "Show posts"
+msgstr "Просмотреть все сообщения"
+
+msgid "Show topics"
+msgstr "Просмотреть все темы"
+
+msgid "Show subscriptions"
+msgstr "Просмотреть все подписки"
+
+msgid "Realname"
+msgstr "Настоящее имя"
+
+msgid "Location"
+msgstr "Местоположение"
+
+msgid "Website"
+msgstr "Сайт"
+
+msgid "Invalid website URL"
+msgstr "Введенный адрес сайта неверен."
+
+msgid "Website not allowed"
+msgstr "Сейчас вам запрещено указывать ссылки на сайты."
+
+msgid "Jabber"
+msgstr "Jabber"
+
+msgid "ICQ"
+msgstr "ICQ"
+
+msgid "MSN"
+msgstr "Microsoft Account"
+
+msgid "AOL IM"
+msgstr "AOL IM"
+
+msgid "Yahoo"
+msgstr "Yahoo! Messenger"
+
+msgid "Avatar"
+msgstr "Аватара"
+
+msgid "Signature"
+msgstr "Подпись"
+
+msgid "Sig max size"
+msgstr "Макс. длина: %s символов / Макс. число строк: %s"
+
+msgid "Avatar legend"
+msgstr "Наcтройка аватары"
+
+msgid "Avatar info"
+msgstr "Аватара - это маленькая картинка, которая будет выводиться возле каждого вашего сообщения. Вы можете загрузить аватару по ссылке ниже."
+
+msgid "Change avatar"
+msgstr "Сменить аватару"
+
+msgid "Signature legend"
+msgstr "Настройка подписи"
+
+msgid "Signature info"
+msgstr "Подпись - это небольшой текст, присоединяемый к вашему сообщению. Здесь вы можете указать что угодно. Возможно, вы захотите поместить сюда любимую цитату или скан вашей росписи. Подпись может содержать BB-коды, если это не запрещено настройками форума. Вы можете увидеть, какие именно возможности включены в примечании под полем ввода подписи."
+
+msgid "Sig preview"
+msgstr "Предварительный просмотр текущей подписи:"
+
+msgid "No sig"
+msgstr "Нет сохраненной подписи."
+
+msgid "Signature quote/code/list/h"
+msgstr "BB-коды quote, code, hr, size, audio, video, spoiler и list запрещены в подписи."
+
+msgid "Topics per page"
+msgstr "Тем"
+
+msgid "Posts per page"
+msgstr "Сообщений"
+
+msgid "Leave blank"
+msgstr "Не вводите ничего, для использования настроек по умолчанию."
+
+msgid "Subscription legend"
+msgstr "Настройка опций вашей подписки"
+
+msgid "Notify full"
+msgstr "Включать в письмо-уведомление текстовую часть новых сообщений."
+
+msgid "Auto notify full"
+msgstr "Автоматически подписываться на темы, в которых публикуете сообщения."
+
+msgid "Show smilies"
+msgstr "Показывать смайлики как графику"
+
+msgid "Show images"
+msgstr "Показывать изображения в сообщениях"
+
+msgid "Show images sigs"
+msgstr "Показывать изображения в подписях"
+
+msgid "Show avatars"
+msgstr "Показывать аватары пользователей"
+
+msgid "Show sigs"
+msgstr "Показывать подписи пользователей"
+
+msgid "Style legend"
+msgstr "Настройка стиля оформления"
+
+msgid "Styles"
+msgstr "Стили"
+
+msgid "Admin note"
+msgstr "Примечание администрации"
+
+msgid "Pagination legend"
+msgstr "Настройка постраничного вывода"
+
+msgid "Post display legend"
+msgstr "Тонкая настройка параметров просмотра сообщений"
+
+msgid "Post display info"
+msgstr "Если у вас медленное соединение, отключите некоторые из настроек. Например, отключение вывода изображений в сообщениях и подписях, существенно ускорит загрузку страниц."
+
+msgid "Instructions"
+msgstr "После сохранения изменений, вы автоматически вернетесь на эту страницу."
+
+msgid "Group membership legend"
+msgstr "Выбор группы пользователя"
+
+msgid "Save"
+msgstr "Сохранить"
+
+msgid "Set mods legend"
+msgstr "Настройка прав модератора"
+
+msgid "Moderator in info"
+msgstr "Выберите разделы, которые будет модерировать этот пользователь.<br /> Замечание: Применимо только к модераторам. Администраторы могут модерировать любой форум."
+
+msgid "Update forums"
+msgstr "Обновить разделы"
+
+msgid "Delete ban legend"
+msgstr "Удалить (только для администраторов) или забанить пользователя"
+
+msgid "Delete user"
+msgstr "Удалить"
+
+msgid "Ban user"
+msgstr "Забанить"
+
+msgid "Confirm delete legend"
+msgstr "ВАЖНО: прочтите перед удалением пользователя"
+
+msgid "Confirm delete user"
+msgstr "Подтверждение удаления учетной записи"
+
+msgid "Confirmation info"
+msgstr "Пожалуйста, подтвердите свое желание удалить учетную запись пользователя"
+
+msgid "Delete warning"
+msgstr "Внимание! Удалённого пользователя и/или его сообщения невозможно восстановить. Если вы не хотите удалять сообщения вместе с пользователями, то их можно будет удалить позже, в ручном режиме."
+
+msgid "Delete posts"
+msgstr "Удалить все темы и сообщения пользователя."
+
+msgid "Delete"
+msgstr "Удалить"
+
+msgid "User delete redirect"
+msgstr "Пользователь удален. Переадресация &hellip;"
+
+msgid "User promote redirect"
+msgstr "Пользователь перемещен. Переадресация &hellip;"
+
+msgid "Group membership redirect"
+msgstr "Группа пользователя изменена. Переадресация &hellip;"
+
+msgid "Update forums redirect"
+msgstr "Права модератора обновлены. Переадресация &hellip;"
+
+msgid "Ban redirect"
+msgstr "Переадресация &hellip;"
+
+msgid "No delete admin message"
+msgstr "Учетная запись администратора не может быть удалена. Чтобы удалить эту учетную запись, надо переместить пользователя в группу с более низкими правами."

+ 2 - 2
app/templates/login.tpl

@@ -5,8 +5,8 @@
         <form class="f-form" method="post" action="{!! $formAction !!}">
           <input type="hidden" name="token" value="{!! $formToken !!}">
           <input type="hidden" name="redirect" value="{{ $formRedirect }}">
-          <label class="f-child1" for="id-name">{!! __('Username') !!}</label>
-          <input required id="id-name" type="text" name="name" value="{{ $name }}" maxlength="25" autofocus="autofocus" spellcheck="false" tabindex="1">
+          <label class="f-child1" for="id-username">{!! __('Username') !!}</label>
+          <input required id="id-username" type="text" name="username" value="{{ $username }}" maxlength="25" autofocus="autofocus" spellcheck="false" tabindex="1">
           <label class="f-child1" for="id-password">{!! __('Password') !!}<a class="f-forgetlink" href="{!! $forgetLink !!}" tabindex="5">{!! __('Forgotten pass') !!}</a></label>
           <input required id="id-password" type="password" name="password" tabindex="2">
 @if($formSave)

+ 0 - 0
app/templates/forget.tpl → app/templates/login/forget.tpl


+ 15 - 0
app/templates/login/password.tpl

@@ -0,0 +1,15 @@
+@extends('layouts/main')
+    <section class="f-main f-login">
+      <div class="f-wdiv">
+        <h2>{!! __('Change pass') !!}</h2>
+        <form class="f-form" method="post" action="{!! $formAction !!}">
+          <input type="hidden" name="token" value="{!! $formToken !!}">
+          <label class="f-child1" for="id-password">{!! __('New pass') !!}</label>
+          <input required id="id-password" type="password" name="password" pattern=".{6,}" autofocus="autofocus" tabindex="1">
+          <label class="f-child1" for="id-password2">{!! __('Confirm new pass') !!}</label>
+          <input required id="id-password2" type="password" name="password2" pattern=".{6,}" tabindex="2">
+          <label class="f-child2">{!! __('Pass info') !!}</label>
+          <input class="f-btn" type="submit" name="login" value="{!! __('Save') !!}" tabindex="3">
+        </form>
+      </div>
+    </section>