From 41ed9e9410024e7e302185f46077d9172fdb63b6 Mon Sep 17 00:00:00 2001 From: mbugeia Date: Tue, 8 Sep 2015 22:16:28 +0200 Subject: [PATCH] Update to v1.0.18 --- conf/config.php | 43 + sources/app/Auth/Google.php | 4 +- sources/app/Controller/Action.php | 2 + sources/app/Controller/Base.php | 7 +- sources/app/Controller/Board.php | 28 +- sources/app/Controller/Project.php | 15 +- sources/app/Controller/Subtask.php | 2 +- sources/app/Controller/User.php | 10 +- sources/app/Core/Router.php | 41 + sources/app/Core/Session.php | 11 +- sources/app/Locale/da_DK/translations.php | 52 + sources/app/Locale/de_DE/translations.php | 52 + sources/app/Locale/es_ES/translations.php | 602 +++--- sources/app/Locale/fi_FI/translations.php | 52 + sources/app/Locale/fr_FR/translations.php | 54 +- sources/app/Locale/hu_HU/translations.php | 52 + sources/app/Locale/it_IT/translations.php | 52 + sources/app/Locale/ja_JP/translations.php | 52 + sources/app/Locale/nl_NL/translations.php | 52 + sources/app/Locale/pl_PL/translations.php | 52 + sources/app/Locale/pt_BR/translations.php | 166 +- sources/app/Locale/ru_RU/translations.php | 52 + .../app/Locale/sr_Latn_RS/translations.php | 52 + sources/app/Locale/sv_SE/translations.php | 166 +- sources/app/Locale/th_TH/translations.php | 52 + sources/app/Locale/tr_TR/translations.php | 52 + sources/app/Locale/zh_CN/translations.php | 176 +- sources/app/Model/Acl.php | 96 +- sources/app/Model/Action.php | 2 + sources/app/Model/Authentication.php | 119 +- sources/app/Model/Color.php | 41 +- sources/app/Model/Config.php | 5 + sources/app/Model/DateParser.php | 15 +- sources/app/Model/File.php | 2 +- sources/app/Model/Project.php | 86 + sources/app/Model/ProjectAnalytic.php | 6 +- sources/app/Model/ProjectPermission.php | 122 +- sources/app/Model/SubtaskTimeTracking.php | 17 +- sources/app/Model/Task.php | 35 +- sources/app/Model/TaskCreation.php | 9 +- sources/app/Model/TaskFilter.php | 60 +- sources/app/Model/TaskFinder.php | 39 + sources/app/Model/TaskLink.php | 62 +- sources/app/Model/User.php | 96 +- sources/app/Model/UserSession.php | 12 + sources/app/Schema/Mysql.php | 24 +- sources/app/Schema/Postgres.php | 24 +- sources/app/Schema/Sqlite.php | 24 +- sources/app/Template/action/index.php | 2 + sources/app/Template/action/params.php | 3 + sources/app/Template/analytic/cfd.php | 2 +- sources/app/Template/analytic/layout.php | 2 +- sources/app/Template/analytic/sidebar.php | 12 +- sources/app/Template/analytic/tasks.php | 2 +- sources/app/Template/analytic/users.php | 2 +- sources/app/Template/app/projects.php | 2 +- sources/app/Template/board/task_footer.php | 22 +- sources/app/Template/board/task_menu.php | 26 +- sources/app/Template/board/task_private.php | 7 +- sources/app/Template/budget/index.php | 4 +- sources/app/Template/category/edit.php | 4 +- sources/app/Template/comment/create.php | 2 +- sources/app/Template/comment/edit.php | 2 +- sources/app/Template/config/about.php | 2 + sources/app/Template/config/integrations.php | 22 +- sources/app/Template/config/sidebar.php | 23 +- sources/app/Template/file/show.php | 2 +- sources/app/Template/layout.php | 11 +- sources/app/Template/project/edit.php | 10 +- sources/app/Template/project/index.php | 60 +- sources/app/Template/project/integrations.php | 12 +- sources/app/Template/project/show.php | 12 +- sources/app/Template/project/sidebar.php | 28 +- sources/app/Template/project/users.php | 1 + sources/app/Template/swimlane/edit.php | 2 + sources/app/Template/task/layout.php | 2 +- sources/app/Template/task/sidebar.php | 36 +- sources/app/Template/user/edit.php | 3 +- sources/app/Template/user/external.php | 18 +- sources/app/Template/user/index.php | 15 +- sources/app/Template/user/show.php | 2 +- sources/app/Template/user/sidebar.php | 30 +- sources/app/common.php | 8 +- sources/app/constants.php | 25 +- sources/assets/css/app.css | 1707 +---------------- .../css/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 212 -> 212 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 208 -> 208 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 335 -> 335 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 207 -> 207 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 262 -> 262 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 262 -> 262 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 332 -> 332 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 280 -> 280 bytes .../css/images/ui-icons_222222_256x240.png | Bin 6922 -> 6922 bytes .../css/images/ui-icons_2e83ff_256x240.png | Bin 4549 -> 4549 bytes .../css/images/ui-icons_454545_256x240.png | Bin 6992 -> 6992 bytes .../css/images/ui-icons_888888_256x240.png | Bin 6999 -> 6999 bytes .../css/images/ui-icons_cd0a0a_256x240.png | Bin 4549 -> 4549 bytes sources/assets/css/src/base.css | 1 - sources/assets/css/src/board.css | 122 +- sources/assets/css/src/dropdown.css | 59 +- sources/assets/css/src/form.css | 4 +- sources/assets/css/src/header.css | 8 +- sources/assets/css/src/markdown.css | 33 +- sources/assets/css/src/responsive.css | 12 +- sources/assets/css/src/sidebar.css | 11 + sources/assets/css/src/table.css | 16 + sources/assets/css/src/task.css | 4 + sources/assets/css/src/tooltip.css | 2 +- .../assets/css/vendor/fullcalendar.min.css | 8 +- sources/assets/css/vendor/jquery-ui.min.css | 6 +- .../assets/css/vendor/jquery-ui.theme.min.css | 2 +- sources/assets/js/app.js | 174 +- sources/assets/js/src/analytic.js | 355 ---- sources/assets/js/src/base.js | 394 ---- sources/assets/js/src/board.js | 267 --- sources/assets/js/src/calendar.js | 51 - sources/assets/js/src/swimlane.js | 90 - sources/assets/js/vendor/dropit.min.js | 99 - sources/assets/js/vendor/fullcalendar.min.js | 13 +- sources/assets/js/vendor/jquery-ui.min.js | 14 +- .../js/vendor/jquery.ui.touch-punch.min.js | 14 +- sources/assets/js/vendor/lang/ar-ma.js | 2 +- sources/assets/js/vendor/lang/ar-sa.js | 2 +- sources/assets/js/vendor/lang/ar-tn.js | 2 +- sources/assets/js/vendor/lang/ar.js | 2 +- sources/assets/js/vendor/lang/bg.js | 2 +- sources/assets/js/vendor/lang/ca.js | 2 +- sources/assets/js/vendor/lang/cs.js | 2 +- sources/assets/js/vendor/lang/da.js | 2 +- sources/assets/js/vendor/lang/de-at.js | 2 +- sources/assets/js/vendor/lang/de.js | 2 +- sources/assets/js/vendor/lang/el.js | 2 +- sources/assets/js/vendor/lang/en-au.js | 2 +- sources/assets/js/vendor/lang/en-ca.js | 2 +- sources/assets/js/vendor/lang/en-gb.js | 2 +- sources/assets/js/vendor/lang/es.js | 2 +- sources/assets/js/vendor/lang/fa.js | 2 +- sources/assets/js/vendor/lang/fi.js | 2 +- sources/assets/js/vendor/lang/fr-ca.js | 2 +- sources/assets/js/vendor/lang/fr.js | 2 +- sources/assets/js/vendor/lang/he.js | 2 +- sources/assets/js/vendor/lang/hi.js | 2 +- sources/assets/js/vendor/lang/hr.js | 2 +- sources/assets/js/vendor/lang/hu.js | 2 +- sources/assets/js/vendor/lang/id.js | 2 +- sources/assets/js/vendor/lang/is.js | 2 +- sources/assets/js/vendor/lang/it.js | 2 +- sources/assets/js/vendor/lang/ja.js | 2 +- sources/assets/js/vendor/lang/ko.js | 2 +- sources/assets/js/vendor/lang/lt.js | 2 +- sources/assets/js/vendor/lang/lv.js | 2 +- sources/assets/js/vendor/lang/nl.js | 2 +- sources/assets/js/vendor/lang/pl.js | 2 +- sources/assets/js/vendor/lang/pt-br.js | 2 +- sources/assets/js/vendor/lang/pt.js | 2 +- sources/assets/js/vendor/lang/ro.js | 2 +- sources/assets/js/vendor/lang/ru.js | 2 +- sources/assets/js/vendor/lang/sk.js | 2 +- sources/assets/js/vendor/lang/sl.js | 2 +- sources/assets/js/vendor/lang/sr-cyrl.js | 2 +- sources/assets/js/vendor/lang/sr.js | 2 +- sources/assets/js/vendor/lang/sv.js | 2 +- sources/assets/js/vendor/lang/th.js | 2 +- sources/assets/js/vendor/lang/tr.js | 2 +- sources/assets/js/vendor/lang/uk.js | 2 +- sources/assets/js/vendor/lang/vi.js | 2 +- sources/assets/js/vendor/lang/zh-cn.js | 2 +- sources/assets/js/vendor/lang/zh-tw.js | 2 +- sources/config.default.php | 43 + sources/jsonrpc.php | 4 +- sources/vendor/autoload.php | 2 +- sources/vendor/composer/ClassLoader.php | 26 + sources/vendor/composer/autoload_classmap.php | 23 +- sources/vendor/composer/autoload_psr4.php | 1 + sources/vendor/composer/autoload_real.php | 10 +- sources/vendor/composer/installed.json | 154 +- sources/vendor/erusev/parsedown/Parsedown.php | 56 +- .../fguillot/json-rpc/src/JsonRPC/Client.php | 8 +- .../fguillot/json-rpc/src/JsonRPC/Server.php | 12 +- .../fguillot/picodb/lib/PicoDb/Database.php | 9 +- .../picodb/lib/PicoDb/Driver/Mysql.php | 9 +- .../picodb/lib/PicoDb/Driver/Sqlite.php | 7 +- .../fguillot/picodb/lib/PicoDb/Table.php | 31 +- .../src/SimpleValidator/Base.php | 32 - .../src/SimpleValidator/Validator.php | 9 +- .../src/SimpleValidator/Validators/Alpha.php | 9 +- .../Validators/AlphaNumeric.php | 9 +- .../src/SimpleValidator/Validators/Date.php | 9 +- .../src/SimpleValidator/Validators/Email.php | 6 +- .../src/SimpleValidator/Validators/Equals.php | 9 +- .../src/SimpleValidator/Validators/Exists.php | 13 +- .../Validators/GreaterThan.php | 4 +- .../SimpleValidator/Validators/InArray.php | 5 +- .../SimpleValidator/Validators/Integer.php | 6 +- .../src/SimpleValidator/Validators/Ip.php | 8 +- .../src/SimpleValidator/Validators/Length.php | 11 +- .../SimpleValidator/Validators/MacAddress.php | 28 - .../SimpleValidator/Validators/MaxLength.php | 10 +- .../SimpleValidator/Validators/MinLength.php | 10 +- .../SimpleValidator/Validators/NotEquals.php | 8 +- .../SimpleValidator/Validators/NotInArray.php | 4 +- .../SimpleValidator/Validators/Numeric.php | 9 +- .../src/SimpleValidator/Validators/Range.php | 6 +- .../SimpleValidator/Validators/Required.php | 8 +- .../src/SimpleValidator/Validators/Unique.php | 10 +- .../SimpleValidator/Validators/Version.php | 18 - .../simpleLogger/src/SimpleLogger/Logger.php | 16 +- sources/vendor/pimple/pimple/CHANGELOG | 5 + sources/vendor/pimple/pimple/LICENSE | 2 +- .../pimple/pimple/ext/pimple/php_pimple.h | 2 +- .../vendor/pimple/pimple/ext/pimple/pimple.c | 5 +- .../pimple/pimple/src/Pimple/Container.php | 4 +- .../src/Pimple/ServiceProviderInterface.php | 2 +- .../pimple/src/Pimple/Tests/PimpleTest.php | 12 +- 215 files changed, 3176 insertions(+), 4333 deletions(-) mode change 100755 => 100644 sources/assets/css/images/ui-bg_flat_0_aaaaaa_40x100.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_flat_75_ffffff_40x100.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_glass_55_fbf9ee_1x400.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_glass_65_ffffff_1x400.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_glass_75_dadada_1x400.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_glass_75_e6e6e6_1x400.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_glass_95_fef1ec_1x400.png mode change 100755 => 100644 sources/assets/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png mode change 100755 => 100644 sources/assets/css/images/ui-icons_222222_256x240.png mode change 100755 => 100644 sources/assets/css/images/ui-icons_2e83ff_256x240.png mode change 100755 => 100644 sources/assets/css/images/ui-icons_454545_256x240.png mode change 100755 => 100644 sources/assets/css/images/ui-icons_888888_256x240.png mode change 100755 => 100644 sources/assets/css/images/ui-icons_cd0a0a_256x240.png delete mode 100644 sources/assets/js/src/analytic.js delete mode 100644 sources/assets/js/src/base.js delete mode 100644 sources/assets/js/src/board.js delete mode 100644 sources/assets/js/src/calendar.js delete mode 100644 sources/assets/js/src/swimlane.js delete mode 100644 sources/assets/js/vendor/dropit.min.js delete mode 100644 sources/vendor/fguillot/simple-validator/src/SimpleValidator/Base.php delete mode 100644 sources/vendor/fguillot/simple-validator/src/SimpleValidator/Validators/MacAddress.php delete mode 100644 sources/vendor/fguillot/simple-validator/src/SimpleValidator/Validators/Version.php diff --git a/conf/config.php b/conf/config.php index cd7e76f..ece12e9 100644 --- a/conf/config.php +++ b/conf/config.php @@ -126,6 +126,33 @@ define('GITHUB_CLIENT_ID', ''); // GitHub client secret key (Copy it from your settings -> Applications -> Developer applications) define('GITHUB_CLIENT_SECRET', ''); +// Github oauth2 authorize url +define('GITHUB_OAUTH_AUTHORIZE_URL', 'https://github.com/login/oauth/authorize'); + +// Github oauth2 token url +define('GITHUB_OAUTH_TOKEN_URL', 'https://github.com/login/oauth/access_token'); + +// Github API url (don't forget the slash at the end) +define('GITHUB_API_URL', 'https://api.github.com/'); + +// Enable/disable Gitlab authentication +define('GITLAB_AUTH', false); + +// Gitlab application id +define('GITLAB_CLIENT_ID', ''); + +// Gitlab application secret +define('GITLAB_CLIENT_SECRET', ''); + +// Gitlab oauth2 authorize url +define('GITLAB_OAUTH_AUTHORIZE_URL', 'https://gitlab.com/oauth/authorize'); + +// Gitlab oauth2 token url +define('GITLAB_OAUTH_TOKEN_URL', 'https://gitlab.com/oauth/token'); + +// Gitlab API url endpoint (don't forget the slash at the end) +define('GITLAB_API_URL', 'https://gitlab.com/api/v3/'); + // Enable/disable the reverse proxy authentication define('REVERSE_PROXY_AUTH', true); @@ -138,6 +165,9 @@ define('REVERSE_PROXY_DEFAULT_ADMIN', 'yuno_admin'); // Default domain to use for setting the email address define('REVERSE_PROXY_DEFAULT_DOMAIN', 'yuno_domain'); +// Enable/disable remember me authentication +define('REMEMBER_ME_AUTH', true); + // Enable or disable "Strict-Transport-Security" HTTP header define('ENABLE_HSTS', true); @@ -155,3 +185,16 @@ define('ENABLE_URL_REWRITE', false); // Hide login form, useful if all your users use Google/Github/ReverseProxy authentication define('HIDE_LOGIN_FORM', true); + +// Enable captcha after 3 authentication failure +define('BRUTEFORCE_CAPTCHA', 3); + +// Lock the account after 6 authentication failure +define('BRUTEFORCE_LOCKDOWN', 6); + +// Lock account duration in minute +define('BRUTEFORCE_LOCKDOWN_DURATION', 15); + +// Session duration in second (0 = until the browser is closed) +// See http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime +define('SESSION_DURATION', 0); diff --git a/sources/app/Auth/Google.php b/sources/app/Auth/Google.php index 972dd74..10ecfe8 100644 --- a/sources/app/Auth/Google.php +++ b/sources/app/Auth/Google.php @@ -77,8 +77,8 @@ class Google extends Base return $this->user->update(array( 'id' => $user_id, 'google_id' => $profile['id'], - 'email' => $profile['email'] ?: $user['email'], - 'name' => $profile['name'] ?: $user['name'], + 'email' => empty($user['email']) ? $profile['email'] : $user['email'], + 'name' => empty($user['name']) ? $profile['name'] : $user['name'], )); } diff --git a/sources/app/Controller/Action.php b/sources/app/Controller/Action.php index 140c47d..d92385c 100644 --- a/sources/app/Controller/Action.php +++ b/sources/app/Controller/Action.php @@ -31,6 +31,7 @@ class Action extends Base 'projects_list' => $this->project->getList(false), 'colors_list' => $this->color->getList(), 'categories_list' => $this->category->getList($project['id']), + 'links_list' => $this->link->getList(0, false), 'title' => t('Automatic actions') ))); } @@ -89,6 +90,7 @@ class Action extends Base 'projects_list' => $projects_list, 'colors_list' => $this->color->getList(), 'categories_list' => $this->category->getList($project['id']), + 'links_list' => $this->link->getList(0, false), 'project' => $project, 'title' => t('Automatic actions') ))); diff --git a/sources/app/Controller/Base.php b/sources/app/Controller/Base.php index f68c475..480976b 100644 --- a/sources/app/Controller/Base.php +++ b/sources/app/Controller/Base.php @@ -80,7 +80,7 @@ abstract class Base extends \Core\Base private function sendHeaders($action) { // HTTP secure headers - $this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '*')); + $this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '* data:')); $this->response->nosniff(); $this->response->xss(); @@ -269,12 +269,17 @@ abstract class Base extends \Core\Base */ protected function getTask() { + $project_id = $this->request->getIntegerParam('project_id'); $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); if (empty($task)) { $this->notfound(); } + if ($project_id !== 0 && $project_id != $task['project_id']) { + $this->forbidden(); + } + return $task; } diff --git a/sources/app/Controller/Board.php b/sources/app/Controller/Board.php index 50d9c62..179c6b3 100644 --- a/sources/app/Controller/Board.php +++ b/sources/app/Controller/Board.php @@ -50,6 +50,8 @@ class Board extends Base $params = $this->getProjectFilters('board', 'show'); $this->response->html($this->template->layout('board/private_view', array( + 'categories_list' => $this->category->getList($params['project']['id'], false), + 'users_list' => $this->projectPermission->getMemberList($params['project']['id'], false), 'swimlanes' => $this->taskFilter->search($params['filters']['search'])->getBoard($params['project']['id']), 'description' => $params['project']['description'], 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'), @@ -116,6 +118,29 @@ class Board extends Base $this->response->html($this->renderBoard($project_id)); } + /** + * Reload the board with new filters + * + * @access public + */ + public function reload() + { + if (! $this->request->isAjax()) { + return $this->response->status(403); + } + + $project_id = $this->request->getIntegerParam('project_id'); + + if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) { + $this->response->text('Forbidden', 403); + } + + $values = $this->request->getJson(); + $this->userSession->setFilters($project_id, $values['search']); + + $this->response->html($this->renderBoard($project_id)); + } + /** * Get links on mouseover * @@ -154,8 +179,7 @@ class Board extends Base $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_files', array( - 'files' => $this->file->getAllDocuments($task['id']), - 'images' => $this->file->getAllImages($task['id']), + 'files' => $this->file->getAll($task['id']), 'task' => $task, ))); } diff --git a/sources/app/Controller/Project.php b/sources/app/Controller/Project.php index 45bc2a4..3e3e47c 100644 --- a/sources/app/Controller/Project.php +++ b/sources/app/Controller/Project.php @@ -30,7 +30,7 @@ class Project extends Base ->setUrl('project', 'index') ->setMax(20) ->setOrder('name') - ->setQuery($this->project->getQueryColumnStats($project_ids)) + ->setQuery($this->project->getQueryProjectDetails($project_ids)) ->calculate(); $this->response->html($this->template->layout('project/index', array( @@ -141,8 +141,15 @@ class Project extends Base $project = $this->getProject(); $values = $this->request->getValues(); - if ($project['is_private'] == 1 && $this->userSession->isAdmin() && ! isset($values['is_private'])) { - $values += array('is_private' => 0); + if (isset($values['is_private'])) { + if (! $this->helper->user->isProjectAdministrationAllowed($project['id'])) { + unset($values['is_private']); + } + } + else if ($project['is_private'] == 1 && ! isset($values['is_private'])) { + if ($this->helper->user->isProjectAdministrationAllowed($project['id'])) { + $values += array('is_private' => 0); + } } list($valid, $errors) = $this->project->validateModification($values); @@ -402,7 +409,7 @@ class Project extends Base */ public function create(array $values = array(), array $errors = array()) { - $is_private = $this->request->getIntegerParam('private', $this->userSession->isAdmin() ? 0 : 1); + $is_private = $this->request->getIntegerParam('private', $this->userSession->isAdmin() || $this->userSession->isProjectAdmin() ? 0 : 1); $this->response->html($this->template->layout('project/new', array( 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()), diff --git a/sources/app/Controller/Subtask.php b/sources/app/Controller/Subtask.php index 87f3fcb..338918f 100644 --- a/sources/app/Controller/Subtask.php +++ b/sources/app/Controller/Subtask.php @@ -186,7 +186,7 @@ class Subtask extends Base $this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); - $this->response->html($this->template->render('board/subtasks', array( + $this->response->html($this->template->render('board/tooltip_subtasks', array( 'subtasks' => $this->subtask->getAll($task['id']), 'task' => $task, ))); diff --git a/sources/app/Controller/User.php b/sources/app/Controller/User.php index 10a3a93..04e5741 100644 --- a/sources/app/Controller/User.php +++ b/sources/app/Controller/User.php @@ -303,12 +303,16 @@ class User extends Base $values = $this->request->getValues(); if ($this->userSession->isAdmin()) { - $values += array('is_admin' => 0); + $values += array('is_admin' => 0, 'is_project_admin' => 0); } else { - + // Regular users can't be admin if (isset($values['is_admin'])) { - unset($values['is_admin']); // Regular users can't be admin + unset($values['is_admin']); + } + + if (isset($values['is_project_admin'])) { + unset($values['is_project_admin']); } } diff --git a/sources/app/Core/Router.php b/sources/app/Core/Router.php index ae989de..6e7576d 100644 --- a/sources/app/Core/Router.php +++ b/sources/app/Core/Router.php @@ -10,6 +10,22 @@ namespace Core; */ class Router extends Base { + /** + * Controller + * + * @access private + * @var string + */ + private $controller = ''; + + /** + * Action + * + * @access private + * @var string + */ + private $action = ''; + /** * Store routes for path lookup * @@ -26,6 +42,28 @@ class Router extends Base */ private $urls = array(); + /** + * Get action + * + * @access public + * @return string + */ + public function getAction() + { + return $this->action; + } + + /** + * Get controller + * + * @access public + * @return string + */ + public function getController() + { + return $this->controller; + } + /** * Get the path to compare patterns * @@ -208,6 +246,9 @@ class Router extends Base return false; } + $this->action = $method; + $this->controller = $controller; + $instance = new $class($this->container); $instance->beforeAction($controller, $method); $instance->$method(); diff --git a/sources/app/Core/Session.php b/sources/app/Core/Session.php index 0e5f742..df0ec5f 100644 --- a/sources/app/Core/Session.php +++ b/sources/app/Core/Session.php @@ -12,15 +12,6 @@ use ArrayAccess; */ class Session implements ArrayAccess { - /** - * Sesion lifetime - * - * http://php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime - * - * @var integer - */ - const SESSION_LIFETIME = 0; // Until the browser is closed - /** * Return true if the session is open * @@ -43,7 +34,7 @@ class Session implements ArrayAccess { // HttpOnly and secure flags for session cookie session_set_cookie_params( - self::SESSION_LIFETIME, + SESSION_DURATION, $base_path ?: '/', null, Request::isHTTPS(), diff --git a/sources/app/Locale/da_DK/translations.php b/sources/app/Locale/da_DK/translations.php index cd7a6f0..6a41f06 100644 --- a/sources/app/Locale/da_DK/translations.php +++ b/sources/app/Locale/da_DK/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/de_DE/translations.php b/sources/app/Locale/de_DE/translations.php index 891ed65..7b38e9f 100644 --- a/sources/app/Locale/de_DE/translations.php +++ b/sources/app/Locale/de_DE/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/es_ES/translations.php b/sources/app/Locale/es_ES/translations.php index a1ba902..ac7c0e4 100644 --- a/sources/app/Locale/es_ES/translations.php +++ b/sources/app/Locale/es_ES/translations.php @@ -35,7 +35,7 @@ return array( 'Unassigned' => 'No asignado', 'View this task' => 'Ver esta tarea', 'Remove user' => 'Eliminar un usuario', - 'Do you really want to remove this user: "%s"?' => '¿De verdad que deseas suprimir a este usuario: « %s » ?', + 'Do you really want to remove this user: "%s"?' => '¿De verdad que desea suprimir a este usuario: « %s » ?', 'New user' => 'Añadir un usuario', 'All users' => 'Todos los usuarios', 'Username' => 'Nombre de usuario', @@ -68,19 +68,19 @@ return array( 'Disable' => 'Desactivar', 'Enable' => 'Activar', 'New project' => 'Nuevo proyecto', - 'Do you really want to remove this project: "%s"?' => '¿De verdad que deseas eliminar este proyecto: « %s » ?', + 'Do you really want to remove this project: "%s"?' => '¿De verdad que desea eliminar este proyecto: « %s » ?', 'Remove project' => 'Suprimir el proyecto', 'Edit the board for "%s"' => 'Modificar el tablero para « %s »', 'All projects' => 'Todos los proyectos', 'Change columns' => 'Cambiar las columnas', 'Add a new column' => 'Añadir una nueva columna', - 'Title' => 'Titulo', + 'Title' => 'Título', 'Nobody assigned' => 'Nadie asignado', 'Assigned to %s' => 'Asignada a %s', 'Remove a column' => 'Suprimir esta columna', 'Remove a column from a board' => 'Suprimir una columna de un tablero', 'Unable to remove this column.' => 'No se puede suprimir esta columna.', - 'Do you really want to remove this column: "%s"?' => '¿De vedad que deseas eliminar esta columna : « %s » ?', + 'Do you really want to remove this column: "%s"?' => '¿De vedad que desea eliminar esta columna : « %s » ?', 'This action will REMOVE ALL TASKS associated to this column!' => '¡Esta acción SUPRIMIRÁ TODAS LAS TAREAS asociadas a esta columna!', 'Settings' => 'Preferencias', 'Application settings' => 'Parámetros de la aplicación', @@ -96,13 +96,13 @@ return array( 'Edit a task' => 'Editar una tarea', 'Column' => 'Columna', 'Color' => 'Color', - 'Assignee' => 'Persona asignada', + 'Assignee' => 'Concesionario', 'Create another task' => 'Crear una nueva tarea', 'New task' => 'Nueva tarea', 'Open a task' => 'Abrir una tarea', 'Do you really want to open this task: "%s"?' => '¿Realmente desea abrir esta tarea: « %s » ?', 'Back to the board' => 'Volver al tablero', - 'Created on %B %e, %Y at %k:%M %p' => 'Creado el %d/%m/%Y a las %H:%M', + 'Created on %B %e, %Y at %k:%M %p' => 'Creado el %e de %B de %Y a las %k:%M %p', 'There is nobody assigned' => 'No hay nadie asignado a esta tarea', 'Column on the board:' => 'Columna en el tablero: ', 'Status is open' => 'Estado abierto', @@ -111,12 +111,12 @@ return array( 'Open this task' => 'Abrir esta tarea', 'There is no description.' => 'No hay descripción.', 'Add a new task' => 'Añadir una nueva tarea', - 'The username is required' => 'El nombre de usuario es obligatorio', + 'The username is required' => 'El nombre del usuario es obligatorio', 'The maximum length is %d characters' => 'La longitud máxima es de %d caracteres', 'The minimum length is %d characters' => 'La longitud mínima es de %d caracteres', 'The password is required' => 'La contraseña es obligatoria', 'This value must be an integer' => 'Este valor debe ser un entero', - 'The username must be unique' => 'El nombre de usuario debe ser único', + 'The username must be unique' => 'El nombre del usuario debe ser único', 'The user id is required' => 'El identificador del usuario es obligatorio', 'Passwords don\'t match' => 'Las contraseñas no coinciden', 'The confirmation is required' => 'La confirmación es obligatoria', @@ -125,7 +125,7 @@ return array( 'The project id is required' => 'El identificador del proyecto es obligatorio', 'The project name is required' => 'El nombre del proyecto es obligatorio', 'This project must be unique' => 'El nombre del proyecto debe ser único', - 'The title is required' => 'El titulo es obligatorio', + 'The title is required' => 'El título es obligatorio', 'Settings saved successfully.' => 'Parámetros guardados correctamente.', 'Unable to save your settings.' => 'No se pueden guardar sus parámetros.', 'Database optimization done.' => 'Optimización de la base de datos terminada.', @@ -159,8 +159,8 @@ return array( 'Work in progress' => 'En curso', 'Done' => 'Hecho', 'Application version:' => 'Versión de la aplicación:', - 'Completed on %B %e, %Y at %k:%M %p' => 'Completado el %d/%m/%Y a las %H:%M', - '%B %e, %Y at %k:%M %p' => '%d/%m/%Y a las %H:%M', + 'Completed on %B %e, %Y at %k:%M %p' => 'Completado el %e de %B de %Y a las %k:%M %p', + '%B %e, %Y at %k:%M %p' => '%e de %B de %Y a las %k:%M %p', 'Date created' => 'Fecha de creación', 'Date completed' => 'Fecha de terminación', 'Id' => 'Identificador', @@ -168,16 +168,16 @@ return array( 'No task for this project' => 'Ninguna tarea para este proyecto', 'Public link' => 'Vinculación pública', 'There is no column in your project!' => '¡No hay ninguna columna para este proyecto!', - 'Change assignee' => 'Cambiar la persona asignada', - 'Change assignee for the task "%s"' => 'Cambiar la persona asignada por la tarea « %s »', + 'Change assignee' => 'Cambiar concesionario', + 'Change assignee for the task "%s"' => 'Cambiar el concesionario para la tarea « %s »', 'Timezone' => 'Zona horaria', - 'Sorry, I didn\'t find this information in my database!' => 'Lo siento no he encontrado información en la base de datos!', + 'Sorry, I didn\'t find this information in my database!' => '¡Lo siento no he encontrado esta información en mi base de datos!', 'Page not found' => 'Página no encontrada', 'Complexity' => 'Complejidad', 'Task limit' => 'Número máximo de tareas', 'Task count' => 'Contador de tareas', 'Edit project access list' => 'Editar los permisos del proyecto', - 'Allow this user' => 'Autorizar este usuario', + 'Allow this user' => 'Autorizar a este usuario', 'Don\'t forget that administrators have access to everything.' => 'No olvide que los administradores tienen acceso a todo.', 'Revoke' => 'Revocar', 'List of authorized users' => 'Lista de los usuarios autorizados', @@ -193,9 +193,9 @@ return array( 'Edit this task' => 'Editar esta tarea', 'Due Date' => 'Fecha límite', 'Invalid date' => 'Fecha no válida', - 'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y', - '%B %e, %Y' => '%d/%m/%Y', - // '%b %e, %Y' => '', + 'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %e de %B de %Y', + '%B %e, %Y' => '%e de %B de %Y', + '%b %e, %Y' => '%e de %B de %Y', 'Automatic actions' => 'Acciones automatizadas', 'Your automatic action have been created successfully.' => 'La acción automatizada ha sido creada correctamente.', 'Unable to create your automatic action.' => 'No se puede crear esta acción automatizada.', @@ -264,13 +264,13 @@ return array( '%d comment' => '%d comentario', 'Email address invalid' => 'Dirección de correo inválida', 'Your external account is not linked anymore to your profile.' => 'Su cuenta externa se ha desvinculado de su perfil.', - 'Unable to unlink your external account.' => 'Imposible desvincular cuenta externa.', + 'Unable to unlink your external account.' => 'Imposible desvincular su cuenta externa.', 'External authentication failed' => 'Falló la autenticación externa', 'Your external account is linked to your profile successfully.' => 'Su cuenta externa se ha vinculado exitosamente con su perfil.', 'Email' => 'Correo', 'Link my Google Account' => 'Vincular con mi Cuenta en Google', 'Unlink my Google Account' => 'Desvincular de mi Cuenta en Google', - 'Login with my Google Account' => 'Ingresar con mi Cuenta en Google', + 'Login with my Google Account' => 'Ingresar con mi Cuenta de Google', 'Project not found.' => 'Proyecto no hallado.', 'Task removed successfully.' => 'Tarea suprimida correctamente.', 'Unable to remove this task.' => 'No pude suprimir esta tarea.', @@ -283,10 +283,10 @@ return array( 'Category:' => 'Categoría:', 'Categories' => 'Categorías', 'Category not found.' => 'Categoría no hallada.', - 'Your category have been created successfully.' => 'Se ha creado tu categoría correctamente.', - 'Unable to create your category.' => 'No pude crear tu categoría.', - 'Your category have been updated successfully.' => 'Se ha actualizado tu categoría correctamente.', - 'Unable to update your category.' => 'No pude actualizar tu categoría.', + 'Your category have been created successfully.' => 'Se ha creado su categoría correctamente.', + 'Unable to create your category.' => 'No pude crear su categoría.', + 'Your category have been updated successfully.' => 'Se ha actualizado su categoría correctamente.', + 'Unable to update your category.' => 'No pude actualizar su categoría.', 'Remove a category' => 'Suprimir una categoría', 'Category removed successfully.' => 'Categoría suprimida correctamente.', 'Unable to remove this category.' => 'No pude suprimir esta categoría.', @@ -301,7 +301,7 @@ return array( 'Unable to remove this file.' => 'No pude borrar este fichero.', 'File removed successfully.' => 'Fichero borrado correctamente.', 'Attach a document' => 'Adjuntar un documento', - 'Do you really want to remove this file: "%s"?' => '¿De verdad que quieres borrar este fichero: "%s"?', + 'Do you really want to remove this file: "%s"?' => '¿De verdad que quiere borrar este fichero: "%s"?', 'open' => 'abrir', 'Attachments' => 'Adjuntos', 'Edit the task' => 'Editar la tarea', @@ -312,8 +312,8 @@ return array( 'Time tracking' => 'Seguimiento temporal', 'Estimate:' => 'Estimado:', 'Spent:' => 'Transcurrido:', - 'Do you really want to remove this sub-task?' => '¿De verdad que quieres suprimir esta sub-tarea?', - 'Remaining:' => 'Quedando', + 'Do you really want to remove this sub-task?' => '¿De verdad que quiere suprimir esta sub-tarea?', + 'Remaining:' => 'Restante:', 'hours' => 'horas', 'spent' => 'transcurrido', 'estimated' => 'estimado', @@ -330,8 +330,8 @@ return array( 'Sub-task removed successfully.' => 'Sub-tarea suprimida correctamente.', 'Unable to remove this sub-task.' => 'No pude suprimir esta sub-tarea.', 'Sub-task updated successfully.' => 'Sub-tarea actualizada correctamente.', - 'Unable to update your sub-task.' => 'No pude actualizar tu sub-tarea.', - 'Unable to create your sub-task.' => 'No pude crear tu sub-tarea.', + 'Unable to update your sub-task.' => 'No pude actualizar su sub-tarea.', + 'Unable to create your sub-task.' => 'No pude crear su sub-tarea.', 'Sub-task added successfully.' => 'Sub-tarea añadida correctamente.', 'Maximum size: ' => 'Tamaño máximo', 'Unable to upload the file.' => 'No pude cargar el fichero.', @@ -340,7 +340,7 @@ return array( 'Link my Github Account' => 'Vincular mi cuenta de Github', 'Unlink my Github Account' => 'Desvincular mi cuenta de Github', 'Created by %s' => 'Creado por %s', - 'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificación %B %e, %Y a las %k:%M %p', + 'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificación %e de %B de %Y a las %k:%M %p', 'Tasks Export' => 'Exportar tareas', 'Tasks exportation for "%s"' => 'Exportación de tareas para "%s"', 'Start Date' => 'Fecha de inicio', @@ -361,7 +361,7 @@ return array( 'Sub-task updated' => 'Subtarea actualizada', 'Title:' => 'Título:', 'Status:' => 'Estado:', - 'Assignee:' => 'Asignada a:', + 'Assignee:' => 'Concesionario:', 'Time tracking:' => 'Control de tiempo:', 'New sub-task' => 'Nueva subtarea', 'New attachment added "%s"' => 'Nuevo adjunto agregado "%s"', @@ -382,19 +382,19 @@ return array( 'Disable public access' => 'Desactivar acceso público', 'Enable public access' => 'Activar acceso público', 'Public access disabled' => 'Acceso público desactivado', - 'Do you really want to disable this project: "%s"?' => '¿Realmente deseas desactivar este proyecto: "%s"?', - 'Do you really want to enable this project: "%s"?' => '¿Realmente deseas activar este proyecto: "%s"?', + 'Do you really want to disable this project: "%s"?' => '¿Realmente desea desactivar este proyecto: "%s"?', + 'Do you really want to enable this project: "%s"?' => '¿Realmente desea activar este proyecto: "%s"?', 'Project activation' => 'Activación de Proyecto', 'Move the task to another project' => 'Mover la tarea a otro proyecto', 'Move to another project' => 'Mover a otro proyecto', - 'Do you really want to duplicate this task?' => '¿Realmente deseas duplicar esta tarea?', + 'Do you really want to duplicate this task?' => '¿Realmente desea duplicar esta tarea?', 'Duplicate a task' => 'Duplicar una tarea', 'External accounts' => 'Cuentas externas', 'Account type' => 'Tipo de Cuenta', 'Local' => 'Local', 'Remote' => 'Remota', 'Enabled' => 'Activada', - 'Disabled' => 'Deactivada', + 'Disabled' => 'Desactivada', 'Google account linked' => 'Vinculada con Cuenta de Google', 'Github account linked' => 'Vinculada con Cuenta de Gitgub', 'Username:' => 'Nombre de Usuario:', @@ -432,7 +432,7 @@ return array( '%s updated a comment on the task %s' => '%s actualizó un comentario de la tarea %s', '%s commented the task %s' => '%s comentó la tarea %s', '%s\'s activity' => 'Actividad de %s', - 'RSS feed' => 'Fichero RSS', + 'RSS feed' => 'Fuentes RSS', '%s updated a comment on the task #%d' => '%s actualizó un comentario de la tarea #%d', '%s commented on the task #%d' => '%s comentó la tarea #%d', '%s updated a subtask for the task #%d' => '%s actualizó una subtarea de la tarea #%d', @@ -446,41 +446,41 @@ return array( 'Activity' => 'Actividad', 'Default values are "%s"' => 'Los valores por defecto son "%s"', 'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)', - 'Task assignee change' => 'Cambiar persona asignada a la tarea', - '%s change the assignee of the task #%d to %s' => '%s cambió el asignado de la tarea #%d por %s', - '%s changed the assignee of the task %s to %s' => '%s cambió el asignado de la tarea %s por %s', + 'Task assignee change' => 'Cambiar concesionario de la tarea', + '%s change the assignee of the task #%d to %s' => '%s cambió el concesionario de la tarea #%d por %s', + '%s changed the assignee of the task %s to %s' => '%s cambió el concesionario de la tarea %s por %s', 'New password for the user "%s"' => 'Nueva contraseña para el usuario "%s"', - 'Choose an event' => 'Escoga un evento', + 'Choose an event' => 'Seleccione un evento', 'Github commit received' => 'Envío a Github recibido', - 'Github issue opened' => 'Problema en Github abierto', - 'Github issue closed' => 'Problema en Github cerrado', - 'Github issue reopened' => 'Problema en Github reabierto', - 'Github issue assignee change' => 'Cambio en signación de problema en Github', - 'Github issue label change' => 'Cambio en etiqueta del problema', + 'Github issue opened' => 'Abierto asunto en Github', + 'Github issue closed' => 'Cerrado asunto en Github', + 'Github issue reopened' => 'Reabierto asunto en Github', + 'Github issue assignee change' => 'Cambio en concesionario de asunto de Github', + 'Github issue label change' => 'Cambio en etiqueta de asunto de Github', 'Create a task from an external provider' => 'Crear una tarea a partir de un proveedor externo', - 'Change the assignee based on an external username' => 'Cambiar la asignación basado en un nombre de usuario externo', + 'Change the assignee based on an external username' => 'Cambiar el concesionario basado en un nombre de usuario externo', 'Change the category based on an external label' => 'Cambiar la categoría basado en una etiqueta externa', 'Reference' => 'Referencia', 'Reference: %s' => 'Referencia: %s', 'Label' => 'Etiqueta', 'Database' => 'Base de Datos', 'About' => 'Acerca de', - 'Database driver:' => 'Driver de la base de datos', + 'Database driver:' => 'Controlador (Driver) de la base de datos', 'Board settings' => 'Configuraciones del Tablero', - 'URL and token' => 'URL y token', + 'URL and token' => 'URL y ficha', 'Webhook settings' => 'Configuraciones del Disparador Web (Webhook)', 'URL for task creation:' => 'URL para la creación de tareas', - 'Reset token' => 'Resetear token', + 'Reset token' => 'Limpiar ficha', 'API endpoint:' => 'Punto final del API', - 'Refresh interval for private board' => 'Intervalo de refrescamiento del tablero privado', - 'Refresh interval for public board' => 'Intervalo de refrescamiento del tablero público', - 'Task highlight period' => 'Periodo del realce de la tarea', + 'Refresh interval for private board' => 'Intervalo de refresco del tablero privado', + 'Refresh interval for public board' => 'Intervalo de refresco del tablero público', + 'Task highlight period' => 'Periodo de realce de la tarea', 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periodo (en segundos) para considerar que una tarea fué modificada recientemente (0 para deshabilitar, 2 días por defecto)', 'Frequency in second (60 seconds by default)' => 'Frecuencia en segundos (60 segundos por defecto)', 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frecuencia en segundos (0 para deshabilitar esta característica, 10 segundos por defecto)', 'Application URL' => 'URL de la aplicación', 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Ejemplo: http://ejemplo.kanboard.net/ (usado por las notificaciones de correo)', - 'Token regenerated.' => 'Token regenerado', + 'Token regenerated.' => 'Ficha regenerada.', 'Date format' => 'Formato de la fecha', 'ISO format is always accepted, example: "%s" and "%s"' => 'El formato ISO siempre es aceptado, ejemplo: "%s" y "%s"', 'New private project' => 'Nuevo proyecto privado', @@ -489,16 +489,16 @@ return array( 'Add' => 'Añadir', 'Estimated time: %s hours' => 'Tiempo estimado: %s horas', 'Time spent: %s hours' => 'Tiempo invertido: %s horas', - 'Started on %B %e, %Y' => 'Iniciado en %B %e, %Y', + 'Started on %B %e, %Y' => 'Iniciado el %e de %B de %Y', 'Start date' => 'Fecha de inicio', 'Time estimated' => 'Tiempo estimado', - 'There is nothing assigned to you.' => 'Esto no le está asignado', + 'There is nothing assigned to you.' => 'No tiene nada asignado.', 'My tasks' => 'Mis tareas', 'Activity stream' => 'Flujo de actividad', 'Dashboard' => 'Tablero', 'Confirmation' => 'Confirmación', - 'Allow everybody to access to this project' => 'Permitir a cualquier acceder a este proyecto', - 'Everybody have access to this project.' => 'Cualquier tiene acceso a este proyecto', + 'Allow everybody to access to this project' => 'Permitir a cualquiera acceder a este proyecto', + 'Everybody have access to this project.' => 'Cualquiera tiene acceso a este proyecto', 'Webhooks' => 'Disparadores Web (Webhooks)', 'API' => 'API', 'Github webhooks' => 'Disparadores Web (Webhooks) de Github', @@ -513,7 +513,7 @@ return array( 'Percentage' => 'Porcentaje', 'Number of tasks' => 'Número de tareas', 'Task distribution' => 'Distribución de tareas', - 'Reportings' => 'Reportes', + 'Reportings' => 'Informes', 'Task repartition for "%s"' => 'Repartición de tareas para "%s"', 'Analytics' => 'Analítica', 'Subtask' => 'Subtarea', @@ -533,7 +533,7 @@ return array( 'The task id is required' => 'El id de la tarea es requerido', 'The task id must be an integer' => 'El id de la tarea debe ser un entero', 'The user id must be an integer' => 'El id del usuario debe ser un entero', - 'This value is required' => 'El valor es requerido', + 'This value is required' => 'Este valor es requerido', 'This value must be numeric' => 'Este valor debe ser numérico', 'Unable to create this task.' => 'Imposible crear esta tarea', 'Cumulative flow diagram' => 'Diagrama de flujo acumulativo', @@ -541,32 +541,32 @@ return array( 'Daily project summary' => 'Sumario diario del proyecto', 'Daily project summary export' => 'Exportar sumario diario del proyecto', 'Daily project summary export for "%s"' => 'Exportar sumario diario del proyecto para "%s"', - 'Exports' => 'Exportar', - 'This export contains the number of tasks per column grouped per day.' => 'Esta exportación contiene el número de tereas por columna agrupada por día', + 'Exports' => 'Exportaciones', + 'This export contains the number of tasks per column grouped per day.' => 'Esta exportación contiene el número de tereas por columna agrupada por día.', 'Nothing to preview...' => 'Nada que previsualizar...', 'Preview' => 'Previsualizar', - 'Write' => 'Escribir', - 'Active swimlanes' => 'Carriles activos', - 'Add a new swimlane' => 'Añadir nuevo carril', - 'Change default swimlane' => 'Cambiar el carril por defecto', - 'Default swimlane' => 'Carril por defecto', - 'Do you really want to remove this swimlane: "%s"?' => '¿Realmente quiere remover este carril: "%s"?', - 'Inactive swimlanes' => 'Carriles inactivos', + 'Write' => 'Grabar', + 'Active swimlanes' => 'Calles activas', + 'Add a new swimlane' => 'Añadir nueva calle', + 'Change default swimlane' => 'Cambiar la calle por defecto', + 'Default swimlane' => 'Calle por defecto', + 'Do you really want to remove this swimlane: "%s"?' => '¿Realmente quiere quitar esta calle: "%s"?', + 'Inactive swimlanes' => 'Calles inactivas', 'Set project manager' => 'Asignar administrador del proyecto', 'Set project member' => 'Asignar miembro del proyecto', - 'Remove a swimlane' => 'Remover un carril', + 'Remove a swimlane' => 'Quitar un calle', 'Rename' => 'Renombrar', - 'Show default swimlane' => 'Mostrar carril por defecto', - 'Swimlane modification for the project "%s"' => 'Modificación del carril para el proyecto "%s"', - 'Swimlane not found.' => 'Carril no encontrado', - 'Swimlane removed successfully.' => 'Carril eliminado correctamente', - 'Swimlanes' => 'Carriles', - 'Swimlane updated successfully.' => 'Carril actualizado correctamente', - 'The default swimlane have been updated successfully.' => 'El carril por defecto ha sido actualizado correctamente', - 'Unable to create your swimlane.' => 'Imposible crear su carril', - 'Unable to remove this swimlane.' => 'Imposible remover este carril', - 'Unable to update this swimlane.' => 'Imposible actualizar este carril', - 'Your swimlane have been created successfully.' => 'Su carril ha sido creado correctamente', + 'Show default swimlane' => 'Mostrar calle por defecto', + 'Swimlane modification for the project "%s"' => 'Modificación de la calle para el proyecto "%s"', + 'Swimlane not found.' => 'Calle no encontrada', + 'Swimlane removed successfully.' => 'Caalle eliminada correctamente', + 'Swimlanes' => 'Calles', + 'Swimlane updated successfully.' => 'Calle actualizada correctamente', + 'The default swimlane have been updated successfully.' => 'La calle por defecto ha sido actualizada correctamente', + 'Unable to create your swimlane.' => 'Imposible crear su calle', + 'Unable to remove this swimlane.' => 'Imposible de quitar esta calle', + 'Unable to update this swimlane.' => 'Imposible de actualizar esta calle', + 'Your swimlane have been created successfully.' => 'Su calle ha sido creada correctamente', 'Example: "Bug, Feature Request, Improvement"' => 'Ejemplo: "Error, Solicitud de característica, Mejora', 'Default categories for new projects (Comma-separated)' => 'Categorías por defecto para nuevos proyectos (separadas por comas)', 'Gitlab commit received' => 'Recibido envío desde Gitlab', @@ -577,9 +577,9 @@ return array( 'Integrations' => 'Integraciones', 'Integration with third-party services' => 'Integración con servicios de terceros', 'Role for this project' => 'Papel de este proyecto', - 'Project manager' => 'Gestor de proyecto', + 'Project manager' => 'Administrador de proyecto', 'Project member' => 'Miembro de proyecto', - 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Un gestor de proyecto puede cambiar sus valores y tener más privilegios que un usuario estándar.', + 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Un administrador de proyecto puede cambiar sus valores y tener más privilegios que un usuario estándar.', 'Gitlab Issue' => 'Asunto Gitlab', 'Subtask Id' => 'Id de Subtarea', 'Subtasks' => 'Subtareas', @@ -593,8 +593,8 @@ return array( 'All columns' => 'Todas las columnas', 'Calendar' => 'Calendario', 'Next' => 'Siguiente', - // '#%d' => '', - 'All swimlanes' => 'Todos los carriles', + '#%d' => '#%d', + 'All swimlanes' => 'Todas las calles', 'All colors' => 'Todos los colores', 'All status' => 'Todos los estados', 'Moved to column %s' => 'Movido a columna %s', @@ -607,20 +607,20 @@ return array( 'There is nothing to show.' => 'Nada que mostrar', 'Time Tracking' => 'Seguimiento Temporal', 'You already have one subtask in progress' => 'Ya dispones de una subtarea en progreso', - 'Which parts of the project do you want to duplicate?' => '¿Qué partes del proyecto deseas duplicar?', + 'Which parts of the project do you want to duplicate?' => '¿Qué partes del proyecto desea duplicar?', 'Disallow login form' => 'Deshabilitar formulario de ingreso', - 'Bitbucket commit received' => 'Recibida envío desde Bitbucket', + 'Bitbucket commit received' => 'Recibido envío desde Bitbucket', 'Bitbucket webhooks' => 'Disparadores Web (webhooks) de Bitbucket', 'Help on Bitbucket webhooks' => 'Ayuda sobre disparadores web (webhooks) de Bitbucket', 'Start' => 'Inicio', 'End' => 'Fin', 'Task age in days' => 'Edad de la tarea en días', 'Days in this column' => 'Días en esta columna', - // '%dd' => '', + '%dd' => '%dd', 'Add a link' => 'Añadir enlace', 'Add a new link' => 'Añadir nuevo enlace', - 'Do you really want to remove this link: "%s"?' => '¿Realmente quieres quitar este enlace: "%s"?', - 'Do you really want to remove this link with task #%d?' => '¿Realmente quieres quitar este enlace con esta tarea: #%d?', + 'Do you really want to remove this link: "%s"?' => '¿Realmente quiere quitar este enlace: "%s"?', + 'Do you really want to remove this link with task #%d?' => '¿Realmente quiere quitar este enlace con esta tarea: #%d?', 'Field required' => 'Es necesario el campo', 'Link added successfully.' => 'Enlace añadido con éxito.', 'Link updated successfully.' => 'Enlace actualizado con éxito', @@ -650,9 +650,9 @@ return array( 'fixes' => 'arregla', 'is fixed by' => 'arreglado por', 'This task' => 'Esta tarea', - // '<1h' => '', - // '%dh' => '', - // '%b %e' => '', + '<1h' => '<1h', + '%dh' => '%dh', + '%b %e' => '%e de %b', 'Expand tasks' => 'Espande tareas', 'Collapse tasks' => 'Colapsa tareas', 'Expand/collapse tasks' => 'Expande/colapasa tareas', @@ -662,13 +662,13 @@ return array( 'Keyboard shortcuts' => 'Atajos de teclado', 'Open board switcher' => 'Abrir conmutador de tablero', 'Application' => 'Aplicación', - 'since %B %e, %Y at %k:%M %p' => 'desde %B %e, %Y a las %k:%M %p', + 'since %B %e, %Y at %k:%M %p' => 'desde %e de %B de %Y a las %k:%M %p', 'Compact view' => 'Compactar vista', 'Horizontal scrolling' => 'Desplazamiento horizontal', 'Compact/wide view' => 'Vista compacta/amplia', 'No results match:' => 'No hay resultados coincidentes:', 'Remove hourly rate' => 'Quitar cobro horario', - 'Do you really want to remove this hourly rate?' => '¿Realmente quires quitar el cobro horario?', + 'Do you really want to remove this hourly rate?' => '¿Realmente quire quitar el cobro horario?', 'Hourly rates' => 'Cobros horarios', 'Hourly rate' => 'Cobro horario', 'Currency' => 'Moneda', @@ -690,17 +690,17 @@ return array( 'Work timetable' => 'Horario de trabajo', 'Week timetable' => 'Horario semanal', 'Day timetable' => 'Horario diario', - 'From' => 'Desde', - 'To' => 'Hasta', - 'Time slot created successfully.' => 'Tiempo asignado creado correctamente.', - 'Unable to save this time slot.' => 'No pude grabar este tiempo asignado.', - 'Time slot removed successfully.' => 'Tiempo asignado quitado correctamente.', - 'Unable to remove this time slot.' => 'No pude quitar este tiempo asignado.', - 'Do you really want to remove this time slot?' => '¿Realmente quieres quitar este tiempo asignado?', - 'Remove time slot' => 'Quitar tiempo asignado', - 'Add new time slot' => 'Añadir nuevo tiempo asignado', + 'From' => 'De', + 'To' => 'Para', + 'Time slot created successfully.' => 'Intervalo de tiempo creado correctamente.', + 'Unable to save this time slot.' => 'No pude grabar este intervalo de tiempo.', + 'Time slot removed successfully.' => 'Intervalo de tiempo quitado correctamente.', + 'Unable to remove this time slot.' => 'No pude quitar este intervalo de tiempo.', + 'Do you really want to remove this time slot?' => '¿Realmente quiere quitar este intervalo de tiempo?', + 'Remove time slot' => 'Quitar intervalo de tiempo', + 'Add new time slot' => 'Añadir nuevo intervalo de tiempo', 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Este horario se usa cuando se marca la casilla "todos los días" para calendario de tiempo libre y horas extras.', - 'Files' => 'Archivos', + 'Files' => 'Ficheros', 'Images' => 'Imágenes', 'Private project' => 'Proyecto privado', 'Amount' => 'Cantidad', @@ -715,7 +715,7 @@ return array( 'Cost breakdown' => 'Desglose de costes', 'Custom Stylesheet' => 'Hoja de estilo Personalizada', 'download' => 'descargar', - 'Do you really want to remove this budget line?' => '¿Realmente quieres quitar esta línea de presupuesto?', + 'Do you really want to remove this budget line?' => '¿Realmente quiere quitar esta línea de presupuesto?', 'EUR - Euro' => 'EUR - Euro', 'Expenses' => 'Gastos', 'GBP - British Pound' => 'GBP - Libra británica', @@ -733,9 +733,9 @@ return array( 'Remaining' => 'Restante', 'Destination column' => 'Columna destino', 'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse al usuario', - 'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el asignado', + 'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el concesionario', 'Source column' => 'Columna fuente', - 'Show subtask estimates (forecast of future work)' => 'Mostrar estimado para la subtarea (pronóstico de trabajo futuro)', + 'Show subtask estimates (forecast of future work)' => 'Mostrar estimaciones para la subtarea (pronóstico de trabajo futuro)', 'Transitions' => 'Transiciones', 'Executer' => 'Ejecutor', 'Time spent in the column' => 'Tiempo transcurrido en la columna', @@ -753,7 +753,7 @@ return array( 'Send notifications to a Slack channel' => 'Enviar notificaciones a un canal Desatendido', 'Webhook URL' => 'URL de Disparador Web (webhook)', 'Help on Slack integration' => 'Ayuda sobre integración Desatendida', - '%s remove the assignee of the task %s' => '%s quita el asignado de la tarea %s', + '%s remove the assignee of the task %s' => '%s quita el concesionario de la tarea %s', 'Send notifications to Hipchat' => 'Enviar notificaciones a Hipchat', 'API URL' => 'URL de API', 'Room API ID or name' => 'ID de API de habitación o nombre', @@ -768,10 +768,10 @@ return array( 'Two factor authentication' => 'Autenticación de dos factores', 'Enable/disable two factor authentication' => 'Activar/desactivar autenticación de dos factores', 'This QR code contains the key URI: ' => 'Este código QR contiene la clave URI: ', - 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Guarda la clave secreta en tu software TOTP (por ejemplo Autenticación Google o FreeOTP).', + 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Guarda la clave secreta en su software TOTP (por ejemplo Autenticación de Google o FreeOTP).', 'Check my code' => 'Revisar mi código', 'Secret key: ' => 'Clave secreta: ', - 'Test your device' => 'Probar tu dispositivo', + 'Test your device' => 'Probar su dispositivo', 'Assign a color when the task is moved to a specific column' => 'Asignar un color al mover la tarea a una columna específica', '%s via Kanboard' => '%s vía Kanboard', 'uploaded by: %s' => 'cargado por: %s', @@ -785,7 +785,7 @@ return array( 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Capture un patallazo y pulse CTRL+V o ⌘+V para pegar aquí.', 'Screenshot uploaded successfully.' => 'Pantallazo cargado con éxito', 'SEK - Swedish Krona' => 'SEK - Corona sueca', - 'The project identifier is an optional alphanumeric code used to identify your project.' => 'El identificador del proyecto us un código opcional alfanumérico que se usa para identificar tu proyecto.', + 'The project identifier is an optional alphanumeric code used to identify your project.' => 'El identificador del proyecto us un código opcional alfanumérico que se usa para identificar su proyecto.', 'Identifier' => 'Identificador', 'Postmark (incoming emails)' => 'Matasellos (emails entrantes)', 'Help on Postmark integration' => 'Ayuda sobre la integración de Matasellos', @@ -794,37 +794,37 @@ return array( 'Sendgrid (incoming emails)' => 'Sendgrid (emails entrantes)', 'Help on Sendgrid integration' => 'Ayuda sobre la integración con Sendgrid', 'Disable two factor authentication' => 'Desactivar la autenticación de dos factores', - 'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmentes quieres desactuvar la autenticación de dos factores para este usuario: "%s?"', + 'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmentes quiere desactuvar la autenticación de dos factores para este usuario: "%s?"', 'Edit link' => 'Editar enlace', 'Start to type task title...' => 'Empiece a escribir el título de la tarea...', - 'A task cannot be linked to itself' => 'Una tarea no puede se enlazada con sí misma', + 'A task cannot be linked to itself' => 'Una tarea no puede se enlazada con sigo misma', 'The exact same link already exists' => 'El mismo enlace ya existe', 'Recurrent task is scheduled to be generated' => 'Tarea recurrente programada para ser generada', 'Recurring information' => 'Información recurrente', - 'Score' => 'Puntaje', + 'Score' => 'Puntuación', 'The identifier must be unique' => 'El identificador debe ser único', 'This linked task id doesn\'t exists' => 'El id de tarea no existe', 'This value must be alphanumeric' => 'Este valor debe ser alfanumérico', - 'Edit recurrence' => 'Editar recurrencia', + 'Edit recurrence' => 'Editar repetición', 'Generate recurrent task' => 'Generar tarea recurrente', 'Trigger to generate recurrent task' => 'Disparador para generar tarea recurrente', - 'Factor to calculate new due date' => 'Factor para calcular la nueva fecha de vencimiento', - 'Timeframe to calculate new due date' => 'Calendario para calcular la nueva fecha de vencimiento', - 'Base date to calculate new due date' => 'Fecha base para calcular la nueva fecha de vencimiento', - 'Action date' => 'Fecha de acción', - 'Base date to calculate new due date: ' => 'Fecha base para calcular la nueva fecha de vencimiento:', + 'Factor to calculate new due date' => 'Factor para calcular la nueva fecha de entrega', + 'Timeframe to calculate new due date' => 'Calendario para calcular la nueva fecha de entrega', + 'Base date to calculate new due date' => 'Fecha base para calcular la nueva fecha de entrega', + 'Action date' => 'Fecha de la acción', + 'Base date to calculate new due date: ' => 'Fecha base para calcular la nueva fecha de entrega:', 'This task has created this child task: ' => 'Esta tarea ha cerado esta tarea hija:', 'Day(s)' => 'Día(s)', - 'Existing due date' => 'Fecha de vencimiento existente', - 'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de vencimiento:', + 'Existing due date' => 'Fecha de entrega existente', + 'Factor to calculate new due date: ' => 'Factor para calcular la nueva fecha de entrega:', 'Month(s)' => 'Mes(es)', - 'Recurrence' => 'Recurrencia', + 'Recurrence' => 'Repetición', 'This task has been created by: ' => 'Esta tarea ha sido creada por: ', 'Recurrent task has been generated:' => 'Tarea recurrente generada:', - 'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de vencimiento:', + 'Timeframe to calculate new due date: ' => 'Calendario para calcular la nueva fecha de entrega:', 'Trigger to generate recurrent task: ' => 'Disparador para generar tarea recurrente', 'When task is closed' => 'Cuando la tarea es cerrada', - 'When task is moved from first column' => 'Cuando la tarea es movida a la primer columna', + 'When task is moved from first column' => 'Cuando la tarea es movida desde la primera columna', 'When task is moved to last column' => 'Cuando la tarea es movida a la última columna', 'Year(s)' => 'Año(s)', 'Jabber (XMPP)' => 'Jabber (XMPP)', @@ -847,172 +847,224 @@ return array( 'iCal feed' => 'Fuente iCal', 'Preferences' => 'Preferencias', 'Security' => 'Seguridad', - 'Two factor authentication disabled' => 'Autenticación de dos factores deshabilitado', - 'Two factor authentication enabled' => 'Autenticación de dos factores habilitado', + 'Two factor authentication disabled' => 'Autenticación de dos factores deshabilitada', + 'Two factor authentication enabled' => 'Autenticación de dos factores habilitada', 'Unable to update this user.' => 'Imposible actualizar este usuario.', 'There is no user management for private projects.' => 'No hay gestión de usuarios para proyectos privados.', 'User that will receive the email' => 'Usuario que recibirá el correo', 'Email subject' => 'Asunto del correo', 'Date' => 'Fecha', - // 'By @%s on Bitbucket' => '', - // 'Bitbucket Issue' => '', - // 'Commit made by @%s on Bitbucket' => '', - // 'Commit made by @%s on Github' => '', - // 'By @%s on Github' => '', - // 'Commit made by @%s on Gitlab' => '', - // 'Add a comment log when moving the task between columns' => '', + 'By @%s on Bitbucket' => 'Mediante @%s en Bitbucket', + 'Bitbucket Issue' => 'Asunto de Bitbucket', + 'Commit made by @%s on Bitbucket' => 'Envío realizado por @%s en Bitbucket', + 'Commit made by @%s on Github' => 'Envío realizado por @%s en Github', + 'By @%s on Github' => 'Por @%s en Github', + 'Commit made by @%s on Gitlab' => 'Envío realizado por @%s en Gitlab', + 'Add a comment log when moving the task between columns' => 'Añadir un comentario al mover la tarea entre columnas', 'Move the task to another column when the category is changed' => 'Mover la tarea a otra columna cuando cambia la categoría', 'Send a task by email to someone' => 'Enviar una tarea a alguien por correo', 'Reopen a task' => 'Reabrir tarea', - // 'Bitbucket issue opened' => '', - // 'Bitbucket issue closed' => '', - // 'Bitbucket issue reopened' => '', - // 'Bitbucket issue assignee change' => '', - // 'Bitbucket issue comment created' => '', + 'Bitbucket issue opened' => 'Abierto asunto de Bitbucket', + 'Bitbucket issue closed' => 'Cerrado asunto de Bitbucket', + 'Bitbucket issue reopened' => 'Reabierto asunto de Bitbucket', + 'Bitbucket issue assignee change' => 'Cambiado concesionario de asunto de Bitbucket', + 'Bitbucket issue comment created' => 'Creado comentario de asunto de Bitbucket', 'Column change' => 'Cambio de columna', 'Position change' => 'Cambio de posición', - 'Swimlane change' => 'Cambio de carril', - 'Assignee change' => 'Cambio de usuario asignado', + 'Swimlane change' => 'Cambio de calle', + 'Assignee change' => 'Cambio de concesionario', '[%s] Overdue tasks' => '[%s] Tareas vencidas', 'Notification' => 'Notificación', - // '%s moved the task #%d to the first swimlane' => '', - // '%s moved the task #%d to the swimlane "%s"' => '', - 'Swimlane' => 'Carril', - // 'Budget overview' => '', + '%s moved the task #%d to the first swimlane' => '%s movió la tarea #%d a la primera calle', + '%s moved the task #%d to the swimlane "%s"' => '%s movió la tarea #%d a la calle "%s"', + 'Swimlane' => 'Calle', + 'Budget overview' => 'Resumen del Presupuesto', 'Type' => 'Tipo', - // 'There is not enough data to show something.' => '', - // 'Gravatar' => '', - // 'Hipchat' => '', - // 'Slack' => '', - // '%s moved the task %s to the first swimlane' => '', - // '%s moved the task %s to the swimlane "%s"' => '', - // 'This report contains all subtasks information for the given date range.' => '', - // 'This report contains all tasks information for the given date range.' => '', - // 'Project activities for %s' => '', - // 'view the board on Kanboard' => '', - // 'The task have been moved to the first swimlane' => '', - // 'The task have been moved to another swimlane:' => '', - // 'Overdue tasks for the project "%s"' => '', - // 'New title: %s' => '', - // 'The task is not assigned anymore' => '', - // 'New assignee: %s' => '', - // 'There is no category now' => '', - // 'New category: %s' => '', - // 'New color: %s' => '', - // 'New complexity: %d' => '', - // 'The due date have been removed' => '', - // 'There is no description anymore' => '', - // 'Recurrence settings have been modified' => '', - // 'Time spent changed: %sh' => '', - // 'Time estimated changed: %sh' => '', - // 'The field "%s" have been updated' => '', - // 'The description have been modified' => '', - // 'Do you really want to close the task "%s" as well as all subtasks?' => '', - // 'Swimlane: %s' => '', - // 'I want to receive notifications for:' => '', - // 'All tasks' => '', - // 'Only for tasks assigned to me' => '', - // 'Only for tasks created by me' => '', - // 'Only for tasks created by me and assigned to me' => '', - // '%A' => '', - // '%b %e, %Y, %k:%M %p' => '', - // 'New due date: %B %e, %Y' => '', - // 'Start date changed: %B %e, %Y' => '', - // '%k:%M %p' => '', - // '%%Y-%%m-%%d' => '', - // 'Total for all columns' => '', - // 'You need at least 2 days of data to show the chart.' => '', - // '<15m' => '', - // '<30m' => '', - // 'Stop timer' => '', - // 'Start timer' => '', - // 'Add project member' => '', - // 'Enable notifications' => '', - // 'My activity stream' => '', - // 'My calendar' => '', - // 'Search tasks' => '', - // 'Back to the calendar' => '', - // 'Filters' => '', - // 'Reset filters' => '', - // 'My tasks due tomorrow' => '', - // 'Tasks due today' => '', - // 'Tasks due tomorrow' => '', - // 'Tasks due yesterday' => '', - // 'Closed tasks' => '', - // 'Open tasks' => '', - // 'Not assigned' => '', - // 'View advanced search syntax' => '', - // 'Overview' => '', - // '%b %e %Y' => '', - // 'Board/Calendar/List view' => '', - // 'Switch to the board view' => '', - // 'Switch to the calendar view' => '', - // 'Switch to the list view' => '', - // 'Go to the search/filter box' => '', - // 'There is no activity yet.' => '', - // 'No tasks found.' => '', - // 'Keyboard shortcut: "%s"' => '', + 'There is not enough data to show something.' => 'No hay datos suficientes como para mostrar algo.', + 'Gravatar' => 'Gravatar', + 'Hipchat' => 'Hipchat', + 'Slack' => 'Desatendida', + '%s moved the task %s to the first swimlane' => '%s movió la tarea %s a la primera calle', + '%s moved the task %s to the swimlane "%s"' => '%s movió la tarea %s a la calle "%s"', + 'This report contains all subtasks information for the given date range.' => 'Este informe contiene todas la información de las subtareas para el rango proporcionado de fechas.', + 'This report contains all tasks information for the given date range.' => 'Este informe contiene todas la información de las tareas para el rango proporcionado de fechas.', + 'Project activities for %s' => 'Actividades del proyecto para %s', + 'view the board on Kanboard' => 'ver el tablero en Kanboard', + 'The task have been moved to the first swimlane' => 'Se ha movido la tarea a la primera calle', + 'The task have been moved to another swimlane:' => 'Se ha movido la tarea a otra calle', + 'Overdue tasks for the project "%s"' => 'Tareas atrasadas para el proyecto "%s"', + 'New title: %s' => 'Nuevo título: %s', + 'The task is not assigned anymore' => 'La tarea ya no está asignada', + 'New assignee: %s' => 'Nuevo concesionario: %s', + 'There is no category now' => 'En este momento no hay categorías', + 'New category: %s' => 'Nueva categoría: %s', + 'New color: %s' => 'Nuevo color: %s', + 'New complexity: %d' => 'Nueva complejidad: %d', + 'The due date have been removed' => 'Se ha quitado la fecha de entrega', + 'There is no description anymore' => 'Ya no hay descripción', + 'Recurrence settings have been modified' => 'Se han modificado los valores recurrentes', + 'Time spent changed: %sh' => 'Se ha cambiado el tiempo empleado: %sh', + 'Time estimated changed: %sh' => 'Se ha cambiado el tiempo estimado: %sh', + 'The field "%s" have been updated' => 'Se ha actualizado el campo "%s"', + 'The description have been modified' => 'Se ha modificado la descripción', + 'Do you really want to close the task "%s" as well as all subtasks?' => '¿De verdad que quiere cerra la tarea "%s" así como todas las subtareas?', + 'Swimlane: %s' => 'Calle: %s', + 'I want to receive notifications for:' => 'Deseo recibir notificaciones para:', + 'All tasks' => 'Todas las tareas', + 'Only for tasks assigned to me' => 'Sólo para las tareas que me han sido asignadas', + 'Only for tasks created by me' => 'Sólo para las taread creadas por mí', + 'Only for tasks created by me and assigned to me' => 'Sólo para las tareas credas por mí y que me han sido asignadas', + '%A' => '%A', + '%b %e, %Y, %k:%M %p' => '%e de %B de %Y a las %k:%M %p', + 'New due date: %B %e, %Y' => 'Nueva fecha de entrega: %B %e, %Y', + 'Start date changed: %B %e, %Y' => 'Cambiadad fecha de inicio: %B %e, %Y', + '%k:%M %p' => '%k:%M %p', + '%%Y-%%m-%%d' => '%%d/%%M/%%Y', + 'Total for all columns' => 'Total para todas las columnas', + 'You need at least 2 days of data to show the chart.' => 'Necesitas al menos 2 días de datos para mostrar el gráfico.', + '<15m' => '<15m', + '<30m' => '<30m', + 'Stop timer' => 'Parar temporizador', + 'Start timer' => 'Arrancar temporizador', + 'Add project member' => 'Añadir miembro al proyecto', + 'Enable notifications' => 'Activar notificaciones', + 'My activity stream' => 'Mi flujo de actividad', + 'My calendar' => 'Mi calendario', + 'Search tasks' => 'Buscar tareas', + 'Back to the calendar' => 'Volver al calendario', + 'Filters' => 'Filtros', + 'Reset filters' => 'Limpiar filtros', + 'My tasks due tomorrow' => 'Mis tareas a entregar mañana', + 'Tasks due today' => 'Tareas a antregar hoy', + 'Tasks due tomorrow' => 'Taraes a entregar mañana', + 'Tasks due yesterday' => 'Tareas a entregar ayer', + 'Closed tasks' => 'Tareas cerradas', + 'Open tasks' => 'Tareas abiertas', + 'Not assigned' => 'No asignada', + 'View advanced search syntax' => 'Ver sintáxis avanzada de búsqueda', + 'Overview' => 'Resumen', + '%b %e %Y' => '%e de %B de %Y', + 'Board/Calendar/List view' => 'Vista de Tablero/Calendario/Lista', + 'Switch to the board view' => 'Cambiar a vista de tablero', + 'Switch to the calendar view' => 'Cambiar a vista de calendario', + 'Switch to the list view' => 'Cambiar a vista de lista', + 'Go to the search/filter box' => 'Ir a caja de buscar/filtrar', + 'There is no activity yet.' => 'Aún no hay actividades.', + 'No tasks found.' => 'No se ha hallado tarea alguna.', + 'Keyboard shortcut: "%s"' => 'Atajo de teclado: %s', 'List' => 'Lista', 'Filter' => 'Filtro', 'Advanced search' => 'Búsqueda avanzada', - // 'Example of query: ' => '', - // 'Search by project: ' => '', - // 'Search by column: ' => '', - // 'Search by assignee: ' => '', - // 'Search by color: ' => '', - // 'Search by category: ' => '', - // 'Search by description: ' => '', - // 'Search by due date: ' => '', - // 'Lead and Cycle time for "%s"' => '', - // 'Average time spent into each column for "%s"' => '', - // 'Average time spent into each column' => '', - // 'Average time spent' => '', - // 'This chart show the average time spent into each column for the last %d tasks.' => '', - // 'Average Lead and Cycle time' => '', - // 'Average lead time: ' => '', - // 'Average cycle time: ' => '', - // 'Cycle Time' => '', - // 'Lead Time' => '', - // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', - // 'Average time into each column' => '', - // 'Lead and cycle time' => '', - // 'Google Authentication' => '', - // 'Help on Google authentication' => '', - // 'Github Authentication' => '', - // 'Help on Github authentication' => '', - // 'Channel/Group/User (Optional)' => '', - // 'Lead time: ' => '', - // 'Cycle time: ' => '', - // 'Time spent into each column' => '', - // 'The lead time is the duration between the task creation and the completion.' => '', - // 'The cycle time is the duration between the start date and the completion.' => '', - // 'If the task is not closed the current time is used instead of the completion date.' => '', - // 'Set automatically the start date' => '', + 'Example of query: ' => 'Ejemplo de query: ', + 'Search by project: ' => 'Buscar por proyecto: ', + 'Search by column: ' => 'Buscar por columna: ', + 'Search by assignee: ' => 'Buscar por concesionario: ', + 'Search by color: ' => 'Buscar por color: ', + 'Search by category: ' => 'Buscar por categoría: ', + 'Search by description: ' => 'Buscar por descripción: ', + 'Search by due date: ' => 'Buscar por fecha de entrega: ', + 'Lead and Cycle time for "%s"' => 'Plazo de Entrega y Ciclo para "%s"', + 'Average time spent into each column for "%s"' => 'Tiempo medio empleado en cada columna para "%s"', + 'Average time spent into each column' => 'Tiempo medio empleado en cada columna', + 'Average time spent' => 'Tiempo medio empleado', + 'This chart show the average time spent into each column for the last %d tasks.' => 'Esta gráfica muestra el tiempo medio empleado en cada columna para las últimas %d tareas.', + 'Average Lead and Cycle time' => 'Plazo Medio de Entrega y de Ciclo', + 'Average lead time: ' => 'Plazo Medio de entrega: ', + 'Average cycle time: ' => 'Tiempo Medio de Ciclo: ', + 'Cycle Time' => 'Tiempo de Ciclo', + 'Lead Time' => 'Plazo de Entrega', + 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Esta gráfica muestra el plazo medio de entrega y de ciclo para las %d últimas tareas transcurridas.', + 'Average time into each column' => 'Tiempo medio en cada columna', + 'Lead and cycle time' => 'Plazo de entrega y de ciclo', + 'Google Authentication' => 'Autenticación de Google', + 'Help on Google authentication' => 'Ayuda con la aAutenticación de Google', + 'Github Authentication' => 'Autenticación de Github', + 'Help on Github authentication' => 'Ayuda con la autenticación de Github', + 'Channel/Group/User (Optional)' => 'Canal/Grupo/Usuario (Opcional)', + 'Lead time: ' => 'Plazo de entrega: ', + 'Cycle time: ' => 'Tiempo de Ciclo: ', + 'Time spent into each column' => 'Tiempo empleado en cada columna', + 'The lead time is the duration between the task creation and the completion.' => 'El plazo de entrega es la duración entre la creación de la tarea su terminación.', + 'The cycle time is the duration between the start date and the completion.' => 'El tiempo de ciclo es la duración entre la fecha de inicio y su terminación.', + 'If the task is not closed the current time is used instead of the completion date.' => 'Si la tarea no se cierra, se usa la fecha actual en lugar de la de terminación.', + 'Set automatically the start date' => 'Poner la fecha de inicio de forma automática', 'Edit Authentication' => 'Editar autenticación', - // 'Google Id' => '', - // 'Github Id' => '', + 'Google Id' => 'Id de Google', + 'Github Id' => 'Id de Github', 'Remote user' => 'Usuario remoto', - // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', - // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', - // 'By @%s on Gitlab' => '', - // 'Gitlab issue comment created' => '', - // 'New remote user' => '', - // 'New local user' => '', - // 'Default task color' => '', - // 'Hide sidebar' => '', - // 'Expand sidebar' => '', - // 'This feature does not work with all browsers.' => '', - // 'There is no destination project available.' => '', - // 'Trigger automatically subtask time tracking' => '', - // 'Include closed tasks in the cumulative flow diagram' => '', - // 'Current swimlane: %s' => '', - // 'Current column: %s' => '', - // 'Current category: %s' => '', - // 'no category' => '', - // 'Current assignee: %s' => '', - // 'not assigned' => '', - // 'Author:' => '', - // 'contributors' => '', - // 'License:' => '', - // 'License' => '', + 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Los usuarios remotos no almacenan sus contraseñas en la base de datos Kanboard, por ejemplo: cuentas de LDAP, Google y Github', + 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si marcas la caja de edición "Desactivar formulario de ingreso", se ignoran las credenciales entradas en el formulario de ingreso.', + 'By @%s on Gitlab' => 'Por @%s en Gitlab', + 'Gitlab issue comment created' => 'Creado comentario de asunto de Gitlab', + 'New remote user' => 'Nuevo usuario remoto', + 'New local user' => 'Nuevo usuario local', + 'Default task color' => 'Color por defecto de tarea', + 'Hide sidebar' => 'Ocultar barra lateral', + 'Expand sidebar' => 'Expandir barra lateral', + 'This feature does not work with all browsers.' => 'Esta característica no funciona con todos los navegadores', + 'There is no destination project available.' => 'No está disponible proyecto destino', + 'Trigger automatically subtask time tracking' => 'Disparar de forma automática seguimiento temporal de subtarea', + 'Include closed tasks in the cumulative flow diagram' => 'Incluir tareas cerradas en el diagrama de flujo acumulado', + 'Current swimlane: %s' => 'Calle en curso: %s', + 'Current column: %s' => 'Columna en curso: %s', + 'Current category: %s' => 'Categoría en curso: %s', + 'no category' => 'no hay categoría', + 'Current assignee: %s' => 'Concesionario en curso: %s', + 'not assigned' => 'sin asignar', + 'Author:' => 'Autor:', + 'contributors' => 'contribuyentes', + 'License:' => 'Licencia:', + 'License' => 'Licencia', + 'Project Administrator' => 'Administrador del Proyecto', + 'Enter the text below' => 'Digita el texto de abajo', + 'Gantt chart for %s' => 'Diagrama de Gantt para %s', + 'Sort by position' => 'Clasificado mediante posición', + 'Sort by date' => 'Clasificado mediante fecha', + 'Add task' => 'Añadir tarea', + 'Start date:' => 'Fecha de inicio:', + 'Due date:' => 'Fecha de entrega:', + 'There is no start date or due date for this task.' => 'No hay fecha de inicio o de entrega para esta tarea.', + 'Moving or resizing a task will change the start and due date of the task.' => 'El mover o redimensionar una tarea cambiará la fecha inicio y de entrega de la misma.', + 'There is no task in your project.' => 'No hay tareas en su proyecto.', + 'Gantt chart' => 'Digrama de Gantt', + 'People who are project managers' => 'Usuarios que son administradores de proyecto', + 'People who are project members' => 'Usuarios que son miembros de proyecto', + 'NOK - Norwegian Krone' => 'NOK - Coronoa Noruega', + 'Show this column' => 'Mostrar esta columna', + 'Hide this column' => 'Ocultar esta columna', + 'open file' => 'abrir fichero', + 'End date' => 'Fecha de fin', + 'Users overview' => 'Resumen de usuarios', + 'Managers' => 'Administradores', + 'Members' => 'Miembros', + 'Shared project' => 'Proyecto compartido', + 'Project managers' => 'Administradores de proyecto', + 'Project members' => 'Miembros de proyecto', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/fi_FI/translations.php b/sources/app/Locale/fi_FI/translations.php index 4acd409..d8c749a 100644 --- a/sources/app/Locale/fi_FI/translations.php +++ b/sources/app/Locale/fi_FI/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/fr_FR/translations.php b/sources/app/Locale/fr_FR/translations.php index 11a429e..0c95c7e 100644 --- a/sources/app/Locale/fr_FR/translations.php +++ b/sources/app/Locale/fr_FR/translations.php @@ -163,7 +163,7 @@ return array( '%B %e, %Y at %k:%M %p' => '%d/%m/%Y à %H:%M', 'Date created' => 'Date de création', 'Date completed' => 'Date de clôture', - 'Id' => 'Identifiant', + 'Id' => 'Id.', '%d closed tasks' => '%d tâches terminées', 'No task for this project' => 'Aucune tâche pour ce projet', 'Public link' => 'Lien public', @@ -1017,4 +1017,56 @@ return array( 'contributors' => 'contributeurs', 'License:' => 'Licence :', 'License' => 'Licence', + 'Project Administrator' => 'Administrateur de projet', + 'Enter the text below' => 'Entrez le texte ci-dessous', + 'Gantt chart for %s' => 'Diagramme de Gantt pour %s', + 'Sort by position' => 'Trier par position', + 'Sort by date' => 'Trier par date', + 'Add task' => 'Ajouter une tâche', + 'Start date:' => 'Date de début :', + 'Due date:' => 'Date d\'échéance :', + 'There is no start date or due date for this task.' => 'Il n\'y a pas de date de début ou de date de fin pour cette tâche.', + 'Moving or resizing a task will change the start and due date of the task.' => 'Déplacer ou redimensionner une tâche va changer la date de début et la date de fin de la tâche.', + 'There is no task in your project.' => 'Il n\'y a aucun tâche dans votre projet.', + 'Gantt chart' => 'Diagramme de Gantt', + 'People who are project managers' => 'Personnes qui sont gestionnaire de projet', + 'People who are project members' => 'Personnes qui sont membre de projet', + 'NOK - Norwegian Krone' => 'NOK - Couronne norvégienne', + 'Show this column' => 'Montrer cette colonne', + 'Hide this column' => 'Cacher cette colonne', + 'open file' => 'ouvrir un fichier', + 'End date' => 'Date de fin', + 'Users overview' => 'Vue d\'ensemble des utilisateurs', + 'Managers' => 'Gérants', + 'Members' => 'Membres', + 'Shared project' => 'Projet partagé', + 'Project managers' => 'Gestionnaires de projet', + 'Project members' => 'Membres de projet', + 'Gantt chart for all projects' => 'Diagramme de Gantt pour tous les projets', + 'Projects list' => 'List des projets', + 'Gantt chart for this project' => 'Diagramme de Gantt pour ce projet', + 'Project board' => 'Tableau du projet', + 'End date:' => 'Date de fin :', + 'There is no start date or end date for this project.' => 'Il n\'y a pas de date de début ou de date de fin pour ce projet.', + 'Projects Gantt chart' => 'Diagramme de Gantt des projets', + 'Start date: %s' => 'Date de début : %s', + 'End date: %s' => 'Date de fin : %s', + 'Link type' => 'Type de lien', + 'Change task color when using a specific task link' => 'Changer la couleur de la tâche lorsqu\'un lien spécifique est utilisé', + 'Task link creation or modification' => 'Création ou modification d\'un lien sur une tâche', + 'Login with my Gitlab Account' => 'Se connecter avec mon compte Gitlab', + 'Milestone' => 'Étape importante', + 'Gitlab Authentication' => 'Authentification Gitlab', + 'Help on Gitlab authentication' => 'Aide sur l\'authentification Gitlab', + 'Gitlab Id' => 'Identifiant Gitlab', + 'Gitlab Account' => 'Compte Gitlab', + 'Link my Gitlab Account' => 'Lier mon compte Gitlab', + 'Unlink my Gitlab Account' => 'Ne plus utiliser mon compte Gitlab', + 'Documentation: %s' => 'Documentation : %s', + 'Switch to the Gantt chart view' => 'Passer à la vue en diagramme de Gantt', + 'Reset the search/filter box' => 'Réinitialiser le champ de recherche', + 'Documentation' => 'Documentation', + 'Table of contents' => 'Table des matières', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Aide avec les permissions des projets', ); diff --git a/sources/app/Locale/hu_HU/translations.php b/sources/app/Locale/hu_HU/translations.php index 18737dc..b346f1e 100644 --- a/sources/app/Locale/hu_HU/translations.php +++ b/sources/app/Locale/hu_HU/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/it_IT/translations.php b/sources/app/Locale/it_IT/translations.php index 93800be..06e2c5c 100644 --- a/sources/app/Locale/it_IT/translations.php +++ b/sources/app/Locale/it_IT/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/ja_JP/translations.php b/sources/app/Locale/ja_JP/translations.php index 77ebd65..cb8c550 100644 --- a/sources/app/Locale/ja_JP/translations.php +++ b/sources/app/Locale/ja_JP/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/nl_NL/translations.php b/sources/app/Locale/nl_NL/translations.php index fedf0c6..23d6416 100644 --- a/sources/app/Locale/nl_NL/translations.php +++ b/sources/app/Locale/nl_NL/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/pl_PL/translations.php b/sources/app/Locale/pl_PL/translations.php index e55e2dc..9947cf3 100644 --- a/sources/app/Locale/pl_PL/translations.php +++ b/sources/app/Locale/pl_PL/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/pt_BR/translations.php b/sources/app/Locale/pt_BR/translations.php index 8965c5a..6aa2f4d 100644 --- a/sources/app/Locale/pt_BR/translations.php +++ b/sources/app/Locale/pt_BR/translations.php @@ -263,10 +263,10 @@ return array( '%d comments' => '%d comentários', '%d comment' => '%d comentário', 'Email address invalid' => 'Endereço de e-mail inválido', - // 'Your external account is not linked anymore to your profile.' => '', - // 'Unable to unlink your external account.' => '', - // 'External authentication failed' => '', - // 'Your external account is linked to your profile successfully.' => '', + 'Your external account is not linked anymore to your profile.' => 'Sua conta externa não está mais ligada ao seu perfil.', + 'Unable to unlink your external account.' => 'Impossível de remover a sua conta externa.', + 'External authentication failed' => 'Autenticação externa falhou', + 'Your external account is linked to your profile successfully.' => 'Sua conta externa está agora ligada ao seu perfil.', 'Email' => 'E-mail', 'Link my Google Account' => 'Vincular minha Conta do Google', 'Unlink my Google Account' => 'Desvincular minha Conta do Google', @@ -608,7 +608,7 @@ return array( 'Time Tracking' => 'Gestão de tempo', 'You already have one subtask in progress' => 'Você já tem um subtarefa em andamento', 'Which parts of the project do you want to duplicate?' => 'Quais as partes do projeto você deseja duplicar?', - // 'Disallow login form' => '', + 'Disallow login form' => 'Proibir o formulário de login', 'Bitbucket commit received' => '"Commit" recebido via Bitbucket', 'Bitbucket webhooks' => 'Webhook Bitbucket', 'Help on Bitbucket webhooks' => 'Ajuda sobre os webhooks Bitbucket', @@ -963,56 +963,108 @@ return array( 'Search by category: ' => 'Pesquisar por categoria: ', 'Search by description: ' => 'Pesquisar por descrição: ', 'Search by due date: ' => 'Pesquisar por data de expiração: ', - // 'Lead and Cycle time for "%s"' => '', - // 'Average time spent into each column for "%s"' => '', - // 'Average time spent into each column' => '', - // 'Average time spent' => '', - // 'This chart show the average time spent into each column for the last %d tasks.' => '', - // 'Average Lead and Cycle time' => '', - // 'Average lead time: ' => '', - // 'Average cycle time: ' => '', - // 'Cycle Time' => '', - // 'Lead Time' => '', - // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', - // 'Average time into each column' => '', - // 'Lead and cycle time' => '', - // 'Google Authentication' => '', - // 'Help on Google authentication' => '', - // 'Github Authentication' => '', - // 'Help on Github authentication' => '', - // 'Channel/Group/User (Optional)' => '', - // 'Lead time: ' => '', - // 'Cycle time: ' => '', - // 'Time spent into each column' => '', - // 'The lead time is the duration between the task creation and the completion.' => '', - // 'The cycle time is the duration between the start date and the completion.' => '', - // 'If the task is not closed the current time is used instead of the completion date.' => '', - // 'Set automatically the start date' => '', - // 'Edit Authentication' => '', - // 'Google Id' => '', - // 'Github Id' => '', - // 'Remote user' => '', - // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', - // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', - // 'By @%s on Gitlab' => '', - // 'Gitlab issue comment created' => '', - // 'New remote user' => '', - // 'New local user' => '', - // 'Default task color' => '', - // 'Hide sidebar' => '', - // 'Expand sidebar' => '', - // 'This feature does not work with all browsers.' => '', - // 'There is no destination project available.' => '', - // 'Trigger automatically subtask time tracking' => '', - // 'Include closed tasks in the cumulative flow diagram' => '', - // 'Current swimlane: %s' => '', - // 'Current column: %s' => '', - // 'Current category: %s' => '', - // 'no category' => '', - // 'Current assignee: %s' => '', - // 'not assigned' => '', - // 'Author:' => '', - // 'contributors' => '', - // 'License:' => '', - // 'License' => '', + 'Lead and Cycle time for "%s"' => 'Lead and Cycle time para "%s"', + 'Average time spent into each column for "%s"' => 'Tempo médio gasto em cada coluna para "%s"', + 'Average time spent into each column' => 'Tempo médio gasto em cada coluna', + 'Average time spent' => 'Tempo médio gasto', + 'This chart show the average time spent into each column for the last %d tasks.' => 'Este gráfico mostra o tempo médio gasto em cada coluna durante nas %d últimas tarefas.', + 'Average Lead and Cycle time' => 'Tempo médio do Lead and cycle time', + 'Average lead time: ' => 'Lead time medio: ', + 'Average cycle time: ' => 'Cycle time medio: ', + 'Cycle Time' => 'Cycle time', + 'Lead Time' => 'Lead time', + 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Este gráfico mostra o tempo médio do Lead and cycle time das últimas %d tarefas.', + 'Average time into each column' => 'Tempo médio de cada coluna', + 'Lead and cycle time' => 'Lead and cycle time', + 'Google Authentication' => 'Autenticação Google', + 'Help on Google authentication' => 'Ajuda com a autenticação Google', + 'Github Authentication' => 'Autenticação Github', + 'Help on Github authentication' => 'Ajuda com a autenticação Github', + 'Channel/Group/User (Optional)' => 'Canal/Grupo/Utilizador (Opcional)', + 'Lead time: ' => 'Lead time: ', + 'Cycle time: ' => 'Cycle time: ', + 'Time spent into each column' => 'Tempo gasto em cada coluna', + 'The lead time is the duration between the task creation and the completion.' => 'O Lead time é o tempo gasto entre a criação da tarefa e a sua conclusão.', + 'The cycle time is the duration between the start date and the completion.' => 'O Cycle time é o tempo gasto entre a data de início e a sua conclusão.', + 'If the task is not closed the current time is used instead of the completion date.' => 'Se a tarefa não está fechada, a hora atual é usada no lugar da data de conclusão.', + 'Set automatically the start date' => 'Definir automaticamente a data de início', + 'Edit Authentication' => 'Modificar a autenticação', + 'Google Id' => 'Google ID', + 'Github Id' => 'Github Id', + 'Remote user' => 'Usuário remoto', + 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Os usuários remotos não conservam as suas senhas no banco de dados Kanboard, exemplos: contas LDAP, Github ou Google.', + 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Se você marcar "Interdir o formulário de autenticação", os identificadores entrados no formulário de login serão ignorado.', + 'By @%s on Gitlab' => 'Por @%s no Gitlab', + 'Gitlab issue comment created' => 'Comentário criado em um bilhete Gitlab', + 'New remote user' => 'Criar um usuário remoto', + 'New local user' => 'Criar um usuário local', + 'Default task color' => 'Cor padrão para as tarefas', + 'Hide sidebar' => 'Esconder a barra lateral', + 'Expand sidebar' => 'Expandir a barra lateral', + 'This feature does not work with all browsers.' => 'Esta funcionalidade não é compatível com todos os navegadores', + 'There is no destination project available.' => 'Não há nenhum projeto de destino disponível.', + 'Trigger automatically subtask time tracking' => 'Ativar automaticamente o monitoramento do tempo para as subtarefas', + 'Include closed tasks in the cumulative flow diagram' => 'Incluir as tarefas fechadas no diagrama de fluxo acumulado', + 'Current swimlane: %s' => 'Swimlane actual: %s', + 'Current column: %s' => 'Coluna actual: %s', + 'Current category: %s' => 'Categoria actual: %s', + 'no category' => 'nenhuma categoria', + 'Current assignee: %s' => 'Designado actual: %s', + 'not assigned' => 'não designado', + 'Author:' => 'Autor:', + 'contributors' => 'contribuidores', + 'License:' => 'Licença:', + 'License' => 'Licença', + 'Project Administrator' => 'Administrador de Projecto', + 'Enter the text below' => 'Entre o texto abaixo', + 'Gantt chart for %s' => 'Gráfico de Gantt para %s', + 'Sort by position' => 'Ordenar por Posição', + 'Sort by date' => 'Ordenar por data', + 'Add task' => 'Adicionar uma tarefa', + 'Start date:' => 'Data de início:', + 'Due date:' => 'Data de expiração:', + 'There is no start date or due date for this task.' => 'Não existe data de inicio ou data de expiração para esta tarefa.', + 'Moving or resizing a task will change the start and due date of the task.' => 'Mover ou redimensionar uma tarefa irá alterar a data de inicio e expiração da tarefa.', + 'There is no task in your project.' => 'Não há nenhuma tarefa no seu projeto.', + 'Gantt chart' => 'Gráfico de Gantt', + 'People who are project managers' => 'Pessoas que são gerente de projeto', + 'People who are project members' => 'Pessoas que são membro de projeto', + 'NOK - Norwegian Krone' => 'NOK - Coroa Norueguesa', + 'Show this column' => 'Mostrar esta coluna', + 'Hide this column' => 'Esconder esta coluna', + 'open file' => 'abrir um arquivo', + 'End date' => 'Data de término', + 'Users overview' => 'Visão geral dos usuários', + 'Managers' => 'Gerentes', + 'Members' => 'Membros', + 'Shared project' => 'Projeto compartilhado', + 'Project managers' => 'Gerentes de projeto', + 'Project members' => 'Membros de projeto', + 'Gantt chart for all projects' => 'Gráfico de Gantt para todos os projetos', + 'Projects list' => 'Lista dos projetos', + 'Gantt chart for this project' => 'Gráfico de Gantt para este projecto', + 'Project board' => 'Painel do projeto', + 'End date:' => 'Data de término:', + 'There is no start date or end date for this project.' => 'Não há data de início ou data de término para este projeto.', + 'Projects Gantt chart' => 'Gráfico de Gantt dos projetos', + 'Start date: %s' => 'Data de início: %s', + 'End date: %s' => 'Data de término: %s', + 'Link type' => 'Tipo de link', + 'Change task color when using a specific task link' => 'Mudar a cor da tarefa quando um link específico é utilizado', + 'Task link creation or modification' => 'Criação ou modificação de um link em uma tarefa', + 'Login with my Gitlab Account' => 'Login com a minha conta Gitlab', + 'Milestone' => 'Milestone', + 'Gitlab Authentication' => 'Autenticação Gitlab', + 'Help on Gitlab authentication' => 'Ajuda com a autenticação Gitlab', + 'Gitlab Id' => 'Gitlab Id', + 'Gitlab Account' => 'Conta Gitlab', + 'Link my Gitlab Account' => 'Vincular minha conta Gitlab', + 'Unlink my Gitlab Account' => 'Desvincular minha conta Gitlab', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/ru_RU/translations.php b/sources/app/Locale/ru_RU/translations.php index bc02e35..feb1b68 100644 --- a/sources/app/Locale/ru_RU/translations.php +++ b/sources/app/Locale/ru_RU/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/sr_Latn_RS/translations.php b/sources/app/Locale/sr_Latn_RS/translations.php index b6b4ca1..0bc5c24 100644 --- a/sources/app/Locale/sr_Latn_RS/translations.php +++ b/sources/app/Locale/sr_Latn_RS/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/sv_SE/translations.php b/sources/app/Locale/sv_SE/translations.php index fd29872..9c76972 100644 --- a/sources/app/Locale/sv_SE/translations.php +++ b/sources/app/Locale/sv_SE/translations.php @@ -263,10 +263,10 @@ return array( '%d comments' => '%d kommentarer', '%d comment' => '%d kommentar', 'Email address invalid' => 'Epost-adressen ogiltig', - // 'Your external account is not linked anymore to your profile.' => '', - // 'Unable to unlink your external account.' => '', - // 'External authentication failed' => '', - // 'Your external account is linked to your profile successfully.' => '', + 'Your external account is not linked anymore to your profile.' => 'Ditt externa konto är inte längre länkad till din profil.', + 'Unable to unlink your external account.' => 'Kunde inte koppla från ditt externa konto.', + 'External authentication failed' => 'Extern autentisering misslyckades', + 'Your external account is linked to your profile successfully.' => 'Ditt externa konto länkades till din profil.', 'Email' => 'Epost', 'Link my Google Account' => 'Länka till mitt Google-konto', 'Unlink my Google Account' => 'Ta bort länken till mitt Google-konto', @@ -791,7 +791,7 @@ return array( 'Help on Postmark integration' => 'Hjälp för Postmark integration', 'Mailgun (incoming emails)' => 'Mailgrun (inkommande e-post)', 'Help on Mailgun integration' => 'Hjälp för Mailgrun integration', - // 'Sendgrid (incoming emails)' => '', + 'Sendgrid (incoming emails)' => 'Sendgrid (inkommande e-post)', 'Help on Sendgrid integration' => 'Hjälp för Sendgrid integration', 'Disable two factor authentication' => 'Inaktivera två-faktors autentisering', 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Vill du verkligen inaktivera två-faktors autentisering för denna användare: "%s"?', @@ -963,56 +963,108 @@ return array( 'Search by category: ' => 'Sök efter kategori:', 'Search by description: ' => 'Sök efter beskrivning', 'Search by due date: ' => 'Sök efter förfallodatum', - // 'Lead and Cycle time for "%s"' => '', - // 'Average time spent into each column for "%s"' => '', - // 'Average time spent into each column' => '', - // 'Average time spent' => '', - // 'This chart show the average time spent into each column for the last %d tasks.' => '', - // 'Average Lead and Cycle time' => '', - // 'Average lead time: ' => '', - // 'Average cycle time: ' => '', - // 'Cycle Time' => '', - // 'Lead Time' => '', - // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '', - // 'Average time into each column' => '', - // 'Lead and cycle time' => '', - // 'Google Authentication' => '', - // 'Help on Google authentication' => '', - // 'Github Authentication' => '', - // 'Help on Github authentication' => '', - // 'Channel/Group/User (Optional)' => '', - // 'Lead time: ' => '', - // 'Cycle time: ' => '', - // 'Time spent into each column' => '', - // 'The lead time is the duration between the task creation and the completion.' => '', - // 'The cycle time is the duration between the start date and the completion.' => '', - // 'If the task is not closed the current time is used instead of the completion date.' => '', - // 'Set automatically the start date' => '', - // 'Edit Authentication' => '', - // 'Google Id' => '', - // 'Github Id' => '', - // 'Remote user' => '', - // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '', - // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', - // 'By @%s on Gitlab' => '', - // 'Gitlab issue comment created' => '', - // 'New remote user' => '', - // 'New local user' => '', - // 'Default task color' => '', - // 'Hide sidebar' => '', - // 'Expand sidebar' => '', - // 'This feature does not work with all browsers.' => '', - // 'There is no destination project available.' => '', - // 'Trigger automatically subtask time tracking' => '', - // 'Include closed tasks in the cumulative flow diagram' => '', - // 'Current swimlane: %s' => '', - // 'Current column: %s' => '', - // 'Current category: %s' => '', - // 'no category' => '', - // 'Current assignee: %s' => '', - // 'not assigned' => '', - // 'Author:' => '', - // 'contributors' => '', - // 'License:' => '', - // 'License' => '', + 'Lead and Cycle time for "%s"' => 'Led- och cykeltid för "%s"', + 'Average time spent into each column for "%s"' => 'Medeltidsåtgång i varje kolumn för "%s"', + 'Average time spent into each column' => 'Medeltidsåtgång i varje kolumn', + 'Average time spent' => 'Medeltidsåtgång', + 'This chart show the average time spent into each column for the last %d tasks.' => 'Diagramet visar medeltidsåtgång i varje kolumn för de senaste %d uppgifterna.', + 'Average Lead and Cycle time' => 'Medel av led och cykeltid', + 'Average lead time: ' => 'Medel av ledtid', + 'Average cycle time: ' => 'Medel av cykeltid', + 'Cycle Time' => 'Cykeltid', + 'Lead Time' => 'Ledtid', + 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Diagramet visar medel av led och cykeltid för de senaste %d uppgifterna över tiden.', + 'Average time into each column' => 'Medeltidsåtgång i varje kolumn', + 'Lead and cycle time' => 'Led och cykeltid', + 'Google Authentication' => 'Google autentisering', + 'Help on Google authentication' => 'Hjälp för Google autentisering', + 'Github Authentication' => 'Github autentisering', + 'Help on Github authentication' => 'Hjälp för Github autentisering', + 'Channel/Group/User (Optional)' => 'Kanal/Grupp/Användare (valfri)', + 'Lead time: ' => 'Ledtid', + 'Cycle time: ' => 'Cykeltid', + 'Time spent into each column' => 'Tidsåtgång per kolumn', + 'The lead time is the duration between the task creation and the completion.' => 'Ledtiden är varaktigheten mellan uppgiftens skapande och slutförande.', + 'The cycle time is the duration between the start date and the completion.' => 'Cykeltiden är varaktigheten mellan uppgiftens startdatum och slut.', + 'If the task is not closed the current time is used instead of the completion date.' => 'Om uppgiften inte är stängd används nuvarande tid istället för slutförandedatum.', + 'Set automatically the start date' => 'Sätt startdatum automatiskt', + 'Edit Authentication' => 'Ändra autentisering', + 'Google Id' => 'Google Id', + 'Github Id' => 'Github Id', + 'Remote user' => 'Extern användare', + 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Externa användares lösenord lagras inte i Kanboard-databasen, exempel: LDAP, Google och Github-konton.', + 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Om du aktiverar boxen "Tillåt inte loginformulär" kommer inloggningsuppgifter i formuläret att ignoreras.', + 'By @%s on Gitlab' => 'Av @%s på Gitlab', + 'Gitlab issue comment created' => 'Gitlab frågekommentar skapad', + 'New remote user' => 'Ny extern användare', + 'New local user' => 'Ny lokal användare', + 'Default task color' => 'Standardfärg för uppgifter', + 'Hide sidebar' => 'Göm sidokolumn', + 'Expand sidebar' => 'Expandera sidokolumn', + 'This feature does not work with all browsers.' => 'Denna funktion fungerar inte i alla webbläsare.', + 'There is no destination project available.' => 'Det finns inget destinationsprojekt tillgängligt.', + 'Trigger automatically subtask time tracking' => 'Aktivera automatisk tidsbevakning av deluppgifter', + 'Include closed tasks in the cumulative flow diagram' => 'Inkludera stängda uppgifter i digrammet med kumulativt flöde', + 'Current swimlane: %s' => 'Nuvarande swimlane: %s', + 'Current column: %s' => 'Nuvarande kolumn: %s', + 'Current category: %s' => 'Nuvarande kategori: %s', + 'no category' => 'ingen kategori', + 'Current assignee: %s' => 'Nuvarande tilldelning: %s', + 'not assigned' => 'inte tilldelad', + 'Author:' => 'Upphovsman:', + 'contributors' => 'bidragare:', + 'License:' => 'Licens:', + 'License' => 'Licens', + 'Project Administrator' => 'Projektadministratör', + 'Enter the text below' => 'Fyll i texten nedan', + 'Gantt chart for %s' => 'Gantt-schema för %s', + 'Sort by position' => 'Sortera efter position', + 'Sort by date' => 'Sortera efter datum', + 'Add task' => 'Lägg till uppgift', + 'Start date:' => 'Startdatum:', + 'Due date:' => 'Slutdatum:', + 'There is no start date or due date for this task.' => 'Det finns inget startdatum eller slutdatum för uppgiften.', + 'Moving or resizing a task will change the start and due date of the task.' => 'Flytt eller storleksändring av uppgiften ändrar start och slutdatum för uppgiften', + 'There is no task in your project.' => 'Det finns ingen uppgift i ditt projekt.', + 'Gantt chart' => 'Gantt-schema', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/th_TH/translations.php b/sources/app/Locale/th_TH/translations.php index 28e4037..a5ed247 100644 --- a/sources/app/Locale/th_TH/translations.php +++ b/sources/app/Locale/th_TH/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/tr_TR/translations.php b/sources/app/Locale/tr_TR/translations.php index a014dfc..9eb5c41 100644 --- a/sources/app/Locale/tr_TR/translations.php +++ b/sources/app/Locale/tr_TR/translations.php @@ -1015,4 +1015,56 @@ return array( // 'contributors' => '', // 'License:' => '', // 'License' => '', + // 'Project Administrator' => '', + // 'Enter the text below' => '', + // 'Gantt chart for %s' => '', + // 'Sort by position' => '', + // 'Sort by date' => '', + // 'Add task' => '', + // 'Start date:' => '', + // 'Due date:' => '', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + // 'Gantt chart' => '', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + // 'End date' => '', + // 'Users overview' => '', + // 'Managers' => '', + // 'Members' => '', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Locale/zh_CN/translations.php b/sources/app/Locale/zh_CN/translations.php index 71c89d9..910bc0b 100644 --- a/sources/app/Locale/zh_CN/translations.php +++ b/sources/app/Locale/zh_CN/translations.php @@ -773,14 +773,14 @@ return array( 'Secret key: ' => '密码:', 'Test your device' => '测试设备', 'Assign a color when the task is moved to a specific column' => '任务移动到指定栏目时设置颜色', - // '%s via Kanboard' => '', - // 'uploaded by: %s' => '', + '%s via Kanboard' => '%s 通过KanBoard', + 'uploaded by: %s' => '由: %s 上传', // 'uploaded on: %s' => '', // 'size: %s' => '', // 'Burndown chart for "%s"' => '', // 'Burndown chart' => '', // 'This chart show the task complexity over the time (Work Remaining).' => '', - // 'Screenshot taken %s' => '', + 'Screenshot taken %s' => '已截图 %s', // 'Add a screenshot' => '', // 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '', // 'Screenshot uploaded successfully.' => '', @@ -795,7 +795,7 @@ return array( // 'Help on Sendgrid integration' => '', // 'Disable two factor authentication' => '', // 'Do you really want to disable the two factor authentication for this user: "%s"?' => '', - // 'Edit link' => '', + 'Edit link' => '编辑链接', // 'Start to type task title...' => '', // 'A task cannot be linked to itself' => '', // 'The exact same link already exists' => '', @@ -832,28 +832,28 @@ return array( // 'XMPP server address' => '', // 'Jabber domain' => '', // 'Jabber nickname' => '', - // 'Multi-user chat room' => '', + 'Multi-user chat room' => '多用户聊天室', // 'Help on Jabber integration' => '', // 'The server address must use this format: "tcp://hostname:5222"' => '', - // 'Calendar settings' => '', + 'Calendar settings' => '日程设置', // 'Project calendar view' => '', - // 'Project settings' => '', + 'Project settings' => '项目设置', // 'Show subtasks based on the time tracking' => '', // 'Show tasks based on the creation date' => '', // 'Show tasks based on the start date' => '', // 'Subtasks time tracking' => '', - // 'User calendar view' => '', - // 'Automatically update the start date' => '', + 'User calendar view' => '用户日程视图', + 'Automatically update the start date' => '自动更新开始日期', // 'iCal feed' => '', - // 'Preferences' => '', - // 'Security' => '', + 'Preferences' => '偏好', + 'Security' => '安全', // 'Two factor authentication disabled' => '', // 'Two factor authentication enabled' => '', // 'Unable to update this user.' => '', // 'There is no user management for private projects.' => '', // 'User that will receive the email' => '', - // 'Email subject' => '', - // 'Date' => '', + 'Email subject' => '邮件主题', + 'Date' => '日期', // 'By @%s on Bitbucket' => '', // 'Bitbucket Issue' => '', // 'Commit made by @%s on Bitbucket' => '', @@ -863,7 +863,7 @@ return array( // 'Add a comment log when moving the task between columns' => '', // 'Move the task to another column when the category is changed' => '', // 'Send a task by email to someone' => '', - // 'Reopen a task' => '', + 'Reopen a task' => '重新开始一个任务', // 'Bitbucket issue opened' => '', // 'Bitbucket issue closed' => '', // 'Bitbucket issue reopened' => '', @@ -874,12 +874,12 @@ return array( // 'Swimlane change' => '', // 'Assignee change' => '', // '[%s] Overdue tasks' => '', - // 'Notification' => '', + 'Notification' => '通知', // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', + 'Budget overview' => '预算概览', + 'Type' => '类型', // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', @@ -924,42 +924,42 @@ return array( // 'You need at least 2 days of data to show the chart.' => '', // '<15m' => '', // '<30m' => '', - // 'Stop timer' => '', - // 'Start timer' => '', - // 'Add project member' => '', - // 'Enable notifications' => '', - // 'My activity stream' => '', - // 'My calendar' => '', - // 'Search tasks' => '', - // 'Back to the calendar' => '', - // 'Filters' => '', - // 'Reset filters' => '', - // 'My tasks due tomorrow' => '', - // 'Tasks due today' => '', - // 'Tasks due tomorrow' => '', - // 'Tasks due yesterday' => '', - // 'Closed tasks' => '', - // 'Open tasks' => '', - // 'Not assigned' => '', - // 'View advanced search syntax' => '', - // 'Overview' => '', + 'Stop timer' => '停止定时器', + 'Start timer' => '开启定时器', + 'Add project member' => '添加项目成员', + 'Enable notifications' => '打开通知', + 'My activity stream' => '我的活动流', + 'My calendar' => '我的日程表', + 'Search tasks' => '搜索任务', + 'Back to the calendar' => '返回日程', + 'Filters' => '过滤器', + 'Reset filters' => '重置过滤器', + 'My tasks due tomorrow' => '我的明天到期的任务', + 'Tasks due today' => '今天到期的任务', + 'Tasks due tomorrow' => '明天到期的任务', + 'Tasks due yesterday' => '昨天到期的任务', + 'Closed tasks' => '已关闭任务', + 'Open tasks' => '打开的任务', + 'Not assigned' => '未指派', + 'View advanced search syntax' => '查看高级搜索语法', + 'Overview' => '概览', // '%b %e %Y' => '', - // 'Board/Calendar/List view' => '', - // 'Switch to the board view' => '', - // 'Switch to the calendar view' => '', - // 'Switch to the list view' => '', - // 'Go to the search/filter box' => '', - // 'There is no activity yet.' => '', - // 'No tasks found.' => '', - // 'Keyboard shortcut: "%s"' => '', - // 'List' => '', - // 'Filter' => '', - // 'Advanced search' => '', - // 'Example of query: ' => '', - // 'Search by project: ' => '', - // 'Search by column: ' => '', - // 'Search by assignee: ' => '', - // 'Search by color: ' => '', + 'Board/Calendar/List view' => '看板/日程/列表视图', + 'Switch to the board view' => '切换到看板视图', + 'Switch to the calendar view' => '切换到日程视图', + 'Switch to the list view' => '切换到列表视图', + 'Go to the search/filter box' => '前往搜索/过滤箱', + 'There is no activity yet.' => '目前无任何活动.', + 'No tasks found.' => '没有找人任何任务.', + 'Keyboard shortcut: "%s"' => '快捷键: "%s"', + 'List' => '列表', + 'Filter' => '过滤器', + 'Advanced search' => '高级搜索', + 'Example of query: ' => '查询示例: ', + 'Search by project: ' => '按项目搜索: ', + 'Search by column: ' => '按列搜索: ', + 'Search by assignee: ' => '按被指派人搜索: ', + 'Search by color: ' => '按颜色搜索: ', // 'Search by category: ' => '', // 'Search by description: ' => '', // 'Search by due date: ' => '', @@ -998,21 +998,73 @@ return array( // 'Gitlab issue comment created' => '', // 'New remote user' => '', // 'New local user' => '', - // 'Default task color' => '', + 'Default task color' => '默认任务颜色', // 'Hide sidebar' => '', // 'Expand sidebar' => '', // 'This feature does not work with all browsers.' => '', // 'There is no destination project available.' => '', - // 'Trigger automatically subtask time tracking' => '', - // 'Include closed tasks in the cumulative flow diagram' => '', + 'Trigger automatically subtask time tracking' => '自动跟踪子任务时间', + 'Include closed tasks in the cumulative flow diagram' => '在累计流程图中包含已关闭任务', // 'Current swimlane: %s' => '', // 'Current column: %s' => '', // 'Current category: %s' => '', - // 'no category' => '', - // 'Current assignee: %s' => '', - // 'not assigned' => '', - // 'Author:' => '', - // 'contributors' => '', - // 'License:' => '', - // 'License' => '', + 'no category' => '无分类', + 'Current assignee: %s' => '当前被指派人: %s', + 'not assigned' => '未指派', + 'Author:' => '作者', + 'contributors' => '贡献者', + 'License:' => '授权许可:', + 'License' => '授权许可', + 'Project Administrator' => '项目管理者', + 'Enter the text below' => '输入下方的文本', + 'Gantt chart for %s' => '%s的甘特图', + 'Sort by position' => '按位置排序', + 'Sort by date' => '按日期排序', + 'Add task' => '添加任务', + 'Start date:' => '开始日期', + 'Due date:' => '到期日期', + // 'There is no start date or due date for this task.' => '', + // 'Moving or resizing a task will change the start and due date of the task.' => '', + // 'There is no task in your project.' => '', + 'Gantt chart' => '甘特图', + // 'People who are project managers' => '', + // 'People who are project members' => '', + // 'NOK - Norwegian Krone' => '', + // 'Show this column' => '', + // 'Hide this column' => '', + // 'open file' => '', + 'End date' => '结束日期', + 'Users overview' => '用户概览', + // 'Managers' => '', + 'Members' => '成员', + // 'Shared project' => '', + // 'Project managers' => '', + // 'Project members' => '', + // 'Gantt chart for all projects' => '', + // 'Projects list' => '', + // 'Gantt chart for this project' => '', + // 'Project board' => '', + // 'End date:' => '', + // 'There is no start date or end date for this project.' => '', + // 'Projects Gantt chart' => '', + // 'Start date: %s' => '', + // 'End date: %s' => '', + // 'Link type' => '', + // 'Change task color when using a specific task link' => '', + // 'Task link creation or modification' => '', + // 'Login with my Gitlab Account' => '', + // 'Milestone' => '', + // 'Gitlab Authentication' => '', + // 'Help on Gitlab authentication' => '', + // 'Gitlab Id' => '', + // 'Gitlab Account' => '', + // 'Link my Gitlab Account' => '', + // 'Unlink my Gitlab Account' => '', + // 'Documentation: %s' => '', + // 'Switch to the Gantt chart view' => '', + // 'Reset the search/filter box' => '', + // 'Documentation' => '', + // 'Table of contents' => '', + // 'Gantt' => '', + // 'Help with project permissions' => '', ); diff --git a/sources/app/Model/Acl.php b/sources/app/Model/Acl.php index 95056de..8c28cb1 100644 --- a/sources/app/Model/Acl.php +++ b/sources/app/Model/Acl.php @@ -17,13 +17,13 @@ class Acl extends Base * @var array */ private $public_acl = array( - 'auth' => array('login', 'check'), + 'auth' => array('login', 'check', 'captcha'), 'task' => array('readonly'), 'board' => array('readonly'), 'webhook' => '*', 'ical' => '*', 'feed' => '*', - 'oauth' => array('google', 'github'), + 'oauth' => array('google', 'github', 'gitlab'), ); /** @@ -32,7 +32,7 @@ class Acl extends Base * @access private * @var array */ - private $member_acl = array( + private $project_member_acl = array( 'board' => '*', 'comment' => '*', 'file' => '*', @@ -56,15 +56,28 @@ class Acl extends Base * @access private * @var array */ - private $manager_acl = array( + private $project_manager_acl = array( 'action' => '*', 'analytic' => '*', 'category' => '*', 'column' => '*', - 'export' => array('tasks', 'subtasks', 'summary'), + 'export' => '*', 'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'), 'swimlane' => '*', 'budget' => '*', + 'gantt' => array('project', 'savetaskdate', 'task', 'savetask'), + ); + + /** + * Controllers and actions for project admins + * + * @access private + * @var array + */ + private $project_admin_acl = array( + 'project' => array('remove'), + 'projectuser' => '*', + 'gantt' => array('projects', 'saveprojectdate'), ); /** @@ -77,8 +90,6 @@ class Acl extends Base 'user' => array('index', 'create', 'save', 'remove', 'authentication'), 'config' => '*', 'link' => '*', - 'project' => array('remove'), - 'hourlyrate' => '*', 'currency' => '*', 'twofactor' => array('disable'), ); @@ -149,9 +160,22 @@ class Acl extends Base * @param string $action Action name * @return bool */ - public function isManagerAction($controller, $action) + public function isProjectManagerAction($controller, $action) { - return $this->matchAcl($this->manager_acl, $controller, $action); + return $this->matchAcl($this->project_manager_acl, $controller, $action); + } + + /** + * Return true if the given action is for application managers + * + * @access public + * @param string $controller Controller name + * @param string $action Action name + * @return bool + */ + public function isProjectAdminAction($controller, $action) + { + return $this->matchAcl($this->project_admin_acl, $controller, $action); } /** @@ -162,9 +186,9 @@ class Acl extends Base * @param string $action Action name * @return bool */ - public function isMemberAction($controller, $action) + public function isProjectMemberAction($controller, $action) { - return $this->matchAcl($this->member_acl, $controller, $action); + return $this->matchAcl($this->project_member_acl, $controller, $action); } /** @@ -189,13 +213,18 @@ class Acl extends Base return false; } + // Check project admin permissions + if ($this->isProjectAdminAction($controller, $action)) { + return $this->handleProjectAdminPermissions($project_id); + } + // Check project manager permissions - if ($this->isManagerAction($controller, $action)) { - return $this->isManagerActionAllowed($project_id); + if ($this->isProjectManagerAction($controller, $action)) { + return $this->handleProjectManagerPermissions($project_id); } // Check project member permissions - if ($this->isMemberAction($controller, $action)) { + if ($this->isProjectMemberAction($controller, $action)) { return $project_id > 0 && $this->projectPermission->isMember($project_id, $this->userSession->getId()); } @@ -203,12 +232,43 @@ class Acl extends Base return true; } - public function isManagerActionAllowed($project_id) + /** + * Handle permission for project manager + * + * @access public + * @param integer $project_id + * @return boolean + */ + public function handleProjectManagerPermissions($project_id) { - if ($this->userSession->isAdmin()) { - return true; + if ($project_id > 0) { + if ($this->userSession->isProjectAdmin()) { + return $this->projectPermission->isMember($project_id, $this->userSession->getId()); + } + + return $this->projectPermission->isManager($project_id, $this->userSession->getId()); } - return $project_id > 0 && $this->projectPermission->isManager($project_id, $this->userSession->getId()); + return false; + } + + /** + * Handle permission for project admins + * + * @access public + * @param integer $project_id + * @return boolean + */ + public function handleProjectAdminPermissions($project_id) + { + if (! $this->userSession->isProjectAdmin()) { + return false; + } + + if ($project_id > 0) { + return $this->projectPermission->isMember($project_id, $this->userSession->getId()); + } + + return true; } } diff --git a/sources/app/Model/Action.php b/sources/app/Model/Action.php index 3759653..87058cc 100644 --- a/sources/app/Model/Action.php +++ b/sources/app/Model/Action.php @@ -59,6 +59,7 @@ class Action extends Base 'TaskUpdateStartDate' => t('Automatically update the start date'), 'TaskMoveColumnCategoryChange' => t('Move the task to another column when the category is changed'), 'TaskEmail' => t('Send a task by email to someone'), + 'TaskAssignColorLink' => t('Change task color when using a specific task link'), ); asort($values); @@ -75,6 +76,7 @@ class Action extends Base public function getAvailableEvents() { $values = array( + TaskLink::EVENT_CREATE_UPDATE => t('Task link creation or modification'), Task::EVENT_MOVE_COLUMN => t('Move a task to another column'), Task::EVENT_UPDATE => t('Task modification'), Task::EVENT_CREATE => t('Task creation'), diff --git a/sources/app/Model/Authentication.php b/sources/app/Model/Authentication.php index 31969b5..93a463f 100644 --- a/sources/app/Model/Authentication.php +++ b/sources/app/Model/Authentication.php @@ -5,6 +5,7 @@ namespace Model; use Core\Request; use SimpleValidator\Validator; use SimpleValidator\Validators; +use Gregwar\Captcha\CaptchaBuilder; /** * Authentication model @@ -53,7 +54,7 @@ class Authentication extends Base } // We try first with the RememberMe cookie - if ($this->backend('rememberMe')->authenticate()) { + if (REMEMBER_ME_AUTH && $this->backend('rememberMe')->authenticate()) { return true; } @@ -75,17 +76,51 @@ class Authentication extends Base */ public function authenticate($username, $password) { - // Try first the database auth and then LDAP if activated - if ($this->backend('database')->authenticate($username, $password)) { + if ($this->user->isLocked($username)) { + $this->container['logger']->error('Account locked: '.$username); + return false; + } + else if ($this->backend('database')->authenticate($username, $password)) { + $this->user->resetFailedLogin($username); return true; } else if (LDAP_AUTH && $this->backend('ldap')->authenticate($username, $password)) { + $this->user->resetFailedLogin($username); return true; } + $this->handleFailedLogin($username); return false; } + /** + * Return true if the captcha must be shown + * + * @access public + * @param string $username + * @return boolean + */ + public function hasCaptcha($username) + { + return $this->user->getFailedLogin($username) >= BRUTEFORCE_CAPTCHA; + } + + /** + * Handle failed login + * + * @access public + * @param string $username + */ + public function handleFailedLogin($username) + { + $this->user->incrementFailedLogin($username); + + if ($this->user->getFailedLogin($username) >= BRUTEFORCE_LOCKDOWN) { + $this->container['logger']->critical('Locking account: '.$username); + $this->user->lock($username, BRUTEFORCE_LOCKDOWN_DURATION); + } + } + /** * Validate user login form * @@ -95,27 +130,12 @@ class Authentication extends Base */ public function validateForm(array $values) { - $v = new Validator($values, array( - new Validators\Required('username', t('The username is required')), - new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), - new Validators\Required('password', t('The password is required')), - )); - - $result = $v->execute(); - $errors = $v->getErrors(); + list($result, $errors) = $this->validateFormCredentials($values); if ($result) { - if ($this->authenticate($values['username'], $values['password'])) { - - // Setup the remember me feature - if (! empty($values['remember_me'])) { - - $credentials = $this->backend('rememberMe') - ->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent()); - - $this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']); - } + if ($this->validateFormCaptcha($values) && $this->authenticate($values['username'], $values['password'])) { + $this->createRememberMeSession($values); } else { $result = false; @@ -123,9 +143,62 @@ class Authentication extends Base } } + return array($result, $errors); + } + + /** + * Validate credentials syntax + * + * @access public + * @param array $values Form values + * @return array $valid, $errors [0] = Success or not, [1] = List of errors + */ + public function validateFormCredentials(array $values) + { + $v = new Validator($values, array( + new Validators\Required('username', t('The username is required')), + new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), + new Validators\Required('password', t('The password is required')), + )); + return array( - $result, - $errors + $v->execute(), + $v->getErrors(), ); } + + /** + * Validate captcha + * + * @access public + * @param array $values Form values + * @return boolean + */ + public function validateFormCaptcha(array $values) + { + if ($this->hasCaptcha($values['username'])) { + $builder = new CaptchaBuilder; + $builder->setPhrase($this->session['captcha']); + return $builder->testPhrase(isset($values['captcha']) ? $values['captcha'] : ''); + } + + return true; + } + + /** + * Create remember me session if necessary + * + * @access private + * @param array $values Form values + */ + private function createRememberMeSession(array $values) + { + if (REMEMBER_ME_AUTH && ! empty($values['remember_me'])) { + + $credentials = $this->backend('rememberMe') + ->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent()); + + $this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']); + } + } } diff --git a/sources/app/Model/Color.php b/sources/app/Model/Color.php index 73e5d62..6df7beb 100644 --- a/sources/app/Model/Color.php +++ b/sources/app/Model/Color.php @@ -122,6 +122,22 @@ class Color extends Base return ''; } + /** + * Get color properties + * + * @access public + * @param string $color_id + * @return array + */ + public function getColorProperties($color_id) + { + if (isset($this->default_colors[$color_id])) { + return $this->default_colors[$color_id]; + } + + return $this->default_colors[$this->getDefaultColor()]; + } + /** * Get available colors * @@ -150,6 +166,17 @@ class Color extends Base return $this->config->get('default_color', 'yellow'); } + /** + * Get the default colors + * + * @access public + * @return array + */ + public function getDefaultColors() + { + return $this->default_colors; + } + /** * Get Bordercolor from string * @@ -159,11 +186,8 @@ class Color extends Base */ public function getBorderColor($color_id) { - if (isset($this->default_colors[$color_id])) { - return $this->default_colors[$color_id]['border']; - } - - return $this->default_colors[$this->getDefaultColor()]['border']; + $color = $this->getColorProperties($color_id); + return $color['border']; } /** @@ -175,11 +199,8 @@ class Color extends Base */ public function getBackgroundColor($color_id) { - if (isset($this->default_colors[$color_id])) { - return $this->default_colors[$color_id]['background']; - } - - return $this->default_colors[$this->getDefaultColor()]['background']; + $color = $this->getColorProperties($color_id); + return $color['background']; } /** diff --git a/sources/app/Model/Config.php b/sources/app/Model/Config.php index c5bb9e9..6fa98f9 100644 --- a/sources/app/Model/Config.php +++ b/sources/app/Model/Config.php @@ -41,6 +41,7 @@ class Config extends Base 'JPY' => t('JPY - Japanese Yen'), 'RSD' => t('RSD - Serbian dinar'), 'SEK' => t('SEK - Swedish Krona'), + 'NOK' => t('NOK - Norwegian Krone'), ); } @@ -83,7 +84,9 @@ class Config extends Base 'it_IT' => 'Italiano', 'hu_HU' => 'Magyar', 'nl_NL' => 'Nederlands', + 'nb_NO' => 'Norsk', 'pl_PL' => 'Polski', + 'pt_PT' => 'Português', 'pt_BR' => 'Português (Brasil)', 'ru_RU' => 'Русский', 'sr_Latn_RS' => 'Srpski', @@ -120,7 +123,9 @@ class Config extends Base 'it_IT' => 'it', 'hu_HU' => 'hu', 'nl_NL' => 'nl', + 'nb_NO' => 'nb', 'pl_PL' => 'pl', + 'pt_PT' => 'pt', 'pt_BR' => 'pt-br', 'ru_RU' => 'ru', 'sr_Latn_RS' => 'sr', diff --git a/sources/app/Model/DateParser.php b/sources/app/Model/DateParser.php index 036725e..002fc03 100644 --- a/sources/app/Model/DateParser.php +++ b/sources/app/Model/DateParser.php @@ -77,7 +77,7 @@ class DateParser extends Base } /** - * Parse a date ad return a unix timestamp, try different date formats + * Parse a date and return a unix timestamp, try different date formats * * @access public * @param string $value Date to parse @@ -96,6 +96,18 @@ class DateParser extends Base return 0; } + /** + * Get ISO8601 date from user input + * + * @access public + * @param string $value Date to parse + * @return string + */ + public function getIsoDate($value) + { + return date('Y-m-d', ctype_digit($value) ? $value : $this->getTimestamp($value)); + } + /** * Get all combinations of date/time formats * @@ -157,6 +169,7 @@ class DateParser extends Base 'm/d/Y' => date('m/d/Y'), 'd/m/Y' => date('d/m/Y'), 'Y/m/d' => date('Y/m/d'), + 'd.m.Y' => date('d.m.Y'), ); } diff --git a/sources/app/Model/File.php b/sources/app/Model/File.php index 3a44fee..f884e46 100644 --- a/sources/app/Model/File.php +++ b/sources/app/Model/File.php @@ -228,7 +228,7 @@ class File extends Base if ($error == UPLOAD_ERR_OK && $_FILES[$form_name]['size'][$key] > 0) { - $original_filename = basename($_FILES[$form_name]['name'][$key]); + $original_filename = $_FILES[$form_name]['name'][$key]; $uploaded_filename = $_FILES[$form_name]['tmp_name'][$key]; $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); diff --git a/sources/app/Model/Project.php b/sources/app/Model/Project.php index 3c864e5..5250082 100644 --- a/sources/app/Model/Project.php +++ b/sources/app/Model/Project.php @@ -114,6 +114,54 @@ class Project extends Base return $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->exists(); } + /** + * Get all projects to generate the Gantt chart + * + * @access public + * @param array $project_ids + * @return array + */ + public function getGanttBars(array $project_ids) + { + if (empty($project_ids)) { + return array(); + } + + $colors = $this->color->getDefaultColors(); + $projects = $this->db->table(self::TABLE)->asc('start_date')->in('id', $project_ids)->eq('is_active', self::ACTIVE)->eq('is_private', 0)->findAll(); + $bars = array(); + + foreach ($projects as $project) { + $start = empty($project['start_date']) ? time() : strtotime($project['start_date']); + $end = empty($project['end_date']) ? $start : strtotime($project['end_date']); + $color = next($colors) ?: reset($colors); + + $bars[] = array( + 'type' => 'project', + 'id' => $project['id'], + 'title' => $project['name'], + 'start' => array( + (int) date('Y', $start), + (int) date('n', $start), + (int) date('j', $start), + ), + 'end' => array( + (int) date('Y', $end), + (int) date('n', $end), + (int) date('j', $end), + ), + 'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])), + 'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])), + 'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])), + 'color' => $color, + 'not_defined' => empty($project['start_date']) || empty($project['end_date']), + 'users' => $this->projectPermission->getProjectUsers($project['id']), + ); + } + + return $bars; + } + /** * Get all projects * @@ -260,6 +308,23 @@ class Project extends Base return $projects; } + /** + * Fetch more information for each project + * + * @access public + * @param array $projects + * @return array + */ + public function applyProjectDetails(array $projects) + { + foreach ($projects as &$project) { + $this->getColumnStats($project); + $project = array_merge($project, $this->projectPermission->getProjectUsers($project['id'])); + } + + return $projects; + } + /** * Get project summary for a list of project * @@ -279,6 +344,25 @@ class Project extends Base ->callback(array($this, 'applyColumnStats')); } + /** + * Get project details (users + columns) for a list of project + * + * @access public + * @param array $project_ids List of project id + * @return \PicoDb\Table + */ + public function getQueryProjectDetails(array $project_ids) + { + if (empty($project_ids)) { + return $this->db->table(Project::TABLE)->limit(0); + } + + return $this->db + ->table(Project::TABLE) + ->in('id', $project_ids) + ->callback(array($this, 'applyProjectDetails')); + } + /** * Create a project * @@ -472,6 +556,8 @@ class Project extends Base new Validators\Required('name', t('The project name is required')), new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50), new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50), + new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10), + new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10), new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) , new Validators\Unique('name', t('This project must be unique'), $this->db->getConnection(), self::TABLE), new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), self::TABLE), diff --git a/sources/app/Model/ProjectAnalytic.php b/sources/app/Model/ProjectAnalytic.php index 8ac2262..dbca4ee 100644 --- a/sources/app/Model/ProjectAnalytic.php +++ b/sources/app/Model/ProjectAnalytic.php @@ -167,8 +167,10 @@ class ProjectAnalytic extends Base $sums[$task['column_id']] += ($task['date_completed'] ?: time()) - $task['date_moved']; foreach ($sums as $column_id => $time_spent) { - $stats[$column_id]['count']++; - $stats[$column_id]['time_spent'] += $time_spent; + if (isset($stats[$column_id])) { + $stats[$column_id]['count']++; + $stats[$column_id]['time_spent'] += $time_spent; + } } } diff --git a/sources/app/Model/ProjectPermission.php b/sources/app/Model/ProjectPermission.php index bc752dd..c412b7a 100644 --- a/sources/app/Model/ProjectPermission.php +++ b/sources/app/Model/ProjectPermission.php @@ -49,6 +49,36 @@ class ProjectPermission extends Base return $allowed_users; } + /** + * Get a list of members and managers with a single SQL query + * + * @access public + * @param integer $project_id Project id + * @return array + */ + public function getProjectUsers($project_id) + { + $result = array( + 'managers' => array(), + 'members' => array(), + ); + + $users = $this->db + ->table(self::TABLE) + ->join(User::TABLE, 'id', 'user_id') + ->eq('project_id', $project_id) + ->asc('username') + ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', self::TABLE.'.is_owner') + ->findAll(); + + foreach ($users as $user) { + $key = $user['is_owner'] == 1 ? 'managers' : 'members'; + $result[$key][$user['id']] = $user['name'] ?: $user['username']; + } + + return $result; + } + /** * Get a list of allowed people for a project * @@ -65,26 +95,6 @@ class ProjectPermission extends Base return $this->getAssociatedUsers($project_id); } - /** - * Get a list of people associated to the project - * - * @access public - * @param integer $project_id Project id - * @return array - */ - public function getAssociatedUsers($project_id) - { - $users = $this->db - ->table(self::TABLE) - ->join(User::TABLE, 'id', 'user_id') - ->eq('project_id', $project_id) - ->asc('username') - ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name') - ->findAll(); - - return $this->user->prepareList($users); - } - /** * Get a list of owners for a project * @@ -106,6 +116,57 @@ class ProjectPermission extends Base return $this->user->prepareList($users); } + /** + * Get query for project users overview + * + * @access public + * @param array $project_ids + * @param integer $is_owner + * @return \PicoDb\Table + */ + public function getQueryByRole(array $project_ids, $is_owner = 0) + { + if (empty($project_ids)) { + $project_ids = array(-1); + } + + return $this + ->db + ->table(self::TABLE) + ->join(User::TABLE, 'id', 'user_id') + ->join(Project::TABLE, 'id', 'project_id') + ->eq(self::TABLE.'.is_owner', $is_owner) + ->eq(Project::TABLE.'.is_private', 0) + ->in(Project::TABLE.'.id', $project_ids) + ->columns( + User::TABLE.'.id', + User::TABLE.'.username', + User::TABLE.'.name', + Project::TABLE.'.name AS project_name', + Project::TABLE.'.id' + ); + } + + /** + * Get a list of people associated to the project + * + * @access public + * @param integer $project_id Project id + * @return array + */ + public function getAssociatedUsers($project_id) + { + $users = $this->db + ->table(self::TABLE) + ->join(User::TABLE, 'id', 'user_id') + ->eq('project_id', $project_id) + ->asc('username') + ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name') + ->findAll(); + + return $this->user->prepareList($users); + } + /** * Get allowed and not allowed users for a project * @@ -127,7 +188,6 @@ class ProjectPermission extends Base $users['managers'] = $this->getManagers($project_id); foreach ($all_users as $user_id => $username) { - if (! isset($users['allowed'][$user_id])) { $users['not_allowed'][$user_id] = $username; } @@ -269,26 +329,6 @@ class ProjectPermission extends Base ->exists(); } - /** - * Filter a list of projects for a given user - * - * @access public - * @param array $projects Project list: ['project_id' => 'project_name'] - * @param integer $user_id User id - * @param string $filter Method name to apply - * @return array - */ - public function filterProjects(array $projects, $user_id, $filter = 'isUserAllowed') - { - foreach ($projects as $project_id => $project_name) { - if (! $this->$filter($project_id, $user_id)) { - unset($projects[$project_id]); - } - } - - return $projects; - } - /** * Return a list of allowed active projects for a given user * diff --git a/sources/app/Model/SubtaskTimeTracking.php b/sources/app/Model/SubtaskTimeTracking.php index 9f17ee3..997031e 100644 --- a/sources/app/Model/SubtaskTimeTracking.php +++ b/sources/app/Model/SubtaskTimeTracking.php @@ -301,7 +301,6 @@ class SubtaskTimeTracking extends Base ->findOneColumn('start'); if ($start_time) { - $start = new DateTime; $start->setTimestamp($start_time); @@ -341,18 +340,24 @@ class SubtaskTimeTracking extends Base public function updateTaskTimeTracking($task_id) { $result = $this->calculateSubtaskTime($task_id); + $values = array(); - if (empty($result['total_spent']) && empty($result['total_estimated'])) { + if ($result['total_spent'] > 0) { + $values['time_spent'] = $result['total_spent']; + } + + if ($result['total_estimated'] > 0) { + $values['time_estimated'] = $result['total_estimated']; + } + + if (empty($values)) { return true; } return $this->db ->table(Task::TABLE) ->eq('id', $task_id) - ->update(array( - 'time_spent' => $result['total_spent'], - 'time_estimated' => $result['total_estimated'], - )); + ->update($values); } /** diff --git a/sources/app/Model/Task.php b/sources/app/Model/Task.php index 71d973a..a1bbca9 100644 --- a/sources/app/Model/Task.php +++ b/sources/app/Model/Task.php @@ -121,7 +121,7 @@ class Task extends Base */ public function getRecurrenceStatusList() { - return array ( + return array( Task::RECURRING_STATUS_NONE => t('No'), Task::RECURRING_STATUS_PENDING => t('Yes'), ); @@ -135,7 +135,7 @@ class Task extends Base */ public function getRecurrenceTriggerList() { - return array ( + return array( Task::RECURRING_TRIGGER_FIRST_COLUMN => t('When task is moved from first column'), Task::RECURRING_TRIGGER_LAST_COLUMN => t('When task is moved to last column'), Task::RECURRING_TRIGGER_CLOSE => t('When task is closed'), @@ -150,7 +150,7 @@ class Task extends Base */ public function getRecurrenceBasedateList() { - return array ( + return array( Task::RECURRING_BASEDATE_DUEDATE => t('Existing due date'), Task::RECURRING_BASEDATE_TRIGGERDATE => t('Action date'), ); @@ -164,10 +164,37 @@ class Task extends Base */ public function getRecurrenceTimeframeList() { - return array ( + return array( Task::RECURRING_TIMEFRAME_DAYS => t('Day(s)'), Task::RECURRING_TIMEFRAME_MONTHS => t('Month(s)'), Task::RECURRING_TIMEFRAME_YEARS => t('Year(s)'), ); } + + /** + * Get task progress based on the column position + * + * @access public + * @param array $task + * @param array $columns + * @return integer + */ + public function getProgress(array $task, array $columns) + { + if ($task['is_active'] == self::STATUS_CLOSED) { + return 100; + } + + $position = 0; + + foreach ($columns as $column_id => $column_title) { + if ($column_id == $task['column_id']) { + break; + } + + $position++; + } + + return round(($position * 100) / count($columns), 1); + } } diff --git a/sources/app/Model/TaskCreation.php b/sources/app/Model/TaskCreation.php index e530da1..4373fa6 100644 --- a/sources/app/Model/TaskCreation.php +++ b/sources/app/Model/TaskCreation.php @@ -25,10 +25,17 @@ class TaskCreation extends Base return 0; } + $position = empty($values['position']) ? 0 : $values['position']; + $this->prepare($values); $task_id = $this->persist(Task::TABLE, $values); if ($task_id !== false) { + + if ($position > 0 && $values['position'] > 1) { + $this->taskPosition->movePosition($values['project_id'], $task_id, $values['column_id'], $position, $values['swimlane_id'], false); + } + $this->fireEvents($task_id, $values); } @@ -46,7 +53,7 @@ class TaskCreation extends Base $this->dateParser->convert($values, array('date_due')); $this->dateParser->convert($values, array('date_started'), true); $this->removeFields($values, array('another_task')); - $this->resetFields($values, array('creator_id', 'owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated')); + $this->resetFields($values, array('date_started', 'creator_id', 'owner_id', 'swimlane_id', 'date_due', 'score', 'category_id', 'time_estimated')); if (empty($values['column_id'])) { $values['column_id'] = $this->board->getFirstColumn($values['project_id']); diff --git a/sources/app/Model/TaskFilter.php b/sources/app/Model/TaskFilter.php index 77ab1f3..89ad9aa 100644 --- a/sources/app/Model/TaskFilter.php +++ b/sources/app/Model/TaskFilter.php @@ -36,7 +36,7 @@ class TaskFilter extends Base $this->query = $this->taskFinder->getExtendedQuery(); if (empty($tree)) { - $this->query->addCondition('1 = 0'); + $this->filterByTitle($input); } foreach ($tree as $filter => $value) { @@ -101,6 +101,7 @@ class TaskFilter extends Base $this->query->columns( Task::TABLE.'.*', 'ua.email AS assignee_email', + 'ua.name AS assignee_name', 'ua.username AS assignee_username', 'uc.email AS creator_email', 'uc.username AS creator_username' @@ -209,11 +210,11 @@ class TaskFilter extends Base */ public function filterByTitle($title) { - if (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1))) { - $this->query->eq(Task::TABLE.'.id', substr($title, 1)); - } - else if (ctype_digit($title)) { - $this->query->eq(Task::TABLE.'.id', $title); + if (ctype_digit($title) || (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1)))) { + $this->query->beginOr(); + $this->query->eq(Task::TABLE.'.id', str_replace('#', '', $title)); + $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%'); + $this->query->closeOr(); } else { $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%'); @@ -673,6 +674,51 @@ class TaskFilter extends Base }); } + /** + * Format tasks to be displayed in the Gantt chart + * + * @access public + * @return array + */ + public function toGanttBars() + { + $bars = array(); + $columns = array(); + + foreach ($this->query->findAll() as $task) { + if (! isset($column_count[$task['project_id']])) { + $columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']); + } + + $start = $task['date_started'] ?: time(); + $end = $task['date_due'] ?: $start; + + $bars[] = array( + 'type' => 'task', + 'id' => $task['id'], + 'title' => $task['title'], + 'start' => array( + (int) date('Y', $start), + (int) date('n', $start), + (int) date('j', $start), + ), + 'end' => array( + (int) date('Y', $end), + (int) date('n', $end), + (int) date('j', $end), + ), + 'column_title' => $task['column_name'], + 'assignee' => $task['assignee_name'] ?: $task['assignee_username'], + 'progress' => $this->task->getProgress($task, $columns[$task['project_id']]).'%', + 'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), + 'color' => $this->color->getColorProperties($task['color_id']), + 'not_defined' => empty($task['date_due']) || empty($task['date_started']), + ); + } + + return $bars; + } + /** * Format the results to the ajax autocompletion * @@ -833,7 +879,7 @@ class TaskFilter extends Base $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); if (! empty($task['owner_id'])) { - $vEvent->setOrganizer('MAILTO:'.($task['assignee_email'] ?: $task['assignee_username'].'@kanboard.local')); + $vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']); } if (! empty($task['creator_id'])) { diff --git a/sources/app/Model/TaskFinder.php b/sources/app/Model/TaskFinder.php index 6cf79d1..3e76041 100644 --- a/sources/app/Model/TaskFinder.php +++ b/sources/app/Model/TaskFinder.php @@ -12,6 +12,43 @@ use PDO; */ class TaskFinder extends Base { + /** + * Get query for project user overview + * + * @access public + * @param array $project_ids + * @param integer $is_active + * @return \PicoDb\Table + */ + public function getProjectUserOverviewQuery(array $project_ids, $is_active) + { + if (empty($project_ids)) { + $project_ids = array(-1); + } + + return $this->db + ->table(Task::TABLE) + ->columns( + Task::TABLE.'.id', + Task::TABLE.'.title', + Task::TABLE.'.date_due', + Task::TABLE.'.date_started', + Task::TABLE.'.project_id', + Task::TABLE.'.color_id', + Task::TABLE.'.time_spent', + Task::TABLE.'.time_estimated', + Project::TABLE.'.name AS project_name', + Board::TABLE.'.title AS column_name', + User::TABLE.'.username AS assignee_username', + User::TABLE.'.name AS assignee_name' + ) + ->eq(Task::TABLE.'.is_active', $is_active) + ->in(Project::TABLE.'.id', $project_ids) + ->join(Project::TABLE, 'id', 'project_id') + ->join(Board::TABLE, 'id', 'column_id', Task::TABLE) + ->join(User::TABLE, 'id', 'owner_id', Task::TABLE); + } + /** * Get query for assigned user tasks * @@ -56,6 +93,7 @@ class TaskFinder extends Base '(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id) AS nb_subtasks', '(SELECT count(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks', '(SELECT count(*) FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id) AS nb_links', + '(SELECT 1 FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id AND '.TaskLink::TABLE.'.link_id = 9) AS is_milestone', 'tasks.id', 'tasks.reference', 'tasks.title', @@ -89,6 +127,7 @@ class TaskFinder extends Base Category::TABLE.'.name AS category_name', Category::TABLE.'.description AS category_description', Board::TABLE.'.title AS column_name', + Board::TABLE.'.position AS column_position', Swimlane::TABLE.'.name AS swimlane_name', Project::TABLE.'.default_swimlane', Project::TABLE.'.name AS project_name' diff --git a/sources/app/Model/TaskLink.php b/sources/app/Model/TaskLink.php index 3fdbd04..466e44d 100644 --- a/sources/app/Model/TaskLink.php +++ b/sources/app/Model/TaskLink.php @@ -4,6 +4,7 @@ namespace Model; use SimpleValidator\Validator; use SimpleValidator\Validators; +use Event\TaskLinkEvent; /** * TaskLink model @@ -21,6 +22,13 @@ class TaskLink extends Base */ const TABLE = 'task_has_links'; + /** + * Events + * + * @var string + */ + const EVENT_CREATE_UPDATE = 'tasklink.create_update'; + /** * Get a task link * @@ -113,6 +121,20 @@ class TaskLink extends Base return $result; } + /** + * Publish events + * + * @access private + * @param array $events + */ + private function fireEvents(array $events) + { + foreach ($events as $event) { + $event['project_id'] = $this->taskFinder->getProjectId($event['task_id']); + $this->container['dispatcher']->dispatch(self::EVENT_CREATE_UPDATE, new TaskLinkEvent($event)); + } + } + /** * Create a new link * @@ -124,29 +146,37 @@ class TaskLink extends Base */ public function create($task_id, $opposite_task_id, $link_id) { + $events = array(); $this->db->startTransaction(); // Get opposite link $opposite_link_id = $this->link->getOppositeLinkId($link_id); - // Create the original task link - $this->db->table(self::TABLE)->insert(array( + $values = array( 'task_id' => $task_id, 'opposite_task_id' => $opposite_task_id, 'link_id' => $link_id, - )); + ); + // Create the original task link + $this->db->table(self::TABLE)->insert($values); $task_link_id = $this->db->getLastId(); + $events[] = $values; // Create the opposite task link - $this->db->table(self::TABLE)->insert(array( + $values = array( 'task_id' => $opposite_task_id, 'opposite_task_id' => $task_id, 'link_id' => $opposite_link_id, - )); + ); + + $this->db->table(self::TABLE)->insert($values); + $events[] = $values; $this->db->closeTransaction(); + $this->fireEvents($events); + return (int) $task_link_id; } @@ -162,6 +192,7 @@ class TaskLink extends Base */ public function update($task_link_id, $task_id, $opposite_task_id, $link_id) { + $events = array(); $this->db->startTransaction(); // Get original task link @@ -174,22 +205,33 @@ class TaskLink extends Base $opposite_link_id = $this->link->getOppositeLinkId($link_id); // Update the original task link - $rs1 = $this->db->table(self::TABLE)->eq('id', $task_link_id)->update(array( + $values = array( 'task_id' => $task_id, 'opposite_task_id' => $opposite_task_id, 'link_id' => $link_id, - )); + ); + + $rs1 = $this->db->table(self::TABLE)->eq('id', $task_link_id)->update($values); + $events[] = $values; // Update the opposite link - $rs2 = $this->db->table(self::TABLE)->eq('id', $opposite_task_link['id'])->update(array( + $values = array( 'task_id' => $opposite_task_id, 'opposite_task_id' => $task_id, 'link_id' => $opposite_link_id, - )); + ); + + $rs2 = $this->db->table(self::TABLE)->eq('id', $opposite_task_link['id'])->update($values); + $events[] = $values; $this->db->closeTransaction(); - return $rs1 && $rs2; + if ($rs1 && $rs2) { + $this->fireEvents($events); + return true; + } + + return false; } /** diff --git a/sources/app/Model/User.php b/sources/app/Model/User.php index b6804ab..8a7eff4 100644 --- a/sources/app/Model/User.php +++ b/sources/app/Model/User.php @@ -57,6 +57,7 @@ class User extends Base 'name', 'email', 'is_admin', + 'is_project_admin', 'is_ldap_user', 'notifications_enabled', 'google_id', @@ -137,6 +138,22 @@ class User extends Base return $this->db->table(self::TABLE)->eq('github_id', $github_id)->findOne(); } + /** + * Get a specific user by the Gitlab id + * + * @access public + * @param string $gitlab_id Gitlab user id + * @return array|boolean + */ + public function getByGitlabId($gitlab_id) + { + if (empty($gitlab_id)) { + return false; + } + + return $this->db->table(self::TABLE)->eq('gitlab_id', $gitlab_id)->findOne(); + } + /** * Get a specific user by the username * @@ -207,12 +224,19 @@ class User extends Base * List all users (key-value pairs with id/username) * * @access public + * @param boolean $prepend Prepend "All users" * @return array */ - public function getList() + public function getList($prepend = false) { $users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll(); - return $this->prepareList($users); + $listing = $this->prepareList($users); + + if ($prepend) { + return array(User::EVERYBODY_ID => t('Everybody')) + $listing; + } + + return $listing; } /** @@ -254,7 +278,7 @@ class User extends Base } $this->removeFields($values, array('confirmation', 'current_password')); - $this->resetFields($values, array('is_admin', 'is_ldap_user')); + $this->resetFields($values, array('is_admin', 'is_ldap_user', 'is_project_admin')); } /** @@ -364,6 +388,71 @@ class User extends Base ->save(array('token' => '')); } + /** + * Get the number of failed login for the user + * + * @access public + * @param string $username + * @return integer + */ + public function getFailedLogin($username) + { + return (int) $this->db->table(self::TABLE)->eq('username', $username)->findOneColumn('nb_failed_login'); + } + + /** + * Reset to 0 the counter of failed login + * + * @access public + * @param string $username + * @return boolean + */ + public function resetFailedLogin($username) + { + return $this->db->table(self::TABLE)->eq('username', $username)->update(array('nb_failed_login' => 0, 'lock_expiration_date' => 0)); + } + + /** + * Increment failed login counter + * + * @access public + * @param string $username + * @return boolean + */ + public function incrementFailedLogin($username) + { + return $this->db->execute('UPDATE '.self::TABLE.' SET nb_failed_login=nb_failed_login+1 WHERE username=?', array($username)) !== false; + } + + /** + * Check if the account is locked + * + * @access public + * @param string $username + * @return boolean + */ + public function isLocked($username) + { + return $this->db->table(self::TABLE) + ->eq('username', $username) + ->neq('lock_expiration_date', 0) + ->gte('lock_expiration_date', time()) + ->exists(); + } + + /** + * Lock the account for the specified duration + * + * @access public + * @param string $username Username + * @param integer $duration Duration in minutes + * @return boolean + */ + public function lock($username, $duration = 15) + { + return $this->db->table(self::TABLE)->eq('username', $username)->update(array('lock_expiration_date' => time() + $duration * 60)); + } + /** * Common validation rules * @@ -377,6 +466,7 @@ class User extends Base new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), new Validators\Email('email', t('Email address invalid')), new Validators\Integer('is_admin', t('This value must be an integer')), + new Validators\Integer('is_project_admin', t('This value must be an integer')), new Validators\Integer('is_ldap_user', t('This value must be an integer')), ); } diff --git a/sources/app/Model/UserSession.php b/sources/app/Model/UserSession.php index 44a9c2a..1ae3fdf 100644 --- a/sources/app/Model/UserSession.php +++ b/sources/app/Model/UserSession.php @@ -34,6 +34,7 @@ class UserSession extends Base $user['id'] = (int) $user['id']; $user['is_admin'] = (bool) $user['is_admin']; + $user['is_project_admin'] = (bool) $user['is_project_admin']; $user['is_ldap_user'] = (bool) $user['is_ldap_user']; $user['twofactor_activated'] = (bool) $user['twofactor_activated']; @@ -73,6 +74,17 @@ class UserSession extends Base return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true; } + /** + * Return true if the logged user is project admin + * + * @access public + * @return bool + */ + public function isProjectAdmin() + { + return isset($this->session['user']['is_project_admin']) && $this->session['user']['is_project_admin'] === true; + } + /** * Get the connected user id * diff --git a/sources/app/Schema/Mysql.php b/sources/app/Schema/Mysql.php index 47fb806..b1ac0ab 100644 --- a/sources/app/Schema/Mysql.php +++ b/sources/app/Schema/Mysql.php @@ -6,7 +6,29 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 81; +const VERSION = 85; + +function version_85($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INT"); +} + +function version_84($pdo) +{ + $pdo->exec("ALTER TABLE projects ADD COLUMN start_date VARCHAR(10) DEFAULT ''"); + $pdo->exec("ALTER TABLE projects ADD COLUMN end_date VARCHAR(10) DEFAULT ''"); +} + +function version_83($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin INT DEFAULT 0"); +} + +function version_82($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INT DEFAULT 0"); + $pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INT DEFAULT 0"); +} function version_81($pdo) { diff --git a/sources/app/Schema/Postgres.php b/sources/app/Schema/Postgres.php index 6b85ff5..9477b41 100644 --- a/sources/app/Schema/Postgres.php +++ b/sources/app/Schema/Postgres.php @@ -6,7 +6,29 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 61; +const VERSION = 65; + +function version_65($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INTEGER"); +} + +function version_64($pdo) +{ + $pdo->exec("ALTER TABLE projects ADD COLUMN start_date VARCHAR(10) DEFAULT ''"); + $pdo->exec("ALTER TABLE projects ADD COLUMN end_date VARCHAR(10) DEFAULT ''"); +} + +function version_63($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin BOOLEAN DEFAULT '0'"); +} + +function version_62($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INTEGER DEFAULT 0"); + $pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INTEGER DEFAULT 0"); +} function version_61($pdo) { diff --git a/sources/app/Schema/Sqlite.php b/sources/app/Schema/Sqlite.php index 9e0575c..b4e4b94 100644 --- a/sources/app/Schema/Sqlite.php +++ b/sources/app/Schema/Sqlite.php @@ -6,7 +6,29 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 77; +const VERSION = 81; + +function version_81($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN gitlab_id INTEGER"); +} + +function version_80($pdo) +{ + $pdo->exec("ALTER TABLE projects ADD COLUMN start_date TEXT DEFAULT ''"); + $pdo->exec("ALTER TABLE projects ADD COLUMN end_date TEXT DEFAULT ''"); +} + +function version_79($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_project_admin INTEGER DEFAULT 0"); +} + +function version_78($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN nb_failed_login INTEGER DEFAULT 0"); + $pdo->exec("ALTER TABLE users ADD COLUMN lock_expiration_date INTEGER DEFAULT 0"); +} function version_77($pdo) { diff --git a/sources/app/Template/action/index.php b/sources/app/Template/action/index.php index 6898fc2..bf2f747 100644 --- a/sources/app/Template/action/index.php +++ b/sources/app/Template/action/index.php @@ -42,6 +42,8 @@ text->in($param['value'], $colors_list) ?> text->contains($param['name'], 'category_id')): ?> text->in($param['value'], $categories_list) ?> + text->contains($param['name'], 'link_id')): ?> + text->in($param['value'], $links_list) ?> e($param['value']) ?> diff --git a/sources/app/Template/action/params.php b/sources/app/Template/action/params.php index 759c596..dcfaa9c 100644 --- a/sources/app/Template/action/params.php +++ b/sources/app/Template/action/params.php @@ -28,6 +28,9 @@ text->contains($param_name, 'category_id')): ?> form->label($param_desc, $param_name) ?> form->select('params['.$param_name.']', $categories_list, $values) ?>
+ text->contains($param_name, 'link_id')): ?> + form->label($param_desc, $param_name) ?> + form->select('params['.$param_name.']', $links_list, $values) ?>
form->label($param_desc, $param_name) ?> form->text('params['.$param_name.']', $values) ?> diff --git a/sources/app/Template/analytic/cfd.php b/sources/app/Template/analytic/cfd.php index ab706d5..45f53e0 100644 --- a/sources/app/Template/analytic/cfd.php +++ b/sources/app/Template/analytic/cfd.php @@ -6,7 +6,7 @@

-
+
diff --git a/sources/app/Template/analytic/layout.php b/sources/app/Template/analytic/layout.php index 9d6bf77..fd2090a 100644 --- a/sources/app/Template/analytic/layout.php +++ b/sources/app/Template/analytic/layout.php @@ -19,7 +19,7 @@ url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $project['id'])) ?> - user->isManager($project['id'])): ?> + user->isProjectManagementAllowed($project['id'])): ?>
  • url->link(t('Project settings'), 'project', 'show', array('project_id' => $project['id'])) ?> diff --git a/sources/app/Template/analytic/sidebar.php b/sources/app/Template/analytic/sidebar.php index 59cc1fa..c942f7e 100644 --- a/sources/app/Template/analytic/sidebar.php +++ b/sources/app/Template/analytic/sidebar.php @@ -1,22 +1,22 @@