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 @@
= $this->text->in($param['value'], $colors_list) ?>
text->contains($param['name'], 'category_id')): ?>
= $this->text->in($param['value'], $categories_list) ?>
+ text->contains($param['name'], 'link_id')): ?>
+ = $this->text->in($param['value'], $links_list) ?>
= $this->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')): ?>
= $this->form->label($param_desc, $param_name) ?>
= $this->form->select('params['.$param_name.']', $categories_list, $values) ?>
+ text->contains($param_name, 'link_id')): ?>
+ = $this->form->label($param_desc, $param_name) ?>
+ = $this->form->select('params['.$param_name.']', $links_list, $values) ?>
= $this->form->label($param_desc, $param_name) ?>
= $this->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 @@
= t('You need at least 2 days of data to show the chart.') ?>
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 @@
= $this->url->link(t('Back to the calendar'), 'calendar', 'show', array('project_id' => $project['id'])) ?>
- user->isManager($project['id'])): ?>
+ user->isProjectManagementAllowed($project['id'])): ?>
= $this->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 @@