summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Auth/Ldap.php2
-rw-r--r--app/Controller/Base.php9
-rw-r--r--app/Controller/Board.php5
-rw-r--r--app/Controller/Budget.php135
-rw-r--r--app/Controller/Calendar.php8
-rw-r--r--app/Controller/Config.php6
-rw-r--r--app/Controller/File.php64
-rw-r--r--app/Controller/Hourlyrate.php89
-rw-r--r--app/Controller/Project.php7
-rw-r--r--app/Controller/Subtask.php20
-rw-r--r--app/Controller/Task.php8
-rw-r--r--app/Controller/Tasklink.php16
-rw-r--r--app/Controller/Timetable.php39
-rw-r--r--app/Controller/Timetableday.php88
-rw-r--r--app/Controller/Timetableextra.php16
-rw-r--r--app/Controller/Timetableoff.php107
-rw-r--r--app/Controller/Timetableweek.php99
-rw-r--r--app/Controller/User.php8
-rw-r--r--app/Core/Helper.php93
-rw-r--r--app/Locale/da_DK/translations.php70
-rw-r--r--app/Locale/de_DE/translations.php76
-rw-r--r--app/Locale/es_ES/translations.php70
-rw-r--r--app/Locale/fi_FI/translations.php70
-rw-r--r--app/Locale/fr_FR/translations.php70
-rw-r--r--app/Locale/hu_HU/translations.php110
-rw-r--r--app/Locale/it_IT/translations.php70
-rw-r--r--app/Locale/ja_JP/translations.php70
-rw-r--r--app/Locale/nl_NL/translations.php807
-rw-r--r--app/Locale/pl_PL/translations.php70
-rw-r--r--app/Locale/pt_BR/translations.php70
-rw-r--r--app/Locale/ru_RU/translations.php70
-rw-r--r--app/Locale/sr_Latn_RS/translations.php807
-rw-r--r--app/Locale/sv_SE/translations.php266
-rw-r--r--app/Locale/th_TH/translations.php70
-rw-r--r--app/Locale/tr_TR/translations.php807
-rw-r--r--app/Locale/zh_CN/translations.php292
-rw-r--r--app/Model/Acl.php2
-rw-r--r--app/Model/Action.php4
-rw-r--r--app/Model/Base.php3
-rw-r--r--app/Model/Budget.php210
-rw-r--r--app/Model/Config.php26
-rw-r--r--app/Model/DateParser.php41
-rw-r--r--app/Model/File.php48
-rw-r--r--app/Model/HourlyRate.php121
-rw-r--r--app/Model/ProjectPermission.php20
-rw-r--r--app/Model/Subtask.php86
-rw-r--r--app/Model/SubtaskTimeTracking.php91
-rw-r--r--app/Model/Swimlane.php50
-rw-r--r--app/Model/TaskFinder.php10
-rw-r--r--app/Model/TaskLink.php2
-rw-r--r--app/Model/Timetable.php358
-rw-r--r--app/Model/TimetableDay.php87
-rw-r--r--app/Model/TimetableExtra.php22
-rw-r--r--app/Model/TimetableOff.php125
-rw-r--r--app/Model/TimetableWeek.php91
-rw-r--r--app/Schema/Mysql.php118
-rw-r--r--app/Schema/Postgres.php112
-rw-r--r--app/Schema/Sqlite.php114
-rw-r--r--app/ServiceProvider/ClassProvider.php8
-rw-r--r--app/ServiceProvider/DatabaseProvider.php2
-rw-r--r--app/Template/analytic/layout.php2
-rw-r--r--app/Template/app/dashboard.php8
-rw-r--r--app/Template/app/projects.php10
-rw-r--r--app/Template/board/edit.php8
-rw-r--r--app/Template/board/files.php41
-rw-r--r--app/Template/board/filters.php26
-rw-r--r--app/Template/board/show.php3
-rw-r--r--app/Template/board/swimlane.php2
-rw-r--r--app/Template/board/task_footer.php14
-rw-r--r--app/Template/board/task_menu.php9
-rw-r--r--app/Template/board/task_private.php4
-rw-r--r--app/Template/board/task_public.php4
-rw-r--r--app/Template/budget/breakdown.php34
-rw-r--r--app/Template/budget/create.php51
-rw-r--r--app/Template/budget/index.php35
-rw-r--r--app/Template/budget/remove.php13
-rw-r--r--app/Template/config/about.php1
-rw-r--r--app/Template/config/application.php3
-rw-r--r--app/Template/file/show.php55
-rw-r--r--app/Template/hourlyrate/index.php46
-rw-r--r--app/Template/hourlyrate/remove.php13
-rw-r--r--app/Template/layout.php14
-rw-r--r--app/Template/project/edit.php29
-rw-r--r--app/Template/project/index.php8
-rw-r--r--app/Template/project/show.php12
-rw-r--r--app/Template/project/sidebar.php5
-rw-r--r--app/Template/subtask/create.php2
-rw-r--r--app/Template/subtask/edit.php2
-rw-r--r--app/Template/subtask/show.php12
-rw-r--r--app/Template/task/new.php4
-rw-r--r--app/Template/task/show.php6
-rw-r--r--app/Template/task/time_tracking.php10
-rw-r--r--app/Template/tasklink/create.php8
-rw-r--r--app/Template/tasklink/show.php22
-rw-r--r--app/Template/timetable/index.php44
-rw-r--r--app/Template/timetable_day/index.php45
-rw-r--r--app/Template/timetable_day/remove.php13
-rw-r--r--app/Template/timetable_extra/index.php56
-rw-r--r--app/Template/timetable_extra/remove.php13
-rw-r--r--app/Template/timetable_off/index.php56
-rw-r--r--app/Template/timetable_off/remove.php13
-rw-r--r--app/Template/timetable_week/index.php46
-rw-r--r--app/Template/timetable_week/remove.php13
-rw-r--r--app/Template/user/sidebar.php8
-rw-r--r--app/Template/user/timesheet.php10
-rw-r--r--app/constants.php4
106 files changed, 6869 insertions, 403 deletions
diff --git a/app/Auth/Ldap.php b/app/Auth/Ldap.php
index 376d16f6..ed29199f 100644
--- a/app/Auth/Ldap.php
+++ b/app/Auth/Ldap.php
@@ -261,7 +261,7 @@ class Ldap extends Base
private function getQuery($username, $email)
{
if ($username && $email) {
- return '(&('.sprintf(LDAP_USER_PATTERN, $username).')('.sprintf(LDAP_ACCOUNT_EMAIL, $email).')';
+ return '(&('.sprintf(LDAP_USER_PATTERN, $username).')('.LDAP_ACCOUNT_EMAIL.'='.$email.'))';
}
else if ($username) {
return sprintf(LDAP_USER_PATTERN, $username);
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index d949048d..6420e0ee 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -34,6 +34,7 @@ use Symfony\Component\EventDispatcher\Event;
* @property \Model\Config $config
* @property \Model\DateParser $dateParser
* @property \Model\File $file
+ * @property \Model\HourlyRate $hourlyRate
* @property \Model\LastLogin $lastLogin
* @property \Model\Notification $notification
* @property \Model\Project $project
@@ -56,12 +57,16 @@ use Symfony\Component\EventDispatcher\Event;
* @property \Model\TaskPosition $taskPosition
* @property \Model\TaskPermission $taskPermission
* @property \Model\TaskStatus $taskStatus
+ * @property \Model\Timetable $timetable
+ * @property \Model\TimetableDay $timetableDay
+ * @property \Model\TimetableWeek $timetableWeek
+ * @property \Model\TimetableExtra $timetableExtra
+ * @property \Model\TimetableOff $timetableOff
* @property \Model\TaskValidator $taskValidator
* @property \Model\TaskLink $taskLink
* @property \Model\CommentHistory $commentHistory
* @property \Model\SubtaskHistory $subtaskHistory
* @property \Model\SubtaskTimeTracking $subtaskTimeTracking
- * @property \Model\TimeTracking $timeTracking
* @property \Model\User $user
* @property \Model\UserSession $userSession
* @property \Model\Webhook $webhook
@@ -148,7 +153,7 @@ abstract class Base
$this->response->xss();
// Allow the public board iframe inclusion
- if ($action !== 'readonly') {
+ if (ENABLE_XFRAME && $action !== 'readonly') {
$this->response->xframe();
}
diff --git a/app/Controller/Board.php b/app/Controller/Board.php
index 90b7f357..17170317 100644
--- a/app/Controller/Board.php
+++ b/app/Controller/Board.php
@@ -127,6 +127,7 @@ class Board extends Base
'swimlanes' => $this->board->getBoard($project['id']),
'categories' => $this->category->getList($project['id'], false),
'title' => $project['name'],
+ 'description' => $project['description'],
'no_layout' => true,
'not_editable' => true,
'board_public_refresh_interval' => $this->config->get('board_public_refresh_interval'),
@@ -187,6 +188,7 @@ class Board extends Base
'swimlanes' => $this->board->getBoard($project['id']),
'categories' => $this->category->getList($project['id'], true, true),
'title' => $project['name'],
+ 'description' => $project['description'],
'board_selector' => $board_selector,
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
@@ -439,7 +441,8 @@ class Board extends Base
$task = $this->getTask();
$this->response->html($this->template->render('board/files', array(
- 'files' => $this->file->getAll($task['id']),
+ 'files' => $this->file->getAllDocuments($task['id']),
+ 'images' => $this->file->getAllImages($task['id']),
'task' => $task,
)));
}
diff --git a/app/Controller/Budget.php b/app/Controller/Budget.php
new file mode 100644
index 00000000..2c56c79d
--- /dev/null
+++ b/app/Controller/Budget.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Budget
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Budget extends Base
+{
+ /**
+ * Budget index page
+ *
+ * @access public
+ */
+ public function index()
+ {
+ $project = $this->getProject();
+
+ $this->response->html($this->projectLayout('budget/index', array(
+ 'daily_budget' => $this->budget->getDailyBudgetBreakdown($project['id']),
+ 'project' => $project,
+ 'title' => t('Budget')
+ )));
+ }
+
+ /**
+ * Cost breakdown by users/subtasks/tasks
+ *
+ * @access public
+ */
+ public function breakdown()
+ {
+ $project = $this->getProject();
+
+ $paginator = $this->paginator
+ ->setUrl('budget', 'breakdown', array('project_id' => $project['id']))
+ ->setMax(30)
+ ->setOrder('start')
+ ->setDirection('DESC')
+ ->setQuery($this->budget->getSubtaskBreakdown($project['id']))
+ ->calculate();
+
+ $this->response->html($this->projectLayout('budget/breakdown', array(
+ 'paginator' => $paginator,
+ 'project' => $project,
+ 'title' => t('Budget')
+ )));
+ }
+
+ /**
+ * Create budget lines
+ *
+ * @access public
+ */
+ public function create(array $values = array(), array $errors = array())
+ {
+ $project = $this->getProject();
+
+ if (empty($values)) {
+ $values['date'] = date('Y-m-d');
+ }
+
+ $this->response->html($this->projectLayout('budget/create', array(
+ 'lines' => $this->budget->getAll($project['id']),
+ 'values' => $values + array('project_id' => $project['id']),
+ 'errors' => $errors,
+ 'project' => $project,
+ 'title' => t('Budget')
+ )));
+ }
+
+ /**
+ * Validate and save a new budget
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $project = $this->getProject();
+
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->budget->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->budget->create($values['project_id'], $values['amount'], $values['comment'], $values['date'])) {
+ $this->session->flash(t('The budget line have been created successfully.'));
+ $this->response->redirect($this->helper->url('budget', 'create', array('project_id' => $project['id'])));
+ }
+ else {
+ $this->session->flashError(t('Unable to create the budget line.'));
+ }
+ }
+
+ $this->create($values, $errors);
+ }
+
+ /**
+ * Confirmation dialog before removing a budget
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $project = $this->getProject();
+
+ $this->response->html($this->projectLayout('budget/remove', array(
+ 'project' => $project,
+ 'budget_id' => $this->request->getIntegerParam('budget_id'),
+ 'title' => t('Remove a budget line'),
+ )));
+ }
+
+ /**
+ * Remove a budget
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $project = $this->getProject();
+
+ if ($this->budget->remove($this->request->getIntegerParam('budget_id'))) {
+ $this->session->flash(t('Budget line removed successfully.'));
+ } else {
+ $this->session->flashError(t('Unable to remove this budget line.'));
+ }
+
+ $this->response->redirect($this->helper->url('budget', 'create', array('project_id' => $project['id'])));
+ }
+}
diff --git a/app/Controller/Calendar.php b/app/Controller/Calendar.php
index 1c7ac7c0..6cfa2bad 100644
--- a/app/Controller/Calendar.php
+++ b/app/Controller/Calendar.php
@@ -14,7 +14,7 @@ use Model\Task as TaskModel;
class Calendar extends Base
{
/**
- * Show calendar view
+ * Show calendar view for projects
*
* @access public
*/
@@ -59,9 +59,7 @@ class Calendar extends Base
->filterByDueDateRange($start, $end)
->toCalendarEvents();
- $subtask_timeslots = $this->subtaskTimeTracking->getProjectCalendarEvents($project_id, $start, $end);
-
- $this->response->json(array_merge($due_tasks, $subtask_timeslots));
+ $this->response->json($due_tasks);
}
/**
@@ -100,7 +98,7 @@ class Calendar extends Base
$this->taskModification->update(array(
'id' => $values['task_id'],
- 'date_due' => $values['date_due'],
+ 'date_due' => substr($values['date_due'], 0, 10),
));
}
}
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index 01c7ad53..bee897be 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -38,7 +38,11 @@ class Config extends Base
{
if ($this->request->isPost()) {
- $values = $this->request->getValues() + array('subtask_restriction' => 0, 'subtask_time_tracking' => 0);
+ $values = $this->request->getValues();
+
+ if ($redirect === 'board') {
+ $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0);
+ }
if ($this->config->save($values)) {
$this->config->reload();
diff --git a/app/Controller/File.php b/app/Controller/File.php
index 3255fe84..3963e2d7 100644
--- a/app/Controller/File.php
+++ b/app/Controller/File.php
@@ -102,6 +102,70 @@ class File extends Base
}
/**
+ * Return image thumbnails
+ *
+ * @access public
+ */
+ public function thumbnail()
+ {
+ $task = $this->getTask();
+ $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+ $width_param = $this->request->getIntegerParam('width');
+ $height_param = $this->request->getIntegerParam('height');
+ $filename = FILES_DIR.$file['path'];
+
+ if ($file['task_id'] == $task['id'] && file_exists($filename)) {
+
+ // Get new sizes
+ list($width, $height) = getimagesize($filename);
+
+ if ($width_param == 0 && $height_param == 0) {
+ $newwidth = 100;
+ $newheight = 100;
+ } elseif ($width_param > 0 && $height_param == 0) {
+ $newwidth = $width_param;
+ $newheight = floor($height * ($width_param / $width));
+ } elseif ($width_param == 0 && $height_param > 0) {
+ $newwidth = floor($width * ($height_param / $height));
+ $newheight = $height_param;
+ } else {
+ $newwidth = $width_param;
+ $newheight = $height_param;
+ }
+
+ // Load
+ $thumb = imagecreatetruecolor($newwidth, $newheight);
+ $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
+
+ switch ($extension) {
+ case 'jpeg':
+ case 'jpg':
+ $source = imagecreatefromjpeg($filename);
+ break;
+ case 'png':
+ $source = imagecreatefrompng($filename);
+ break;
+ case 'gif':
+ $source = imagecreatefromgif($filename);
+ break;
+ default:
+ die('File "' . $filename . '" is not valid jpg, png or gif image.');
+ break;
+ }
+
+ // Resize
+ imagecopyresampled($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
+
+ $metadata = getimagesize($filename);
+
+ if (isset($metadata['mime'])) {
+ $this->response->contentType($metadata['mime']);
+ imagejpeg($thumb);
+ }
+ }
+ }
+
+ /**
* Remove a file
*
* @access public
diff --git a/app/Controller/Hourlyrate.php b/app/Controller/Hourlyrate.php
new file mode 100644
index 00000000..8d96e5ca
--- /dev/null
+++ b/app/Controller/Hourlyrate.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Hourly Rate controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Hourlyrate extends User
+{
+ /**
+ * Display rate and form
+ *
+ * @access public
+ */
+ public function index(array $values = array(), array $errors = array())
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout('hourlyrate/index', array(
+ 'rates' => $this->hourlyRate->getAllByUser($user['id']),
+ 'currencies_list' => $this->config->getCurrencies(),
+ 'values' => $values + array('user_id' => $user['id']),
+ 'errors' => $errors,
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Validate and save a new rate
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->hourlyRate->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->hourlyRate->create($values['user_id'], $values['rate'], $values['currency'], $values['date_effective'])) {
+ $this->session->flash(t('Hourly rate created successfully.'));
+ $this->response->redirect($this->helper->url('hourlyrate', 'index', array('user_id' => $values['user_id'])));
+ }
+ else {
+ $this->session->flashError(t('Unable to save the hourly rate.'));
+ }
+ }
+
+ $this->index($values, $errors);
+ }
+
+ /**
+ * Confirmation dialag box to remove a row
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout('hourlyrate/remove', array(
+ 'rate_id' => $this->request->getIntegerParam('rate_id'),
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Remove a row
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $user = $this->getUser();
+
+ if ($this->hourlyRate->remove($this->request->getIntegerParam('rate_id'))) {
+ $this->session->flash(t('Rate removed successfully.'));
+ }
+ else {
+ $this->session->flash(t('Unable to remove this rate.'));
+ }
+
+ $this->response->redirect($this->helper->url('hourlyrate', 'index', array('user_id' => $user['id'])));
+ }
+}
diff --git a/app/Controller/Project.php b/app/Controller/Project.php
index fb0a8d05..4e01271a 100644
--- a/app/Controller/Project.php
+++ b/app/Controller/Project.php
@@ -23,7 +23,7 @@ class Project extends Base
else {
$project_ids = $this->projectPermission->getMemberProjectIds($this->userSession->getId());
}
-
+
$nb_projects = count($project_ids);
$paginator = $this->paginator
@@ -128,6 +128,11 @@ class Project extends Base
{
$project = $this->getProject();
$values = $this->request->getValues();
+
+ if ($project['is_private'] == 1) {
+ $values += array('is_private' => 0);
+ }
+
list($valid, $errors) = $this->project->validateModification($values);
if ($valid) {
diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php
index c7ec00d1..385785a1 100644
--- a/app/Controller/Subtask.php
+++ b/app/Controller/Subtask.php
@@ -185,7 +185,7 @@ class Subtask extends Base
if ($redirect === 'board') {
$this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId());
-
+
$this->response->html($this->template->render('board/subtasks', array(
'subtasks' => $this->subtask->getAll($task['id']),
'task' => $task,
@@ -259,4 +259,22 @@ class Subtask extends Base
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
}
}
+
+ /**
+ * Move subtask position
+ *
+ * @access public
+ */
+ public function movePosition()
+ {
+ $this->checkCSRFParam();
+ $project_id = $this->request->getIntegerParam('project_id');
+ $task_id = $this->request->getIntegerParam('task_id');
+ $subtask_id = $this->request->getIntegerParam('subtask_id');
+ $direction = $this->request->getStringParam('direction');
+ $method = $direction === 'up' ? 'moveUp' : 'moveDown';
+
+ $this->subtask->$method($task_id, $subtask_id);
+ $this->response->redirect($this->helper->url('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id)).'#subtasks');
+ }
}
diff --git a/app/Controller/Task.php b/app/Controller/Task.php
index 741db61e..ace40a01 100644
--- a/app/Controller/Task.php
+++ b/app/Controller/Task.php
@@ -68,12 +68,14 @@ class Task extends Base
$this->response->html($this->taskLayout('task/show', array(
'project' => $this->project->getById($task['project_id']),
- 'files' => $this->file->getAll($task['id']),
+ 'files' => $this->file->getAllDocuments($task['id']),
+ 'images' => $this->file->getAllImages($task['id']),
'comments' => $this->comment->getAll($task['id']),
'subtasks' => $subtasks,
'links' => $this->taskLink->getLinks($task['id']),
'task' => $task,
'values' => $values,
+ 'link_label_list' => $this->link->getList(0, false),
'columns_list' => $this->board->getColumnsList($task['project_id']),
'colors_list' => $this->color->getList(),
'date_format' => $this->config->get('application_date_format'),
@@ -91,11 +93,12 @@ class Task extends Base
{
$project = $this->getProject();
$method = $this->request->isAjax() ? 'render' : 'layout';
+ $swimlanes_list = $this->swimlane->getList($project['id']);
if (empty($values)) {
$values = array(
- 'swimlane_id' => $this->request->getIntegerParam('swimlane_id'),
+ 'swimlane_id' => $this->request->getIntegerParam('swimlane_id', key($swimlanes_list)),
'column_id' => $this->request->getIntegerParam('column_id'),
'color_id' => $this->request->getStringParam('color_id'),
'owner_id' => $this->request->getIntegerParam('owner_id'),
@@ -112,6 +115,7 @@ class Task extends Base
'users_list' => $this->projectPermission->getMemberList($project['id'], true, false, true),
'colors_list' => $this->color->getList(),
'categories_list' => $this->category->getList($project['id']),
+ 'swimlanes_list' => $swimlanes_list,
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'title' => $project['name'].' &gt; '.t('New task')
diff --git a/app/Controller/Tasklink.php b/app/Controller/Tasklink.php
index 61b7fab8..59ce0433 100644
--- a/app/Controller/Tasklink.php
+++ b/app/Controller/Tasklink.php
@@ -36,6 +36,7 @@ class Tasklink extends Base
public function create(array $values = array(), array $errors = array())
{
$task = $this->getTask();
+ $ajax = $this->request->isAjax() || $this->request->getIntegerParam('ajax');
if (empty($values)) {
$values = array(
@@ -43,6 +44,17 @@ class Tasklink extends Base
);
}
+ if ($ajax) {
+ $this->response->html($this->template->render('tasklink/create', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'task' => $task,
+ 'labels' => $this->link->getList(0, false),
+ 'title' => t('Add a new link'),
+ 'ajax' => $ajax,
+ )));
+ }
+
$this->response->html($this->taskLayout('tasklink/create', array(
'values' => $values,
'errors' => $errors,
@@ -61,6 +73,7 @@ class Tasklink extends Base
{
$task = $this->getTask();
$values = $this->request->getValues();
+ $ajax = $this->request->isAjax() || $this->request->getIntegerParam('ajax');
list($valid, $errors) = $this->taskLink->validateCreation($values);
@@ -68,6 +81,9 @@ class Tasklink extends Base
if ($this->taskLink->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) {
$this->session->flash(t('Link added successfully.'));
+ if ($ajax) {
+ $this->response->redirect($this->helper->url('board', 'show', array('project_id' => $task['project_id'])));
+ }
$this->response->redirect($this->helper->url('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#links');
}
else {
diff --git a/app/Controller/Timetable.php b/app/Controller/Timetable.php
new file mode 100644
index 00000000..65edb44c
--- /dev/null
+++ b/app/Controller/Timetable.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Controller;
+
+use DateTime;
+
+/**
+ * Timetable controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Timetable extends User
+{
+ /**
+ * Display timetable for the user
+ *
+ * @access public
+ */
+ public function index()
+ {
+ $user = $this->getUser();
+ $from = $this->request->getStringParam('from', date('Y-m-d'));
+ $to = $this->request->getStringParam('to', date('Y-m-d', strtotime('next week')));
+ $timetable = $this->timetable->calculate($user['id'], new DateTime($from), new DateTime($to));
+
+ $this->response->html($this->layout('timetable/index', array(
+ 'user' => $user,
+ 'timetable' => $timetable,
+ 'values' => array(
+ 'from' => $from,
+ 'to' => $to,
+ 'controller' => 'timetable',
+ 'action' => 'index',
+ 'user_id' => $user['id'],
+ ),
+ )));
+ }
+}
diff --git a/app/Controller/Timetableday.php b/app/Controller/Timetableday.php
new file mode 100644
index 00000000..eea44ae1
--- /dev/null
+++ b/app/Controller/Timetableday.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Day Timetable controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Timetableday extends User
+{
+ /**
+ * Display timetable for the user
+ *
+ * @access public
+ */
+ public function index(array $values = array(), array $errors = array())
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout('timetable_day/index', array(
+ 'timetable' => $this->timetableDay->getByUser($user['id']),
+ 'values' => $values + array('user_id' => $user['id']),
+ 'errors' => $errors,
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Validate and save
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->timetableDay->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->timetableDay->create($values['user_id'], $values['start'], $values['end'])) {
+ $this->session->flash(t('Time slot created successfully.'));
+ $this->response->redirect($this->helper->url('timetableday', 'index', array('user_id' => $values['user_id'])));
+ }
+ else {
+ $this->session->flashError(t('Unable to save this time slot.'));
+ }
+ }
+
+ $this->index($values, $errors);
+ }
+
+ /**
+ * Confirmation dialag box to remove a row
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout('timetable_day/remove', array(
+ 'slot_id' => $this->request->getIntegerParam('slot_id'),
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Remove a row
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $user = $this->getUser();
+
+ if ($this->timetableDay->remove($this->request->getIntegerParam('slot_id'))) {
+ $this->session->flash(t('Time slot removed successfully.'));
+ }
+ else {
+ $this->session->flash(t('Unable to remove this time slot.'));
+ }
+
+ $this->response->redirect($this->helper->url('timetableday', 'index', array('user_id' => $user['id'])));
+ }
+}
diff --git a/app/Controller/Timetableextra.php b/app/Controller/Timetableextra.php
new file mode 100644
index 00000000..7c6fe265
--- /dev/null
+++ b/app/Controller/Timetableextra.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Over-time Timetable controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Timetableextra extends Timetableoff
+{
+ protected $model = 'timetableExtra';
+ protected $controller_url = 'timetableextra';
+ protected $template_dir = 'timetable_extra';
+}
diff --git a/app/Controller/Timetableoff.php b/app/Controller/Timetableoff.php
new file mode 100644
index 00000000..19a6fab1
--- /dev/null
+++ b/app/Controller/Timetableoff.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Time-off Timetable controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Timetableoff extends User
+{
+ protected $model = 'timetableOff';
+ protected $controller_url = 'timetableoff';
+ protected $template_dir = 'timetable_off';
+
+ /**
+ * Display timetable for the user
+ *
+ * @access public
+ */
+ public function index(array $values = array(), array $errors = array())
+ {
+ $user = $this->getUser();
+
+ $paginator = $this->paginator
+ ->setUrl($this->controller_url, 'index', array('user_id' => $user['id']))
+ ->setMax(10)
+ ->setOrder('date')
+ ->setDirection('desc')
+ ->setQuery($this->{$this->model}->getUserQuery($user['id']))
+ ->calculate();
+
+ $this->response->html($this->layout($this->template_dir.'/index', array(
+ 'values' => $values + array('user_id' => $user['id']),
+ 'errors' => $errors,
+ 'paginator' => $paginator,
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Validate and save
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->{$this->model}->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->{$this->model}->create(
+ $values['user_id'],
+ $values['date'],
+ isset($values['all_day']) && $values['all_day'] == 1,
+ $values['start'],
+ $values['end'],
+ $values['comment'])) {
+
+ $this->session->flash(t('Time slot created successfully.'));
+ $this->response->redirect($this->helper->url($this->controller_url, 'index', array('user_id' => $values['user_id'])));
+ }
+ else {
+ $this->session->flashError(t('Unable to save this time slot.'));
+ }
+ }
+
+ $this->index($values, $errors);
+ }
+
+ /**
+ * Confirmation dialag box to remove a row
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout($this->template_dir.'/remove', array(
+ 'slot_id' => $this->request->getIntegerParam('slot_id'),
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Remove a row
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $user = $this->getUser();
+
+ if ($this->{$this->model}->remove($this->request->getIntegerParam('slot_id'))) {
+ $this->session->flash(t('Time slot removed successfully.'));
+ }
+ else {
+ $this->session->flash(t('Unable to remove this time slot.'));
+ }
+
+ $this->response->redirect($this->helper->url($this->controller_url, 'index', array('user_id' => $user['id'])));
+ }
+}
diff --git a/app/Controller/Timetableweek.php b/app/Controller/Timetableweek.php
new file mode 100644
index 00000000..829f4402
--- /dev/null
+++ b/app/Controller/Timetableweek.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Controller;
+
+/**
+ * Week Timetable controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Timetableweek extends User
+{
+ /**
+ * Display timetable for the user
+ *
+ * @access public
+ */
+ public function index(array $values = array(), array $errors = array())
+ {
+ $user = $this->getUser();
+
+ if (empty($values)) {
+
+ $day = $this->timetableDay->getByUser($user['id']);
+
+ $values = array(
+ 'user_id' => $user['id'],
+ 'start' => isset($day[0]['start']) ? $day[0]['start'] : null,
+ 'end' => isset($day[0]['end']) ? $day[0]['end'] : null,
+ );
+ }
+
+ $this->response->html($this->layout('timetable_week/index', array(
+ 'timetable' => $this->timetableWeek->getByUser($user['id']),
+ 'values' => $values,
+ 'errors' => $errors,
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Validate and save
+ *
+ * @access public
+ */
+ public function save()
+ {
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->timetableWeek->validateCreation($values);
+
+ if ($valid) {
+
+ if ($this->timetableWeek->create($values['user_id'], $values['day'], $values['start'], $values['end'])) {
+ $this->session->flash(t('Time slot created successfully.'));
+ $this->response->redirect($this->helper->url('timetableweek', 'index', array('user_id' => $values['user_id'])));
+ }
+ else {
+ $this->session->flashError(t('Unable to save this time slot.'));
+ }
+ }
+
+ $this->index($values, $errors);
+ }
+
+ /**
+ * Confirmation dialag box to remove a row
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $user = $this->getUser();
+
+ $this->response->html($this->layout('timetable_week/remove', array(
+ 'slot_id' => $this->request->getIntegerParam('slot_id'),
+ 'user' => $user,
+ )));
+ }
+
+ /**
+ * Remove a row
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $user = $this->getUser();
+
+ if ($this->timetableWeek->remove($this->request->getIntegerParam('slot_id'))) {
+ $this->session->flash(t('Time slot removed successfully.'));
+ }
+ else {
+ $this->session->flash(t('Unable to remove this time slot.'));
+ }
+
+ $this->response->redirect($this->helper->url('timetableweek', 'index', array('user_id' => $user['id'])));
+ }
+}
diff --git a/app/Controller/User.php b/app/Controller/User.php
index decdb646..46d0214d 100644
--- a/app/Controller/User.php
+++ b/app/Controller/User.php
@@ -69,12 +69,12 @@ class User extends Base
/**
* Common layout for user views
*
- * @access private
+ * @access protected
* @param string $template Template name
* @param array $params Template parameters
* @return string
*/
- private function layout($template, array $params)
+ protected function layout($template, array $params)
{
$content = $this->template->render($template, $params);
$params['user_content_for_layout'] = $content;
@@ -90,10 +90,10 @@ class User extends Base
/**
* Common method to get the user
*
- * @access private
+ * @access protected
* @return array
*/
- private function getUser()
+ protected function getUser()
{
$user = $this->user->getById($this->request->getIntegerParam('user_id'));
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 01ebb08f..34a5e6ab 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -677,4 +677,97 @@ class Helper
array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'redirect' => $redirect)
);
}
+
+ /**
+ * Get all hours for day
+ *
+ * @access public
+ * @return array
+ */
+ public function getDayHours()
+ {
+ $values = array();
+
+ foreach (range(0, 23) as $hour) {
+ foreach (array(0, 30) as $minute) {
+ $time = sprintf('%02d:%02d', $hour, $minute);
+ $values[$time] = $time;
+ }
+ }
+
+ return $values;
+ }
+
+ /**
+ * Get all days of a week
+ *
+ * @access public
+ * @return array
+ */
+ public function getWeekDays()
+ {
+ $values = array();
+
+ foreach (range(1, 7) as $day) {
+ $values[$day] = $this->getWeekDay($day);
+ }
+
+ return $values;
+ }
+
+ /**
+ * Get the localized day name from the day number
+ *
+ * @access public
+ * @param integer $day Day number
+ * @return string
+ */
+ public function getWeekDay($day)
+ {
+ return dt('%A', strtotime('next Monday +'.($day - 1).' days'));
+ }
+
+ /**
+ * Get file icon
+ *
+ * @access public
+ * @param string $filename Filename
+ * @return string Font-Awesome-Icon-Name
+ */
+ public function getFileIcon($filename){
+
+ $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ switch ($extension) {
+ case 'jpeg':
+ case 'jpg':
+ case 'png':
+ case 'gif':
+ return 'fa-file-image-o';
+ case 'xls':
+ case 'xlsx':
+ return 'fa-file-excel-o';
+ case 'doc':
+ case 'docx':
+ return 'fa-file-word-o';
+ case 'ppt':
+ case 'pptx':
+ return 'fa-file-powerpoint-o';
+ case 'zip':
+ case 'rar':
+ return 'fa-archive-o';
+ case 'mp3':
+ return 'fa-audio-o';
+ case 'avi':
+ return 'fa-video-o';
+ case 'php':
+ case 'html':
+ case 'css':
+ return 'fa-code-o';
+ case 'pdf':
+ return 'fa-file-pdf-o';
+ }
+
+ return 'fa-file-o';
+ }
}
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 75f27a7c..1732e7bb 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Ingen',
'edit' => 'rediger',
'Edit' => 'Rediger',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 54503b64..3ab31d97 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Keines',
'edit' => 'Bearbeiten',
'Edit' => 'Bearbeiten',
@@ -625,8 +627,8 @@ return array(
'Example: "Bug, Feature Request, Improvement"' => 'Beispiel: "Bug, Funktionswünsche, Verbesserung"',
'Default categories for new projects (Comma-separated)' => 'Standard Kategorien für neue Projekte (Komma-getrennt)',
'Gitlab commit received' => 'Gitlab commit erhalten',
- 'Gitlab issue opened' => 'Gitlab Thema eröffnet',
- 'Gitlab issue closed' => 'Gitlab Thema geschlossen',
+ 'Gitlab issue opened' => 'Gitlab Fehler eröffnet',
+ 'Gitlab issue closed' => 'Gitlab Fehler geschlossen',
'Gitlab webhooks' => 'Gitlab Webhook',
'Help on Gitlab webhooks' => 'Hilfe für Gitlab Webhooks',
'Integrations' => 'Integration',
@@ -635,7 +637,7 @@ return array(
'Project manager' => 'Projektmanager',
'Project member' => 'Projektmitglied',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Ein Projektmanager kann die Projekteinstellungen ändern und hat mehr Rechte als ein normaler Benutzer.',
- 'Gitlab Issue' => 'Gitlab Thema',
+ 'Gitlab Issue' => 'Gitlab Fehler',
'Subtask Id' => 'Teilaufgaben Id',
'Subtasks' => 'Teilaufgaben',
'Subtasks Export' => 'Teilaufgaben Export',
@@ -734,4 +736,72 @@ return array(
'Filter recently updated' => 'Zuletzt geänderte anzeigen',
'since %B %e, %Y at %k:%M %p' => 'seit %B %e, %Y um %k:%M %p',
'More filters' => 'Mehr Filter',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 3981f12d..f186dfc8 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Ninguno',
'edit' => 'modificar',
'Edit' => 'Modificar',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 06b21953..f235cc12 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Ei mikään',
'edit' => 'muokkaa',
'Edit' => 'Muokkaa',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index b05f7076..1aadb393 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ 'number.decimals_separator' => ',',
+ 'number.thousands_separator' => ' ',
'None' => 'Aucun',
'edit' => 'modifier',
'Edit' => 'Modifier',
@@ -736,4 +738,72 @@ return array(
'Filter recently updated' => 'Récemment modifié',
'since %B %e, %Y at %k:%M %p' => 'depuis le %d/%m/%Y à %H:%M',
'More filters' => 'Plus de filtres',
+ 'Compact view' => 'Vue compacte',
+ 'Horizontal scrolling' => 'Défilement horizontal',
+ 'Compact/wide view' => 'Basculer entre la vue compacte et étendue',
+ 'No results match:' => 'Aucun résultat :',
+ 'Remove hourly rate' => 'Supprimer un taux horaire',
+ 'Do you really want to remove this hourly rate?' => 'Voulez-vous vraiment supprimer ce taux horaire ?',
+ 'Hourly rates' => 'Taux horaires',
+ 'Hourly rate' => 'Taux horaire',
+ 'Currency' => 'Devise',
+ 'Effective date' => 'Date d\'effet',
+ 'Add new rate' => 'Ajouter un nouveau taux horaire',
+ 'Rate removed successfully.' => 'Taux horaire supprimé avec succès.',
+ 'Unable to remove this rate.' => 'Impossible de supprimer ce taux horaire.',
+ 'Unable to save the hourly rate.' => 'Impossible de sauvegarder ce taux horaire.',
+ 'Hourly rate created successfully.' => 'Taux horaire créé avec succès.',
+ 'Start time' => 'Date de début',
+ 'End time' => 'Date de fin',
+ 'Comment' => 'Commentaire',
+ 'All day' => 'Toute la journée',
+ 'Day' => 'Jour',
+ 'Manage timetable' => 'Gérer les horaires',
+ 'Overtime timetable' => 'Heures supplémentaires',
+ 'Time off timetable' => 'Heures d\'absences',
+ 'Timetable' => 'Horaires',
+ 'Work timetable' => 'Horaires travaillés',
+ 'Week timetable' => 'Horaires de la semaine',
+ 'Day timetable' => 'Horaire d\'une journée',
+ 'From' => 'Depuis',
+ 'To' => 'À',
+ 'Time slot created successfully.' => 'Créneau horaire créé avec succès.',
+ 'Unable to save this time slot.' => 'Impossible de sauvegarder ce créneau horaire.',
+ 'Time slot removed successfully.' => 'Créneau horaire supprimé avec succès.',
+ 'Unable to remove this time slot.' => 'Impossible de supprimer ce créneau horaire.',
+ 'Do you really want to remove this time slot?' => 'Voulez-vous vraiment supprimer ce créneau horaire ?',
+ 'Remove time slot' => 'Supprimer un créneau horaire',
+ 'Add new time slot' => 'Ajouter un créneau horaire',
+ 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ces horaires sont utilisés lorsque la case « Toute la journée » est cochée pour les heures d\'absences ou supplémentaires programmées.',
+ 'Files' => 'Fichiers',
+ 'Images' => 'Images',
+ 'Private project' => 'Projet privé',
+ 'Amount' => 'Montant',
+ 'AUD - Australian Dollar' => 'AUD - Dollar australien',
+ 'Budget' => 'Budget',
+ 'Budget line' => 'Ligne budgétaire',
+ 'Budget line removed successfully.' => 'Ligne budgétaire supprimée avec succès.',
+ 'Budget lines' => 'Lignes budgétaire',
+ 'CAD - Canadian Dollar' => 'CAD - Dollar canadien',
+ 'CHF - Swiss Francs' => 'CHF - Franc suisse',
+ 'Cost' => 'Coût',
+ 'Cost breakdown' => 'Détail des coûts',
+ 'Custom Stylesheet' => 'Feuille de style personalisée',
+ 'download' => 'télécharger',
+ 'Do you really want to remove this budget line?' => 'Voulez-vous vraiment supprimer cette ligne budgétaire ?',
+ 'EUR - Euro' => 'EUR - Euro',
+ 'Expenses' => 'Dépenses',
+ 'GBP - British Pound' => 'GBP - Livre sterling',
+ 'INR - Indian Rupee' => 'INR - Roupie indienne',
+ 'JPY - Japanese Yen' => 'JPY - Yen',
+ 'New budget line' => 'Nouvelle ligne budgétaire',
+ 'NZD - New Zealand Dollar' => 'NZD - Dollar néo-zélandais',
+ 'Remove a budget line' => 'Supprimer une ligne budgétaire',
+ 'Remove budget line' => 'Supprimer une ligne budgétaire',
+ 'RSD - Serbian dinar' => 'RSD - Dinar serbe',
+ 'The budget line have been created successfully.' => 'La ligne de budgétaire a été créee avec succès.',
+ 'Unable to create the budget line.' => 'Impossible de créer cette ligne budgétaire.',
+ 'Unable to remove this budget line.' => 'Impossible de supprimer cette ligne budgétaire.',
+ 'USD - US Dollar' => 'USD - Dollar américain',
+ 'Remaining' => 'Restant',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 1780505f..75cdbebc 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Nincs',
'edit' => 'szerkesztés',
'Edit' => 'Szerkesztés',
@@ -104,7 +106,7 @@ return array(
'Open a task' => 'Feladat felnyitás',
'Do you really want to open this task: "%s"?' => 'Tényleg meg akarja nyitni ezt a feladatot: "%s"?',
'Back to the board' => 'Vissza a táblához',
- 'Created on %B %e, %Y at %k:%M %p' => 'Létrehozva: %Y.%m.%d %H:%M',
+ 'Created on %B %e, %Y at %k:%M %p' => 'Létrehozva: %Y. %m. %d. %H:%M',
'There is nobody assigned' => 'Nincs felelős',
'Column on the board:' => 'Tábla oszlopa: ',
'Status is open' => 'Nyitott állapot',
@@ -133,12 +135,12 @@ return array(
'The title is required' => 'A címet meg kell adni',
'The language is required' => 'A nyelvet meg kell adni',
'There is no active project, the first step is to create a new project.' => 'Nincs aktív projekt. Először létre kell hozni egy projektet.',
- 'Settings saved successfully.' => 'A beállítások mentése sikeres.',
+ 'Settings saved successfully.' => 'A beállítások sikeresen mentve.',
'Unable to save your settings.' => 'A beállítások mentése sikertelen.',
'Database optimization done.' => 'Adatbázis optimalizálás kész.',
'Your project have been created successfully.' => 'Projekt sikeresen létrehozva',
'Unable to create your project.' => 'Projekt létrehozása sikertelen.',
- 'Project updated successfully.' => 'Projekt frissítése sikeres.',
+ 'Project updated successfully.' => 'Projekt sikeresen frissítve.',
'Unable to update this project.' => 'Projekt frissítése sikertelen.',
'Unable to remove this project.' => 'Projekt törlése sikertelen.',
'Project removed successfully.' => 'Projekt sikeresen törölve.',
@@ -146,7 +148,7 @@ return array(
'Unable to activate this project.' => 'Projekt aktiválása sikertelen.',
'Project disabled successfully.' => 'Projekt sikeresen letiltva.',
'Unable to disable this project.' => 'Projekt letiltása sikertelen.',
- 'Unable to open this task.' => 'A feladat felnyitása nem sikerült.',
+ 'Unable to open this task.' => 'A feladat felnyitása sikertelen.',
'Task opened successfully.' => 'Feladat sikeresen megnyitva .',
'Unable to close this task.' => 'A feladat lezárása sikertelen.',
'Task closed successfully.' => 'Feladat sikeresen lezárva.',
@@ -166,8 +168,8 @@ return array(
'Work in progress' => 'Folyamatban',
'Done' => 'Kész',
'Application version:' => 'Alkalmazás verzió:',
- 'Completed on %B %e, %Y at %k:%M %p' => 'Elkészült %Y.%m.%d %H:%M ..',
- '%B %e, %Y at %k:%M %p' => '%Y.%m.%d %H:%M',
+ 'Completed on %B %e, %Y at %k:%M %p' => 'Elkészült: %Y. %m. %d. %H:%M',
+ '%B %e, %Y at %k:%M %p' => '%Y. %m. %d. %H:%M',
'Date created' => 'Létrehozás időpontja',
'Date completed' => 'Befejezés időpontja',
'Id' => 'ID',
@@ -211,9 +213,9 @@ return array(
'Edit this task' => 'Feladat módosítása',
'Due Date' => 'Határidő',
'Invalid date' => 'Érvénytelen dátum',
- 'Must be done before %B %e, %Y' => 'Kész kell lennie %Y.%m.%d előtt',
- '%B %e, %Y' => '%Y.%m.%d',
- '%b %e, %Y' => '%Y.%m.%d',
+ 'Must be done before %B %e, %Y' => 'Kész kell lennie %Y. %m. %d. előtt',
+ '%B %e, %Y' => '%Y. %m. %d.',
+ '%b %e, %Y' => '%Y. %m. %d.',
'Automatic actions' => 'Automatikus intézkedések',
'Your automatic action have been created successfully.' => 'Az automatikus intézkedés sikeresen elkészült.',
'Unable to create your automatic action.' => 'Automatikus intézkedés létrehozása nem lehetséges.',
@@ -254,7 +256,7 @@ return array(
'link' => 'link',
'Update this comment' => 'Hozzászólás frissítése',
'Comment updated successfully.' => 'Megjegyzés sikeresen frissítve.',
- 'Unable to update your comment.' => 'Megjegyzés frissítése nem sikerült.',
+ 'Unable to update your comment.' => 'Megjegyzés frissítése sikertelen.',
'Remove a comment' => 'Megjegyzés törlése',
'Comment removed successfully.' => 'Megjegyzés sikeresen törölve.',
'Unable to remove this comment.' => 'Megjegyzés törölése nem lehetséges.',
@@ -294,8 +296,8 @@ return array(
'Your Google Account is not linked anymore to your profile.' => 'Google Fiók már nincs a profilhoz kapcsolva.',
'Unable to unlink your Google Account.' => 'Leválasztás a Google fiókról nem lehetséges.',
'Google authentication failed' => 'Google azonosítás sikertelen',
- 'Unable to link your Google Account.' => 'Google profilhoz kapcsolás nem sikerült.',
- 'Your Google Account is linked to your profile successfully.' => 'Sikeresen összekapcsolva a Google fiókkal.',
+ 'Unable to link your Google Account.' => 'A Google profilhoz kapcsolás sikertelen.',
+ 'Your Google Account is linked to your profile successfully.' => 'Google fiókkal sikeresen összekapcsolva.',
'Email' => 'E-mail',
'Link my Google Account' => 'Kapcsold össze a Google fiókkal',
'Unlink my Google Account' => 'Válaszd le a Google fiókomat',
@@ -377,7 +379,7 @@ return array(
'Link my GitHub Account' => 'GitHub fiók csatolása',
'Unlink my GitHub Account' => 'GitHub fiók leválasztása',
'Created by %s' => 'Készítette: %s',
- 'Last modified on %B %e, %Y at %k:%M %p' => 'Utolsó módosítás: %Y.%m.%d %H:%M',
+ 'Last modified on %B %e, %Y at %k:%M %p' => 'Utolsó módosítás: %Y. %m. %d. %H:%M',
'Tasks Export' => 'Feladatok exportálása',
'Tasks exportation for "%s"' => 'Feladatok exportálása: "%s"',
'Start Date' => 'Kezdés dátuma',
@@ -391,7 +393,7 @@ return array(
'Webhook URL for task modification' => 'Webhook URL a feladatot módosításakor',
'Clone' => 'Másolat',
'Clone Project' => 'Projekt másolása',
- 'Project cloned successfully.' => 'A projekt másolása sikeres',
+ 'Project cloned successfully.' => 'A projekt sikeresen másolva.',
'Unable to clone this project.' => 'A projekt másolása sikertelen.',
'Email notifications' => 'E-mail értesítések',
'Enable email notifications' => 'E-mail értesítések engedélyezése',
@@ -541,7 +543,7 @@ return array(
'Add' => 'Hozzáadás',
'Estimated time: %s hours' => 'Becsült idő: %s óra',
'Time spent: %s hours' => 'Eltöltött idő: %s óra',
- 'Started on %B %e, %Y' => 'Elkezdve: %Y.%m.%d',
+ 'Started on %B %e, %Y' => 'Elkezdve: %Y. %m. %d.',
'Start date' => 'Kezdés dátuma',
'Time estimated' => 'Becsült időtartam',
'There is nothing assigned to you.' => 'Nincs kiosztott feladat.',
@@ -670,7 +672,7 @@ return array(
'Time Tracking' => 'Idő követés',
'You already have one subtask in progress' => 'Már van egy folyamatban levő részfeladata',
'Which parts of the project do you want to duplicate?' => 'A projekt mely részeit szeretné duplikálni?',
- 'Change dashboard view' => 'Vezérlőpult megjelenítés változtatás',
+ 'Change dashboard view' => 'Vezérlőpult megjelenés változtatás',
'Show/hide activities' => 'Tevékenységek megjelenítése/elrejtése',
'Show/hide projects' => 'Projektek megjelenítése/elrejtése',
'Show/hide subtasks' => 'Részfeladatok megjelenítése/elrejtése',
@@ -730,8 +732,76 @@ return array(
'Board view' => 'Tábla nézet',
'Keyboard shortcuts' => 'Billentyű kombináció',
'Open board switcher' => 'Tábla választó lenyitása',
- // 'Application' => '',
- // 'Filter recently updated' => '',
- // 'since %B %e, %Y at %k:%M %p' => '',
- // 'More filters' => '',
+ 'Application' => 'Alkalmazás',
+ 'Filter recently updated' => 'Szűrés az utolsó módosítás ideje szerint',
+ 'since %B %e, %Y at %k:%M %p' => '%Y. %m. %d. %H:%M óta',
+ 'More filters' => 'További szűrők',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 525c828b..d5fd6902 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Nessuno',
'edit' => 'modificare',
'Edit' => 'Modificare',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index 90af6a02..6e3c14c8 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'なし',
'edit' => '変更',
'Edit' => '変更',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
new file mode 100644
index 00000000..2b434d53
--- /dev/null
+++ b/app/Locale/nl_NL/translations.php
@@ -0,0 +1,807 @@
+<?php
+
+return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
+ 'None' => 'Geen',
+ 'edit' => 'bewerken',
+ 'Edit' => 'Bewerken',
+ 'remove' => 'verwijderen',
+ 'Remove' => 'Verwijderen',
+ 'Update' => 'Update',
+ 'Yes' => 'Ja',
+ 'No' => 'Nee',
+ 'cancel' => 'annuleren',
+ 'or' => 'of',
+ 'Yellow' => 'Geel',
+ 'Blue' => 'Blauw',
+ 'Green' => 'Groen',
+ 'Purple' => 'Paars',
+ 'Red' => 'Rood',
+ 'Orange' => 'Oranje',
+ 'Grey' => 'Grijs',
+ 'Save' => 'Opslaan',
+ 'Login' => 'Inloggen',
+ 'Official website:' => 'Officiële website :',
+ 'Unassigned' => 'Niet toegewezen',
+ 'View this task' => 'Deze taak bekijken',
+ 'Remove user' => 'Gebruiker verwijderen',
+ 'Do you really want to remove this user: "%s"?' => 'Weet u zeker dat u deze gebruiker wil verwijderen : « %s » ?',
+ 'New user' => 'Nieuwe gebruiker',
+ 'All users' => 'Alle gebruikers',
+ 'Username' => 'Gebruikersnaam',
+ 'Password' => 'Wachtwoord',
+ 'Default project' => 'Standaard wachtwoord',
+ 'Administrator' => 'Administrator',
+ 'Sign in' => 'Inloggen',
+ 'Users' => 'Gebruikers',
+ 'No user' => 'Geen gebruiker',
+ 'Forbidden' => 'Geweigerd',
+ 'Access Forbidden' => 'Toegang geweigerd',
+ 'Only administrators can access to this page.' => 'Alleen administrators hebben toegang tot deze pagina.',
+ 'Edit user' => 'Gebruiker bewerken',
+ 'Logout' => 'Uitloggen',
+ 'Bad username or password' => 'Verkeerde gebruikersnaam of wachtwoord',
+ 'users' => 'gebruikers',
+ 'projects' => 'projecten',
+ 'Edit project' => 'Project bewerken',
+ 'Name' => 'Naam',
+ 'Activated' => 'Geactiveerd',
+ 'Projects' => 'Projecten',
+ 'No project' => 'Geen project',
+ 'Project' => 'Project',
+ 'Status' => 'Status',
+ 'Tasks' => 'Taken',
+ 'Board' => 'Bord',
+ 'Actions' => 'Acties',
+ 'Inactive' => 'Inactief',
+ 'Active' => 'Actief',
+ 'Column %d' => 'Kolom %d',
+ 'Add this column' => 'Deze kolom toevoegen',
+ '%d tasks on the board' => '%d taken op het bord',
+ '%d tasks in total' => '%d taken in totaal',
+ 'Unable to update this board.' => 'Update van dit bord niet mogelijk.',
+ 'Edit board' => 'Bord bewerken',
+ 'Disable' => 'Deactiveren',
+ 'Enable' => 'Activeren',
+ 'New project' => 'Nieuw project',
+ 'Do you really want to remove this project: "%s"?' => 'Weet u zeker dat u dit project wil verwijderen : « %s » ?',
+ 'Remove project' => 'Project verwijderen',
+ 'Boards' => 'Borden',
+ 'Edit the board for "%s"' => 'Bord bewerken voor « %s »',
+ 'All projects' => 'Alle projecten',
+ 'Change columns' => 'Kolommen veranderen',
+ 'Add a new column' => 'Kolom toevoegen',
+ 'Title' => 'Titel',
+ 'Add Column' => 'Kolom toevoegen',
+ 'Project "%s"' => 'Project « %s »',
+ 'Nobody assigned' => 'Niemand toegewezen',
+ 'Assigned to %s' => 'Toegewezen aan %s',
+ 'Remove a column' => 'Kolom verwijderen',
+ 'Remove a column from a board' => 'Kolom verwijderen van het bord',
+ 'Unable to remove this column.' => 'Verwijderen van deze kolom niet mogelijk.',
+ 'Do you really want to remove this column: "%s"?' => 'Weet u zeker dat u deze kolom wil verwijderen : « %s » ?',
+ 'This action will REMOVE ALL TASKS associated to this column!' => 'Deze actie zal ALLE TAKEN VERWIJDEREN die zijn geassocieerd met deze kolom!',
+ 'Settings' => 'Instellingen',
+ 'Application settings' => 'Applicatie instellingen',
+ 'Language' => 'Taal',
+ 'Webhook token:' => 'Webhook token :',
+ 'API token:' => 'API token :',
+ 'More information' => 'Meer informatie',
+ 'Database size:' => 'Database grootte :',
+ 'Download the database' => 'Download de database',
+ 'Optimize the database' => 'Optimaliseer de database',
+ '(VACUUM command)' => '(VACUUM commando)',
+ '(Gzip compressed Sqlite file)' => '(Gzip ingepakt Sqlite bestand)',
+ 'User settings' => 'Gebruikers instellingen',
+ 'My default project:' => 'Mijn standaard project : ',
+ 'Close a task' => 'Taak sluiten',
+ 'Do you really want to close this task: "%s"?' => 'Weet u zeker dat u deze taak wil sluiten : « %s » ?',
+ 'Edit a task' => 'Taak bewerken',
+ 'Column' => 'Kolom',
+ 'Color' => 'Kleur',
+ 'Assignee' => 'Toegewezene',
+ 'Create another task' => 'Nog een taak aanmaken',
+ 'New task' => 'Nieuwe taak',
+ 'Open a task' => 'Een taak openen',
+ 'Do you really want to open this task: "%s"?' => 'Weet u zeker dat u deze taak wil openen : « %s » ?',
+ 'Back to the board' => 'Terug naar het bord',
+ 'Created on %B %e, %Y at %k:%M %p' => 'Aangemaakt op %d/%m/%Y à %H:%M',
+ 'There is nobody assigned' => 'Er is niemand toegewezen',
+ 'Column on the board:' => 'Kolom op het bord : ',
+ 'Status is open' => 'Status is open',
+ 'Status is closed' => 'Status is gesloten',
+ 'Close this task' => 'Deze taak sluiten',
+ 'Open this task' => 'Deze taak openen',
+ 'There is no description.' => 'Er is geen omschrijving.',
+ 'Add a new task' => 'Een nieuwe taak toevoegen',
+ 'The username is required' => 'De gebruikersnaam is verplicht',
+ 'The maximum length is %d characters' => 'De maximale lengte is %d karakters',
+ 'The minimum length is %d characters' => 'De minimale lengte is %d karakters',
+ 'The password is required' => 'Het wachtwoord is verplicht',
+ 'This value must be an integer' => 'Deze waarde dient een integer te zijn',
+ 'The username must be unique' => 'De gebruikersnaam moet uniek zijn',
+ 'The username must be alphanumeric' => 'De gebruikersnaam moet alfanumeriek zijn',
+ 'The user id is required' => 'Het gebruikers id is verplicht',
+ 'Passwords don\'t match' => 'De wachtwoorden komen niet overeen',
+ 'The confirmation is required' => 'De bevestiging is verplicht',
+ 'The column is required' => 'De kolom is verplicht',
+ 'The project is required' => 'Het project is verplicht',
+ 'The color is required' => 'De kleur is verplicht',
+ 'The id is required' => 'Het id is verplicht',
+ 'The project id is required' => 'Het project id is verplicht',
+ 'The project name is required' => 'De projectnaam is verplicht',
+ 'This project must be unique' => 'Dit project moet uniek zijn',
+ 'The title is required' => 'De titel is verplicht',
+ 'The language is required' => 'De taal is verplicht',
+ 'There is no active project, the first step is to create a new project.' => 'Er is geen actief project, de eerste stap is een nieuw project aanmaken.',
+ 'Settings saved successfully.' => 'Instellingen succesvol opgeslagen.',
+ 'Unable to save your settings.' => 'Instellingen opslaan niet gelukt.',
+ 'Database optimization done.' => 'Database optimaliseren voltooid.',
+ 'Your project have been created successfully.' => 'Uw project is succesvol aangemaakt.',
+ 'Unable to create your project.' => 'Het aanmaken van het project is niet gelukt.',
+ 'Project updated successfully.' => 'Project succesvol geupdate.',
+ 'Unable to update this project.' => 'Updaten van project niet gelukt.',
+ 'Unable to remove this project.' => 'Verwijderen van project niet gelukt.',
+ 'Project removed successfully.' => 'Project succesvol verwijderd.',
+ 'Project activated successfully.' => 'Project succesvol geactiveerd.',
+ 'Unable to activate this project.' => 'Project activeren niet gelukt.',
+ 'Project disabled successfully.' => 'Project uitschakelen succesvol.',
+ 'Unable to disable this project.' => 'Project uitschakelen niet gelukt.',
+ 'Unable to open this task.' => 'Openen van deze taak niet gelukt.',
+ 'Task opened successfully.' => 'Taak succesvol geopend.',
+ 'Unable to close this task.' => 'Sluiten van deze taak niet gelukt.',
+ 'Task closed successfully.' => 'Taak succesvol gesloten.',
+ 'Unable to update your task.' => 'Updaten van uw taak mislukt.',
+ 'Task updated successfully.' => 'Taak succesvol geupdate.',
+ 'Unable to create your task.' => 'Taak aanmaken niet gelukt.',
+ 'Task created successfully.' => 'Taak succesvol aangemaakt.',
+ 'User created successfully.' => 'Gebruiker succesvol aangemaakt.',
+ 'Unable to create your user.' => 'Aanmaken van gebruiker niet gelukt.',
+ 'User updated successfully.' => 'Gebruiker succesvol geupdate',
+ 'Unable to update your user.' => 'Updaten van gebruiker niet gelukt.',
+ 'User removed successfully.' => 'Gebruiker succesvol verwijderd.',
+ 'Unable to remove this user.' => 'Verwijderen van gebruikers niet gelukt.',
+ 'Board updated successfully.' => 'Board succesvol geupdate.',
+ 'Ready' => 'Klaar',
+ 'Backlog' => 'En attente',
+ 'Work in progress' => 'In behandeling',
+ 'Done' => 'Klaar',
+ 'Application version:' => 'Applicatie versie :',
+ 'Completed on %B %e, %Y at %k:%M %p' => 'Voltooid op %d/%m/%Y à %H:%M',
+ '%B %e, %Y at %k:%M %p' => '%d/%m/%Y op %H:%M',
+ 'Date created' => 'Datum aangemaakt',
+ 'Date completed' => 'Datum voltooid',
+ 'Id' => 'Id',
+ 'No task' => 'Geen taak',
+ 'Completed tasks' => 'Voltooide taken',
+ 'List of projects' => 'Lijst van projecten',
+ 'Completed tasks for "%s"' => 'Vooltooide taken voor « %s »',
+ '%d closed tasks' => '%d gesloten taken',
+ 'No task for this project' => 'Geen taken voor dit project',
+ 'Public link' => 'Publieke link',
+ 'There is no column in your project!' => 'Er is geen kolom in uw project !',
+ 'Change assignee' => 'Toegewezene aanpassen',
+ 'Change assignee for the task "%s"' => 'Toegewezene aanpassen voor taak « %s »',
+ 'Timezone' => 'Tijdzone',
+ 'Sorry, I didn\'t find this information in my database!' => 'Sorry deze informatie kon niet worden gevonden in de database !',
+ 'Page not found' => 'Pagina niet gevonden',
+ 'Complexity' => 'Complexiteit',
+ 'limit' => 'Limiet',
+ 'Task limit' => 'Taak limiet.',
+ 'Task count' => 'Aantal taken',
+ 'This value must be greater than %d' => 'Deze waarde moet groter zijn dan %d',
+ 'Edit project access list' => 'Aanpassen toegangsrechten project',
+ 'Edit users access' => 'Gebruikerstoegang aanpassen',
+ 'Allow this user' => 'Deze gebruiker toestaan',
+ 'Only those users have access to this project:' => 'Alleen deze gebruikers hebben toegang tot dit project :',
+ 'Don\'t forget that administrators have access to everything.' => 'Vergeet niet dat administrators overal toegang hebben.',
+ 'Revoke' => 'Intrekken',
+ 'List of authorized users' => 'Lijst met geautoriseerde gebruikers',
+ 'User' => 'Gebruiker',
+ 'Nobody have access to this project.' => 'Niemand heeft toegang tot dit project',
+ 'You are not allowed to access to this project.' => 'U heeft geen toegang tot dit project.',
+ 'Comments' => 'Commentaar',
+ 'Post comment' => 'Commentaar toevoegen',
+ 'Write your text in Markdown' => 'Schrijf uw tekst in Markdown',
+ 'Leave a comment' => 'Schrijf een commentaar',
+ 'Comment is required' => 'Commentaar is verplicht',
+ 'Leave a description' => 'Schrijf een omschrijving',
+ 'Comment added successfully.' => 'Commentaar succesvol toegevoegd.',
+ 'Unable to create your comment.' => 'Commentaar toevoegen niet gelukt.',
+ 'The description is required' => 'Omschrijving is verplicht',
+ 'Edit this task' => 'Deze taak aanpassen',
+ 'Due Date' => 'Vervaldag',
+ 'Invalid date' => 'Ongeldige datum',
+ 'Must be done before %B %e, %Y' => 'Moet voltooid zijn voor %d/%m/%Y',
+ '%B %e, %Y' => '%d %B %Y',
+ '%b %e, %Y' => '%d/%m/%Y',
+ 'Automatic actions' => 'Geautomatiseerd acties',
+ 'Your automatic action have been created successfully.' => 'Geautomatiseerde actie succesvol aangemaakt.',
+ 'Unable to create your automatic action.' => 'Geautomatiseerde actie aanmaken niet gelukt.',
+ 'Remove an action' => 'Actie verwijderen',
+ 'Unable to remove this action.' => 'Actie verwijderen niet gelukt',
+ 'Action removed successfully.' => 'Actie succesvol verwijder.',
+ 'Automatic actions for the project "%s"' => 'Automatiseer acties voor project « %s »',
+ 'Defined actions' => 'Gedefinieerde acties',
+ 'Add an action' => 'Actie toevoegen',
+ 'Event name' => 'Naam gebeurtenis',
+ 'Action name' => 'Actie naam',
+ 'Action parameters' => 'Actie paramaters',
+ 'Action' => 'Actie',
+ 'Event' => 'Evenement',
+ 'When the selected event occurs execute the corresponding action.' => 'Als de geselecteerde gebeurtenis optreedt de volgende actie uitvoeren',
+ 'Next step' => 'Volgende stap',
+ 'Define action parameters' => 'Bepaal actie parameters',
+ 'Save this action' => 'Actie opslaan',
+ 'Do you really want to remove this action: "%s"?' => 'Weet u zeker dat u de volgende actie wil verwijderen : « %s » ?',
+ 'Remove an automatic action' => 'Automatische actie verwijderen',
+ 'Close the task' => 'Taak sluiten',
+ 'Assign the task to a specific user' => 'Taak toewijzen aan een gebruiker',
+ 'Assign the task to the person who does the action' => 'Taak toewijzen aan een gebruiker die de actie uitvoert',
+ 'Duplicate the task to another project' => 'Taak dupliceren in een ander project',
+ 'Move a task to another column' => 'Taak verplaatsen naar een andere kolom',
+ 'Move a task to another position in the same column' => 'Taak verplaatsen naar een andere positie in dezelfde kolom',
+ 'Task modification' => 'Taak aanpassen',
+ 'Task creation' => 'Taak aanmaken',
+ 'Open a closed task' => 'Gesloten taak openen',
+ 'Closing a task' => 'Taak sluiten',
+ 'Assign a color to a specific user' => 'Wijs een kleur toe aan een gebruiker',
+ 'Column title' => 'Kolom titel',
+ 'Position' => 'Positie',
+ 'Move Up' => 'Omhoog verplaatsen',
+ 'Move Down' => 'Omlaag verplaatsen',
+ 'Duplicate to another project' => 'Dupliceren in een ander project',
+ 'Duplicate' => 'Dupliceren',
+ 'link' => 'koppelen',
+ 'Update this comment' => 'Commentaar aanpassen',
+ 'Comment updated successfully.' => 'Commentaar succesvol aangepast.',
+ 'Unable to update your comment.' => 'Commentaar aanpassen niet gelukt.',
+ 'Remove a comment' => 'Commentaar verwijderen',
+ 'Comment removed successfully.' => 'Commentaar succesvol verwijder.',
+ 'Unable to remove this comment.' => 'Commentaar verwijderen niet gelukt.',
+ 'Do you really want to remove this comment?' => 'Weet u zeker dat u dit commentaar wil verwijderen ?',
+ 'Only administrators or the creator of the comment can access to this page.' => 'Alleen administrators of de aanmaker van het commentaar hebben toegang tot deze pagina.',
+ 'Details' => 'Details',
+ 'Current password for the user "%s"' => 'Huidig wachtwoord voor gebruiker « %s »',
+ 'The current password is required' => 'Huidig wachtwoord is verplicht',
+ 'Wrong password' => 'Onjuist wachtwoord',
+ 'Reset all tokens' => 'Alle tokens resetten',
+ 'All tokens have been regenerated.' => 'Alle tokens zijn opnieuw gegenereerd.',
+ 'Unknown' => 'Onbekend',
+ 'Last logins' => 'Laatste logins',
+ 'Login date' => 'Login datum',
+ 'Authentication method' => 'Authenticatie methode',
+ 'IP address' => 'IP adres',
+ 'User agent' => 'User agent',
+ 'Persistent connections' => 'Persistente connectie',
+ 'No session.' => 'Geen sessie.',
+ 'Expiration date' => 'Verloopdatum',
+ 'Remember Me' => 'Onthoud mij',
+ 'Creation date' => 'Aanmaakdatum',
+ 'Filter by user' => 'Filter op gebruiker',
+ 'Filter by due date' => 'Filter op vervaldatum',
+ 'Everybody' => 'Iedereen',
+ 'Open' => 'Open',
+ 'Closed' => 'Gesloten',
+ 'Search' => 'Zoek',
+ 'Nothing found.' => 'Niets gevonden.',
+ 'Search in the project "%s"' => 'Zoek in project « %s »',
+ 'Due date' => 'Vervaldatum',
+ 'Others formats accepted: %s and %s' => 'Andere toegestane formaten : %s en %s',
+ 'Description' => 'Omschrijving',
+ '%d comments' => '%d commentaren',
+ '%d comment' => '%d commentaar',
+ 'Email address invalid' => 'Ongeldig emailadres',
+ 'Your Google Account is not linked anymore to your profile.' => 'Uw Google Account is niet meer aan uw profiel gelinkt.',
+ 'Unable to unlink your Google Account.' => 'Verwijderen link met Google Account niet gelukt.',
+ 'Google authentication failed' => 'Google authenticatie niet gelukt',
+ 'Unable to link your Google Account.' => 'Linken met Google Account niet gelukt',
+ 'Your Google Account is linked to your profile successfully.' => 'Linken met Google Account succesvol.',
+ 'Email' => 'Email',
+ 'Link my Google Account' => 'Link mijn Google Account',
+ 'Unlink my Google Account' => 'Link met Google Account verwijderen',
+ 'Login with my Google Account' => 'Inloggen met mijn Google Account',
+ 'Project not found.' => 'Project niet gevonden.',
+ 'Task #%d' => 'Taak %d',
+ 'Task removed successfully.' => 'Taak succesvol verwijderd.',
+ 'Unable to remove this task.' => 'Taak verwijderen niet gelukt.',
+ 'Remove a task' => 'Taak verwijderen',
+ 'Do you really want to remove this task: "%s"?' => 'Weet u zeker dat u deze taak wil verwijderen « %s » ?',
+ 'Assign automatically a color based on a category' => 'Automatisch een kleur toewijzen aan de hand van een categorie',
+ 'Assign automatically a category based on a color' => 'Automatisch een categorie toewijzen aan de hand van een kleur',
+ 'Task creation or modification' => 'Taak aanmaken of wijzigen',
+ 'Category' => 'Categorie',
+ 'Category:' => 'Categorie :',
+ 'Categories' => 'Categorieën',
+ 'Category not found.' => 'Categorie niet gevonden',
+ 'Your category have been created successfully.' => 'Categorie succesvol aangemaakt.',
+ 'Unable to create your category.' => 'Categorie aanmaken niet gelukt.',
+ 'Your category have been updated successfully.' => 'Categorie succesvol aangepast.',
+ 'Unable to update your category.' => 'Aanpassen van categorie niet gelukt.',
+ 'Remove a category' => 'Categorie verwijderen',
+ 'Category removed successfully.' => 'Categorie succesvol verwijderd.',
+ 'Unable to remove this category.' => 'Categorie verwijderen niet gelukt.',
+ 'Category modification for the project "%s"' => 'Categorie aanpassen voor project « %s »',
+ 'Category Name' => 'Categorie naam',
+ 'Categories for the project "%s"' => 'Categorieën voor project « %s »',
+ 'Add a new category' => 'Categorie toevoegen',
+ 'Do you really want to remove this category: "%s"?' => 'Weet u zeker dat u deze categorie wil verwijderen: « %s » ?',
+ 'Filter by category' => 'Filter op categorie',
+ 'All categories' => 'Alle categorieën',
+ 'No category' => 'Geen categorie',
+ 'The name is required' => 'De naam is verplicht',
+ 'Remove a file' => 'Bestand verwijderen',
+ 'Unable to remove this file.' => 'Bestand verwijderen niet gelukt.',
+ 'File removed successfully.' => 'Bestand succesvol verwijdered.',
+ 'Attach a document' => 'Document toevoegen',
+ 'Do you really want to remove this file: "%s"?' => 'Weet u zeker dat u dit bestand wil verwijderen: « %s » ?',
+ 'open' => 'openen',
+ 'Attachments' => 'Bijlages',
+ 'Edit the task' => 'Taak aanpassen',
+ 'Edit the description' => 'Omschrijving aanpassen',
+ 'Add a comment' => 'Commentaar toevoegen',
+ 'Edit a comment' => 'Commentaar aanpassen',
+ 'Summary' => 'Samenvatting',
+ 'Time tracking' => 'Tijdschrijven',
+ 'Estimate:' => 'Schatting :',
+ 'Spent:' => 'Besteed :',
+ 'Do you really want to remove this sub-task?' => 'Weet u zeker dat u deze subtaak wil verwijderen ?',
+ 'Remaining:' => 'Restant :',
+ 'hours' => 'uren',
+ 'spent' => 'besteed',
+ 'estimated' => 'geschat',
+ 'Sub-Tasks' => 'Subtaken',
+ 'Add a sub-task' => 'Subtaak toevoegen',
+ 'Original estimate' => 'Orginele schatting',
+ 'Create another sub-task' => 'Nog een subtaak toevoegen',
+ 'Time spent' => 'Tijd besteed',
+ 'Edit a sub-task' => 'Subtaak aanpassen',
+ 'Remove a sub-task' => 'Subtaak verwijderen',
+ 'The time must be a numeric value' => 'De tijd moet een numerieke waarde zijn',
+ 'Todo' => 'Nog te doen',
+ 'In progress' => 'In behandeling',
+ 'Sub-task removed successfully.' => 'Subtaak succesvol verwijderd.',
+ 'Unable to remove this sub-task.' => 'Subtaak verwijderen niet gelukt.',
+ 'Sub-task updated successfully.' => 'Subtaak succesvol aangepast.',
+ 'Unable to update your sub-task.' => 'Subtaak aanpassen niet gelukt.',
+ 'Unable to create your sub-task.' => 'Subtaak aanmaken niet gelukt.',
+ 'Sub-task added successfully.' => 'Subtaak succesvol aangemaakt.',
+ 'Maximum size: ' => 'Maximale grootte : ',
+ 'Unable to upload the file.' => 'Uploaden van bestand niet gelukt.',
+ 'Display another project' => 'Een ander project weergeven',
+ 'Your GitHub account was successfully linked to your profile.' => 'Uw Github Account is succesvol gelinkt aan uw profiel.',
+ 'Unable to link your GitHub Account.' => 'Linken van uw Github Account niet gelukt.',
+ 'GitHub authentication failed' => 'Github Authenticatie niet gelukt',
+ 'Your GitHub account is no longer linked to your profile.' => 'Uw Github Account is niet langer gelinkt aan uw profiel.',
+ 'Unable to unlink your GitHub Account.' => 'Verwijdern van de link met uw Github Account niet gelukt.',
+ 'Login with my GitHub Account' => 'Login met mijn Github Account',
+ 'Link my GitHub Account' => 'Link met mijn Github',
+ 'Unlink my GitHub Account' => 'Link met mijn Github verwijderen',
+ 'Created by %s' => 'Aangemaakt door %s',
+ 'Last modified on %B %e, %Y at %k:%M %p' => 'Laatst gewijzigd op %d/%m/%Y à %H:%M',
+ 'Tasks Export' => 'Taken exporteren',
+ 'Tasks exportation for "%s"' => 'Taken exporteren voor « %s »',
+ 'Start Date' => 'Startdatum',
+ 'End Date' => 'Einddatum',
+ 'Execute' => 'Uitvoeren',
+ 'Task Id' => 'Taak Id',
+ 'Creator' => 'Aangemaakt door',
+ 'Modification date' => 'Wijzigingsdatum',
+ 'Completion date' => 'Afgerond op',
+ 'Webhook URL for task creation' => 'Webhook URL voor aanmaken taak',
+ 'Webhook URL for task modification' => 'Webhook URL voor wijzigen taak',
+ 'Clone' => 'Kloon',
+ 'Clone Project' => 'Project klonen',
+ 'Project cloned successfully.' => 'Project succesvol gekloond.',
+ 'Unable to clone this project.' => 'Klonen van project niet gelukt.',
+ 'Email notifications' => 'Email notificatie',
+ 'Enable email notifications' => 'Email notificatie aanzetten',
+ 'Task position:' => 'Taak positie :',
+ 'The task #%d have been opened.' => 'Taak #%d is geopend.',
+ 'The task #%d have been closed.' => 'Taak #%d is gesloten.',
+ 'Sub-task updated' => 'Subtaak aangepast',
+ 'Title:' => 'Titel :',
+ 'Status:' => 'Status :',
+ 'Assignee:' => 'Toegewezene :',
+ 'Time tracking:' => 'Tijdschrijven :',
+ 'New sub-task' => 'Nieuwe subtaak',
+ 'New attachment added "%s"' => 'Nieuwe bijlage toegevoegd « %s »',
+ 'Comment updated' => 'Commentaar aangepast',
+ 'New comment posted by %s' => 'Nieuw commentaar geplaatst door « %s »',
+ 'List of due tasks for the project "%s"' => 'Lijst van taken die binnenkort voltooid moeten worden voor project « %s »',
+ 'New attachment' => 'Nieuwe bijlage',
+ 'New comment' => 'Nieuw commentaar',
+ 'New subtask' => 'Nieuwe subtaak',
+ 'Subtask updated' => 'Subtaak aangepast',
+ 'Task updated' => 'Taak aangepast',
+ 'Task closed' => 'Taak gesloten',
+ 'Task opened' => 'Taak geopend',
+ '[%s][Due tasks]' => '[%s][binnekort te voltooien taken]',
+ '[Kanboard] Notification' => '[Kanboard] Notificatie',
+ 'I want to receive notifications only for those projects:' => 'Ik wil notificaties ontvangen van de volgende projecten :',
+ 'view the task on Kanboard' => 'taak bekijken op Kanboard',
+ 'Public access' => 'Publieke toegang',
+ 'Category management' => 'Categorie management',
+ 'User management' => 'Gebruikers management',
+ 'Active tasks' => 'Actieve taken',
+ 'Disable public access' => 'Publieke toegang uitschakelen',
+ 'Enable public access' => 'Publieke toegang inschakelen',
+ 'Active projects' => 'Actieve projecten',
+ 'Inactive projects' => 'Inactieve projecten',
+ 'Public access disabled' => 'Publieke toegang uitgeschakeld',
+ 'Do you really want to disable this project: "%s"?' => 'Weet u zeker dat u dit project wil uitschakelen : « %s » ?',
+ 'Do you really want to duplicate this project: "%s"?' => 'Weet u zeker dat u dit project wil dupliceren : « %s » ?',
+ 'Do you really want to enable this project: "%s"?' => 'Weet u zeker dat u dit project wil activeren : « %s » ?',
+ 'Project activation' => 'Project activatie',
+ 'Move the task to another project' => 'Taak verplaatsen naar een ander project',
+ 'Move to another project' => 'Verplaats naar een ander project',
+ 'Do you really want to duplicate this task?' => 'Weet u zeker dat u deze taak wil dupliceren ?',
+ 'Duplicate a task' => 'Taak dupliceren',
+ 'External accounts' => 'Externe accounts',
+ 'Account type' => 'Account type',
+ 'Local' => 'Lokaal',
+ 'Remote' => 'Remote',
+ 'Enabled' => 'Actief',
+ 'Disabled' => 'Inactief',
+ 'Google account linked' => 'Gelinkt Google Account',
+ 'Github account linked' => 'Gelinkt Github Account',
+ 'Username:' => 'Gebruikersnaam :',
+ 'Name:' => 'Naam :',
+ 'Email:' => 'Email :',
+ 'Default project:' => 'Standaard project :',
+ 'Notifications:' => 'Notificaties :',
+ 'Notifications' => 'Notificaties',
+ 'Group:' => 'Groep :',
+ 'Regular user' => 'Normale gebruiker',
+ 'Account type:' => 'Account type:',
+ 'Edit profile' => 'Profiel aanpassen',
+ 'Change password' => 'Wachtwoord aanpassen',
+ 'Password modification' => 'Wachtwoord aanpassen',
+ 'External authentications' => 'Externe authenticatie',
+ 'Google Account' => 'Google Account',
+ 'Github Account' => 'Github Account',
+ 'Never connected.' => 'Nooit verbonden.',
+ 'No account linked.' => 'Geen account gelinkt.',
+ 'Account linked.' => 'Account gelinkt.',
+ 'No external authentication enabled.' => 'Geen externe authenticatie aangezet.',
+ 'Password modified successfully.' => 'Wachtwoord succesvol aangepast.',
+ 'Unable to change the password.' => 'Aanpassen van wachtwoord niet gelukt.',
+ 'Change category for the task "%s"' => 'Pas categorie aan voor taak « %s »',
+ 'Change category' => 'Categorie aanpassen',
+ '%s updated the task %s' => '%s heeft taak %s aangepast',
+ '%s opened the task %s' => '%s heeft taak %s geopend',
+ '%s moved the task %s to the position #%d in the column "%s"' => '%s heeft taak %s naar positie %d in de kolom « %s » verplaatst',
+ '%s moved the task %s to the column "%s"' => '%s heeft taak %s verplaatst naar kolom « %s »',
+ '%s created the task %s' => '%s heeft taak %s aangemaakt',
+ '%s closed the task %s' => '%s heeft taak %s gesloten',
+ '%s created a subtask for the task %s' => '%s heeft een subtaak aangemaakt voor taak %s',
+ '%s updated a subtask for the task %s' => '%s heeft een subtaak aangepast voor taak %s',
+ 'Assigned to %s with an estimate of %s/%sh' => 'Toegewezen aan %s met een schatting van %s/%sh',
+ 'Not assigned, estimate of %sh' => 'Niet toegewezen, schatting: %sh',
+ '%s updated a comment on the task %s' => '%s heeft een commentaar aangepast voor taak %s',
+ '%s commented the task %s' => '%s heeft een commentaar geplaatst voor taak %s',
+ '%s\'s activity' => 'Activiteiten van %s',
+ 'No activity.' => 'Geen activiteiten.',
+ 'RSS feed' => 'RSS feed',
+ '%s updated a comment on the task #%d' => '%s heeft een commentaar aangepast voor taak %d',
+ '%s commented on the task #%d' => '%s heeft commentaar geplaatst voor taak %d',
+ '%s updated a subtask for the task #%d' => '%s heeft een commentaar aangepast voor subtaak %d',
+ '%s created a subtask for the task #%d' => '%s heeft een subtaak aangemaakt voor taak %d',
+ '%s updated the task #%d' => '%s heeft taak %d aangepast',
+ '%s created the task #%d' => '%s heeft taak %d aangemaakt',
+ '%s closed the task #%d' => '%s heeft taak %d gesloten',
+ '%s open the task #%d' => '%s a heeft taak %d geopend',
+ '%s moved the task #%d to the column "%s"' => '%s heeft taak %d verplaatst naar kolom « %s »',
+ '%s moved the task #%d to the position %d in the column "%s"' => '%s heeft taak %d verplaatst naar positie %d in kolom « %s »',
+ 'Activity' => 'Activiteit',
+ 'Default values are "%s"' => 'Standaardwaarden zijn « %s »',
+ 'Default columns for new projects (Comma-separated)' => 'Standaard kolommen voor nieuw projecten (komma gescheiden)',
+ 'Task assignee change' => 'Taak toegewezene verandering',
+ '%s change the assignee of the task #%d to %s' => '%s heeft de toegewezene voor taak %d veranderd in %s',
+ '%s changed the assignee of the task %s to %s' => '%s heeft de toegewezene voor taak %d veranderd in %s',
+ 'Column Change' => 'Kolom verandering',
+ 'Position Change' => 'Positie verandering',
+ 'Assignee Change' => 'Toegewezene verandering',
+ 'New password for the user "%s"' => 'Nieuw wachtwoord voor gebruiker « %s »',
+ 'Choose an event' => 'Kies een gebeurtenis',
+ 'Github commit received' => 'Github commentaar ontvangen',
+ 'Github issue opened' => 'Github issue geopend',
+ 'Github issue closed' => 'Github issue gesloten',
+ 'Github issue reopened' => 'Github issue heropend',
+ 'Github issue assignee change' => 'Github toegewezen veranderd',
+ 'Github issue label change' => 'Github issue label verander',
+ 'Create a task from an external provider' => 'Maak een taak aan vanuit een externe provider',
+ 'Change the assignee based on an external username' => 'Verander de toegewezene aan de hand van de externe gebruikersnaam',
+ 'Change the category based on an external label' => 'Verander de categorie aan de hand van een extern label',
+ 'Reference' => 'Referentie',
+ 'Reference: %s' => 'Referentie : %s',
+ 'Label' => 'Label',
+ 'Database' => 'Database',
+ 'About' => 'Over',
+ 'Database driver:' => 'Database driver :',
+ 'Board settings' => 'Bord instellingen',
+ 'URL and token' => 'URL en token',
+ 'Webhook settings' => 'Webhook instellingen',
+ 'URL for task creation:' => 'URL voor aanmaken taken :',
+ 'Reset token' => 'Token resetten',
+ 'API endpoint:' => 'API endpoint :',
+ 'Refresh interval for private board' => 'Verversingsinterval voor private borden',
+ 'Refresh interval for public board' => 'Verversingsinterval voor publieke borden',
+ 'Task highlight period' => 'Taak highlight periode',
+ 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode (in seconden) om aan te geven of een taak recent is aangepast (0 om uit te schakelen, standaard 2 dagen)',
+ 'Frequency in second (60 seconds by default)' => 'Frequentie in seconden (stadaard 60)',
+ 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frequentie in seconden (0 om uit te schakelen, standaard 10)',
+ 'Application URL' => 'Applicatie URL',
+ 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Voorbeeld: http://example.kanboard.net/ (gebruikt voor email notificaties)',
+ 'Token regenerated.' => 'Token opnieuw gegenereerd.',
+ 'Date format' => 'Datum formaat',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'ISO formaat is altijd geaccepteerd, bijvoorbeeld : « %s » et « %s »',
+ 'New private project' => 'Nieuw privé project',
+ 'This project is private' => 'Dit project is privé',
+ 'Type here to create a new sub-task' => 'Typ hier om een nieuwe subtaak aan te maken',
+ 'Add' => 'Toevoegen',
+ 'Estimated time: %s hours' => 'Geschatte tijd: %s hours',
+ 'Time spent: %s hours' => 'Tijd besteed : %s heures',
+ 'Started on %B %e, %Y' => 'Gestart op %d/%m/%Y',
+ 'Start date' => 'Startdatum',
+ 'Time estimated' => 'Geschatte tijd',
+ 'There is nothing assigned to you.' => 'Er is niets aan u toegewezen.',
+ 'My tasks' => 'Mijn taken',
+ 'Activity stream' => 'Activiteiten',
+ 'Dashboard' => 'Dashboard',
+ // 'Confirmation' => '',
+ 'Allow everybody to access to this project' => 'Geef iedereen toegang tot dit project',
+ 'Everybody have access to this project.' => 'Iedereen heeft toegang tot dit project.',
+ 'Webhooks' => 'Webhooks',
+ 'API' => 'API',
+ 'Integration' => 'Integratue',
+ 'Github webhooks' => 'Github webhooks',
+ 'Help on Github webhooks' => 'Hulp bij Github webhooks',
+ 'Create a comment from an external provider' => 'Voeg een commentaar toe van een externe provider',
+ 'Github issue comment created' => 'Github issue commentaar aangemaakt',
+ 'Configure' => 'Configureren',
+ 'Project management' => 'Project management',
+ 'My projects' => 'Mijn projecten',
+ 'Columns' => 'Kolommen',
+ 'Task' => 'Taak',
+ 'Your are not member of any project.' => 'U bent van geen enkel project lid.',
+ 'Percentage' => 'Percentage',
+ 'Number of tasks' => 'Aantal taken',
+ 'Task distribution' => 'Distributie van taken',
+ 'Reportings' => 'Rapporten',
+ 'Task repartition for "%s"' => 'Taakverdeling voor « %s »',
+ 'Analytics' => 'Analytics',
+ 'Subtask' => 'Subtaak',
+ 'My subtasks' => 'Mijn subtaken',
+ 'User repartition' => 'Gebruikerverdeling',
+ 'User repartition for "%s"' => 'Gebruikerverdeling voor « %s »',
+ 'Clone this project' => 'Kloon dit project',
+ 'Column removed successfully.' => 'Kolom succesvol verwijderd.',
+ 'Edit Project' => 'Project aanpassen',
+ 'Github Issue' => 'Github issue',
+ 'Not enough data to show the graph.' => 'Niet genoeg data om de grafiek te laten zien.',
+ // 'Previous' => '',
+ 'The id must be an integer' => 'Het id moet een integer zijn',
+ 'The project id must be an integer' => 'Het project id moet een integer zijn',
+ 'The status must be an integer' => 'De status moet een integer zijn',
+ 'The subtask id is required' => 'Het id van de subtaak is verplicht',
+ 'The subtask id must be an integer' => 'Het id van de subtaak moet een integer zijn',
+ 'The task id is required' => 'Het id van de taak is verplicht',
+ 'The task id must be an integer' => 'Het id van de taak moet een integer zijn',
+ 'The user id must be an integer' => 'Het id van de gebruiker moet een integer zijn',
+ 'This value is required' => 'Deze waarde is verplicht',
+ 'This value must be numeric' => 'Deze waarde moet numeriek zijn',
+ 'Unable to create this task.' => 'Aanmaken van de taak mislukt',
+ 'Cumulative flow diagram' => 'Cummulatief stroomdiagram',
+ 'Cumulative flow diagram for "%s"' => 'Cummulatief stroomdiagram voor « %s »',
+ 'Daily project summary' => 'Dagelijkse project samenvatting',
+ 'Daily project summary export' => 'Dagelijkse project samenvatting export',
+ 'Daily project summary export for "%s"' => 'Dagelijkse project samenvatting voor « %s »',
+ 'Exports' => 'Exports',
+ 'This export contains the number of tasks per column grouped per day.' => 'Dit rapport bevat het aantal taken per kolom gegroupeerd per dag.',
+ 'Nothing to preview...' => 'Niets om te previewen...',
+ 'Preview' => 'Preview',
+ 'Write' => 'Schrijf',
+ 'Active swimlanes' => 'Actieve swinlanes',
+ 'Add a new swimlane' => 'Nieuwe swimlane toevoegen',
+ 'Change default swimlane' => 'Standaard swimlane aapassen',
+ 'Default swimlane' => 'Standaard swinlane',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Weet u zeker dat u deze swimlane wil verwijderen : « %s » ?',
+ 'Inactive swimlanes' => 'Inactieve swinlanes',
+ 'Set project manager' => 'Project manager instellen',
+ 'Set project member' => 'Project lid instellen',
+ 'Remove a swimlane' => 'Verwijder swinlane',
+ 'Rename' => 'Hernoemen',
+ 'Show default swimlane' => 'Standaard swimlane tonen',
+ 'Swimlane modification for the project "%s"' => 'Swinlane aanpassing voor project « %s »',
+ 'Swimlane not found.' => 'Swimlane niet gevonden.',
+ 'Swimlane removed successfully.' => 'Swimlane succesvol verwijderd.',
+ 'Swimlanes' => 'Swimlanes',
+ 'Swimlane updated successfully.' => 'Swimlane succesvol aangepast.',
+ 'The default swimlane have been updated successfully.' => 'De standaard swimlane is succesvol aangepast.',
+ 'Unable to create your swimlane.' => 'Swimlane aanmaken niet gelukt.',
+ 'Unable to remove this swimlane.' => 'Swimlane verwijderen niet gelukt.',
+ 'Unable to update this swimlane.' => 'Swimlane aanpassen niet gelukt.',
+ 'Your swimlane have been created successfully.' => 'Swimlane succesvol aangemaakt.',
+ 'Example: "Bug, Feature Request, Improvement"' => 'Voorbeeld: « Bug, Feature Request, Improvement »',
+ 'Default categories for new projects (Comma-separated)' => 'Standaard categorieën voor nieuwe projecten (komma gescheiden)',
+ 'Gitlab commit received' => 'Gitlab commir ontvangen',
+ 'Gitlab issue opened' => 'Gitlab issue geopend',
+ 'Gitlab issue closed' => 'Gitlab issue gesloten',
+ 'Gitlab webhooks' => 'Gitlab webhooks',
+ 'Help on Gitlab webhooks' => 'Hulp bij Gitlab webhooks',
+ 'Integrations' => 'Integraties',
+ 'Integration with third-party services' => 'Integratie met derde-partij-services',
+ 'Role for this project' => 'Rol voor dit project',
+ 'Project manager' => 'Project manager',
+ 'Project member' => 'Project lid',
+ 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Een project manager kan de instellingen van het project wijzigen en heeft meer rechten dan een normale gebruiker.',
+ 'Gitlab Issue' => 'Gitlab issue',
+ 'Subtask Id' => 'Subtaak id',
+ 'Subtasks' => 'Subtaken',
+ 'Subtasks Export' => 'Subtaken exporteren',
+ 'Subtasks exportation for "%s"' => 'Subtaken exporteren voor project « %s »',
+ 'Task Title' => 'Taak title',
+ 'Untitled' => 'Geen titel',
+ 'Application default' => 'Standaard taal voor applicatie',
+ 'Language:' => 'Taal :',
+ 'Timezone:' => 'Tijdzone :',
+ 'All columns' => 'Alle kolommen',
+ 'Calendar for "%s"' => 'Agenda voor « %s »',
+ 'Filter by column' => 'Filter op kolom',
+ 'Filter by status' => 'Filter op status',
+ 'Calendar' => 'Agenda',
+ 'Next' => 'Volgende',
+ '#%d' => '%d',
+ 'Filter by color' => 'Filter op kleur',
+ 'Filter by swimlane' => 'Filter op swimlane',
+ 'All swimlanes' => 'Alle swimlanes',
+ 'All colors' => 'Alle kleuren',
+ 'All status' => 'Alle statussen',
+ 'Add a comment logging moving the task between columns' => 'Voeg een commentaar toe bij het verplaatsen van een taak tussen kolommen',
+ 'Moved to column %s' => 'Verplaatst naar kolom',
+ 'Change description' => 'Verandering omschrijving',
+ 'User dashboard' => 'Gebruiker dashboard',
+ 'Allow only one subtask in progress at the same time for a user' => 'Sta maximaal één subtaak in behandeling toe per gebruiker',
+ 'Edit column "%s"' => 'Kolom « %s » aanpassen',
+ 'Enable time tracking for subtasks' => 'Activeer tijdschrijven voor subtaken',
+ 'Select the new status of the subtask: "%s"' => 'Selecteer nieuwe status voor subtaak : « %s »',
+ 'Subtask timesheet' => 'Subtaak timesheet',
+ 'There is nothing to show.' => 'Er is niets om te laten zijn.',
+ 'Time Tracking' => 'Tijdschrijven',
+ 'You already have one subtask in progress' => 'U heeft al een subtaak in behandeling',
+ 'Which parts of the project do you want to duplicate?' => 'Welke onderdelen van het project wilt u dupliceren?',
+ 'Change dashboard view' => 'Pas dashboard aan',
+ 'Show/hide activities' => 'Toon/verberg activiteiten',
+ 'Show/hide projects' => 'Toon/verberg projecten',
+ 'Show/hide subtasks' => 'Toon/verberg subtaken',
+ 'Show/hide tasks' => 'Toon/verberg taken',
+ 'Disable login form' => 'Schakel login scherm uit',
+ 'Show/hide calendar' => 'Toon/verberg agenda',
+ 'User calendar' => 'Agenda gebruiker',
+ 'Bitbucket commit received' => 'Bitbucket commit ontvangen',
+ 'Bitbucket webhooks' => 'Bitbucket webhooks',
+ 'Help on Bitbucket webhooks' => 'Help bij Bitbucket webhooks',
+ 'Start' => 'Start',
+ 'End' => 'Eind',
+ 'Task age in days' => 'Leeftijd taak in dagen',
+ 'Days in this column' => 'Dagen in deze kolom',
+ '%dd' => '%dj',
+ 'Add a link' => 'Link toevoegen',
+ 'Add a new link' => 'Nieuwe link toevoegen',
+ 'Do you really want to remove this link: "%s"?' => 'Weet u zeker dat u deze link wil verwijderen : « %s » ?',
+ 'Do you really want to remove this link with task #%d?' => 'Weet u zeker dat u deze link met taak %d wil verwijderen?',
+ 'Field required' => 'Veld verplicht',
+ 'Link added successfully.' => 'Link succesvol toegevoegd.',
+ 'Link updated successfully.' => 'Link succesvol aangepast.',
+ 'Link removed successfully.' => 'Link succesvol verwijderd.',
+ 'Link labels' => 'Link labels',
+ 'Link modification' => 'Link aanpassing',
+ 'Links' => 'Links',
+ 'Link settings' => 'Link instellingen',
+ 'Opposite label' => 'Tegenovergesteld label',
+ 'Remove a link' => 'Link verwijderen',
+ 'Task\'s links' => 'Links van taak',
+ 'The labels must be different' => 'De labels moeten verschillend zijn',
+ 'There is no link.' => 'Er is geen link.',
+ 'This label must be unique' => 'Dit label moet uniek zijn',
+ 'Unable to create your link.' => 'Link aanmaken niet gelukt.',
+ 'Unable to update your link.' => 'Link aanpassen niet gelukt.',
+ 'Unable to remove this link.' => 'Link verwijderen niet gelukt.',
+ 'relates to' => 'is gerelateerd aan',
+ 'blocks' => 'blokkeert',
+ 'is blocked by' => 'is geblokkeerd door',
+ 'duplicates' => 'dupliceert',
+ 'is duplicated by' => 'is gedupliceerd',
+ 'is a child of' => 'is een kind van',
+ 'is a parent of' => 'is een ouder van',
+ 'targets milestone' => 'is nodig voor milestone',
+ 'is a milestone of' => 'is een milestone voor',
+ 'fixes' => 'corrigeert',
+ 'is fixed by' => 'word gecorrigeerd door',
+ 'This task' => 'Deze taal',
+ '<1h' => '<1h',
+ '%dh' => '%dh',
+ '%b %e' => '%e %b',
+ 'Expand tasks' => 'Taken uitklappen',
+ 'Collapse tasks' => 'Taken inklappen',
+ 'Expand/collapse tasks' => 'Taken in/uiklappen',
+ 'Close dialog box' => 'Venster sluiten',
+ 'Submit a form' => 'Formulier insturen',
+ 'Board view' => 'Bord weergave',
+ 'Keyboard shortcuts' => 'Keyboard snelkoppelingen',
+ 'Open board switcher' => 'Open bord switcher',
+ 'Application' => 'Applicatie',
+ 'Filter recently updated' => 'Filter recent aangepast',
+ 'since %B %e, %Y at %k:%M %p' => 'sinds %d/%m/%Y à %H:%M',
+ 'More filters' => 'Meer filters',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
+);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index c6becf4c..4bee7c42 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Brak',
'edit' => 'edytuj',
'Edit' => 'Edytuj',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index 89f7e294..edba2cae 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Nenhum',
'edit' => 'editar',
'Edit' => 'Editar',
@@ -734,4 +736,72 @@ return array(
'Filter recently updated' => 'Filtro recentemente atualizado',
// 'since %B %e, %Y at %k:%M %p' => '',
'More filters' => 'Mais filtros',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 02a66b56..6a2ed073 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Отсутствует',
'edit' => 'изменить',
'Edit' => 'Изменить',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
new file mode 100644
index 00000000..83d6eaa3
--- /dev/null
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -0,0 +1,807 @@
+<?php
+
+return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
+ 'None' => 'None',
+ 'edit' => 'izmeni',
+ 'Edit' => 'Izmeni',
+ 'remove' => 'ukloni',
+ 'Remove' => 'Ukloni',
+ 'Update' => 'Ažuriraj',
+ 'Yes' => 'Da',
+ 'No' => 'Ne',
+ 'cancel' => 'odustani',
+ 'or' => 'ili',
+ 'Yellow' => 'Žuta',
+ 'Blue' => 'Plava',
+ 'Green' => 'Zelena',
+ 'Purple' => 'Ljubičasta',
+ 'Red' => 'Crvena',
+ 'Orange' => 'Narandžasta',
+ 'Grey' => 'Siva',
+ 'Save' => 'Snimi',
+ 'Login' => 'Prijava',
+ 'Official website:' => 'Zvanična strana:',
+ 'Unassigned' => 'Nedodeljen',
+ 'View this task' => 'Pregledaj zadatak',
+ 'Remove user' => 'Ukloni korisnika',
+ 'Do you really want to remove this user: "%s"?' => 'Da li zaista želiš da ukloniš korisnika: "%s"?',
+ 'New user' => 'novi korisnik',
+ 'All users' => 'Svi korisnici',
+ 'Username' => 'Korisnik',
+ 'Password' => 'Lozinka',
+ 'Default project' => 'Podrazumevani projekat',
+ 'Administrator' => 'Administrator',
+ 'Sign in' => 'Odjava',
+ 'Users' => 'Korisnik',
+ 'No user' => 'Ne',
+ 'Forbidden' => 'Zabranjeno',
+ 'Access Forbidden' => 'Zabranjen prostup',
+ 'Only administrators can access to this page.' => 'Samo administrator može videti ovu stranu.',
+ 'Edit user' => 'Izmeni korisnika',
+ 'Logout' => 'Odjava',
+ 'Bad username or password' => 'Loše korisničko ime ili lozinka',
+ 'users' => 'korisnici',
+ 'projects' => 'projekti',
+ 'Edit project' => 'Izmeni projekat',
+ 'Name' => 'Ime',
+ 'Activated' => 'Aktiviran',
+ 'Projects' => 'Projekti',
+ 'No project' => 'Bez projekta',
+ 'Project' => 'Projekat',
+ 'Status' => 'Status',
+ 'Tasks' => 'Zadatak',
+ 'Board' => 'Tabla',
+ 'Actions' => 'Akcje',
+ 'Inactive' => 'Neaktivan',
+ 'Active' => 'Aktivan',
+ 'Column %d' => 'Kolona %d',
+ 'Add this column' => 'Dodaj kolonu',
+ '%d tasks on the board' => '%d zadataka na tabli',
+ '%d tasks in total' => '%d zadataka ukupno',
+ 'Unable to update this board.' => 'Nemogu da ažuriram ovu tablu.',
+ 'Edit board' => 'Izmeni tablu',
+ 'Disable' => 'Onemogući',
+ 'Enable' => 'Omogući',
+ 'New project' => 'Novi projekat',
+ 'Do you really want to remove this project: "%s"?' => 'Da li želiš da ukloniš projekat: "%s"?',
+ 'Remove project' => 'Ukloni projekat',
+ 'Boards' => 'Table',
+ 'Edit the board for "%s"' => 'Izmeni tablu za "%s"',
+ 'All projects' => 'Svi projekti',
+ 'Change columns' => 'Zameni kolonu',
+ 'Add a new column' => 'Dodaj novu kolonu',
+ 'Title' => 'Naslov',
+ 'Add Column' => 'Dodaj kolunu',
+ 'Project "%s"' => 'Projekt "%s"',
+ 'Nobody assigned' => 'Niko nije dodeljen',
+ 'Assigned to %s' => 'Dodeljen korisniku %s',
+ 'Remove a column' => 'Ukloni kolonu',
+ 'Remove a column from a board' => 'Ukloni kolonu sa table',
+ 'Unable to remove this column.' => 'Nemoguće uklanjanje kolone.',
+ 'Do you really want to remove this column: "%s"?' => 'Da li zaista želiš da ukoniš ovu kolonu: "%s"?',
+ 'This action will REMOVE ALL TASKS associated to this column!' => 'Ova akcija BRIŠE SVE ZADATKE vezane za ovu kolonu!',
+ 'Settings' => 'Podešavanja',
+ 'Application settings' => 'Podešavanja aplikacije',
+ 'Language' => 'Jezik',
+ 'Webhook token:' => 'Token :',
+ 'API token:' => 'Token za API',
+ 'More information' => 'Još informacja',
+ 'Database size:' => 'Veličina baze :',
+ 'Download the database' => 'Preuzmi bazu',
+ 'Optimize the database' => 'Optimizuj bazu',
+ '(VACUUM command)' => '(komanda VACUUM)',
+ '(Gzip compressed Sqlite file)' => '(Sqlite baza spakovana Gzip-om)',
+ 'User settings' => 'Korisnička podešavanja',
+ 'My default project:' => 'Moj podrazumevani projekat:',
+ 'Close a task' => 'Zatvori zadatak',
+ 'Do you really want to close this task: "%s"?' => 'Da li zaista želiš da zatvoriš ovaj zadatak: "%s"?',
+ 'Edit a task' => 'Izmeni zadatak',
+ 'Column' => 'Kolona',
+ 'Color' => 'Boja',
+ 'Assignee' => 'Dodeli',
+ 'Create another task' => 'Dodaj zadatak',
+ 'New task' => 'Novi zadatak',
+ 'Open a task' => 'Otvori zadatak',
+ 'Do you really want to open this task: "%s"?' => 'Da li zaista želiš da otvoriš zadatak: "%s"?',
+ 'Back to the board' => 'Nazad na tablu',
+ 'Created on %B %e, %Y at %k:%M %p' => 'Kreiran %e %B %Y o %k:%M',
+ 'There is nobody assigned' => 'Niko nije dodeljen!',
+ 'Column on the board:' => 'Kolona na tabli:',
+ 'Status is open' => 'Status otvoren',
+ 'Status is closed' => 'Status zatvoren',
+ 'Close this task' => 'Zatvori ovaj zadatak',
+ 'Open this task' => 'Otvori ovaj zadatak',
+ 'There is no description.' => 'Bez opisa.',
+ 'Add a new task' => 'Dodaj zadatak',
+ 'The username is required' => 'Korisničko ime je obavezno',
+ 'The maximum length is %d characters' => 'Maksimalna dužina je %d znakova',
+ 'The minimum length is %d characters' => 'Minimalna dužina je %d znakova',
+ 'The password is required' => 'Lozinka je obavezna',
+ 'This value must be an integer' => 'Mora biti ceo broj',
+ 'The username must be unique' => 'Korisničko ime mora biti jedinstveno',
+ 'The username must be alphanumeric' => 'Korisničko ime sme sadržati samo brojeve i slova',
+ 'The user id is required' => 'ID korisnika je obavezan',
+ 'Passwords don\'t match' => 'Lozinke se ne podudaraju',
+ 'The confirmation is required' => 'Potvrda je obavezna',
+ 'The column is required' => 'Kolona je obavezna',
+ 'The project is required' => 'Projekat je obavezan',
+ 'The color is required' => 'Boja je obavezna',
+ 'The id is required' => 'ID je obavezan',
+ 'The project id is required' => 'ID projekta je obavezan',
+ 'The project name is required' => 'Naziv projekta je obavezan',
+ 'This project must be unique' => 'Projekat mora biti jedinstven',
+ 'The title is required' => 'Naslov je obavezan',
+ 'The language is required' => 'Jezik je obavezan',
+ 'There is no active project, the first step is to create a new project.' => 'Nema aktivnih projekata. Potrebno je prvo napraviti novi projekat.',
+ 'Settings saved successfully.' => 'Podešavanja uspešno snimljena.',
+ 'Unable to save your settings.' => 'Nemoguće snimanje podešavanja.',
+ 'Database optimization done.' => 'Optimizacija baze je završena.',
+ 'Your project have been created successfully.' => 'Projekat je uspešno napravljen.',
+ 'Unable to create your project.' => 'Nemoguće kreiranje projekta.',
+ 'Project updated successfully.' => 'Projekt je uspešno ažuriran.',
+ 'Unable to update this project.' => 'Nemoguće ažuriranje projekta.',
+ 'Unable to remove this project.' => 'Nemoguće uklanjanje projekta.',
+ 'Project removed successfully.' => 'Projekat uspešno uklonjen.',
+ 'Project activated successfully.' => 'Projekt uspešno aktiviran.',
+ 'Unable to activate this project.' => 'Nemoguće aktiviranje projekta.',
+ 'Project disabled successfully.' => 'Projekat uspešno deaktiviran.',
+ 'Unable to disable this project.' => 'nemoguće deaktiviranje projekta.',
+ 'Unable to open this task.' => 'Nemoguće otvaranje zadatka.',
+ 'Task opened successfully.' => 'Zadatak uspešno otvoren.',
+ 'Unable to close this task.' => 'Nije moguće zatvaranje ovog zadatka.',
+ 'Task closed successfully.' => 'Zadatak uspešno zatvoren.',
+ 'Unable to update your task.' => 'Nije moguće ažuriranje zadatka.',
+ 'Task updated successfully.' => 'Zadatak uspešno ažuriran.',
+ 'Unable to create your task.' => 'Nije moguće kreiranje zadatka.',
+ 'Task created successfully.' => 'Zadatak uspešno kreiran.',
+ 'User created successfully.' => 'Korisnik uspešno kreiran',
+ 'Unable to create your user.' => 'Nije uspelo kreiranje korisnika.',
+ 'User updated successfully.' => 'Korisnik uspešno ažuriran.',
+ 'Unable to update your user.' => 'Nije moguće ažuriranje korisnika.',
+ 'User removed successfully.' => 'Korisnik uspešno uklonjen.',
+ 'Unable to remove this user.' => 'Nije moguće uklanjanje korisnika.',
+ 'Board updated successfully.' => 'Tabla uspešno ažurirana.',
+ 'Ready' => 'Spreman',
+ 'Backlog' => 'Log',
+ 'Work in progress' => 'U radu',
+ 'Done' => 'Gotovo',
+ 'Application version:' => 'Verzija aplikacije:',
+ 'Completed on %B %e, %Y at %k:%M %p' => 'Završeno u %e %B %Y o %k:%M',
+ '%B %e, %Y at %k:%M %p' => '%e %B %Y o %k:%M',
+ 'Date created' => 'Kreiran dana',
+ 'Date completed' => 'Završen dana',
+ 'Id' => 'Id',
+ 'No task' => 'bez zadataka',
+ 'Completed tasks' => 'Zatvoreni zadaci',
+ 'List of projects' => 'Spisak projekata',
+ 'Completed tasks for "%s"' => 'zatvoreni zadaci za "%s"',
+ '%d closed tasks' => '%d zatvorenih zadataka',
+ 'No task for this project' => 'Nema dodeljenih zadataka ovom projektu',
+ 'Public link' => 'Javni link',
+ 'There is no column in your project!' => 'Nema dodeljenih kolona ovom projektu',
+ 'Change assignee' => 'Izmeni dodelu',
+ 'Change assignee for the task "%s"' => 'Izmeni dodelu za ovaj zadatak "%s"',
+ 'Timezone' => 'Vremenska zona',
+ 'Sorry, I didn\'t find this information in my database!' => 'Na žalost, nije pronađena informacija u bazi',
+ 'Page not found' => 'Strana nije pronađena',
+ 'Complexity' => 'Složenost',
+ 'limit' => 'ograničenje',
+ 'Task limit' => 'Ograničenje zadatka',
+ 'Task count' => 'Broj zadataka',
+ 'This value must be greater than %d' => 'Vrednost mora biti veća od %d',
+ 'Edit project access list' => 'Izmeni prava pristupa projektu',
+ 'Edit users access' => 'Izmeni korisnička prava',
+ 'Allow this user' => 'Dozvoli ovog korisnika',
+ 'Only those users have access to this project:' => 'Samo ovi korisnici imaju pristup projektu:',
+ 'Don\'t forget that administrators have access to everything.' => 'Zapamti: Administrator može pristupiti svemu!',
+ 'Revoke' => 'Povuci',
+ 'List of authorized users' => 'Spisak odobrenih korisnika',
+ 'User' => 'Korisnik',
+ 'Nobody have access to this project.' => 'Niko nema pristup ovom projektu',
+ 'You are not allowed to access to this project.' => 'Nije ti dozvoljen pristup ovom projektu.',
+ 'Comments' => 'Komentari',
+ 'Post comment' => 'Dodaj komentar',
+ 'Write your text in Markdown' => 'Pisanje teksta pomoću Markdown',
+ 'Leave a comment' => 'Ostavi komentar',
+ 'Comment is required' => 'Komentar je obavezan',
+ 'Leave a description' => 'Dodaj opis',
+ 'Comment added successfully.' => 'Komentar uspešno ostavljen',
+ 'Unable to create your comment.' => 'Nemoguće kreiranje komentara',
+ 'The description is required' => 'Opis je obavezan',
+ 'Edit this task' => 'Izmeni ovaj zadatak',
+ 'Due Date' => 'Termin',
+ 'Invalid date' => 'Loš datum',
+ 'Must be done before %B %e, %Y' => 'Termin do %e %B %Y',
+ '%B %e, %Y' => '%e %B %Y',
+ // '%b %e, %Y' => '',
+ 'Automatic actions' => 'Automatske akcije',
+ 'Your automatic action have been created successfully.' => 'Uspešno kreirana automatska akcija',
+ 'Unable to create your automatic action.' => 'Nemoguće kreiranje automatske akcije',
+ 'Remove an action' => 'Obriši akciju',
+ 'Unable to remove this action.' => 'Nije moguće obrisati akciju',
+ 'Action removed successfully.' => 'Akcija obrisana',
+ 'Automatic actions for the project "%s"' => 'Akcje za automatizaciju projekta "%s"',
+ 'Defined actions' => 'Definisane akcje',
+ 'Add an action' => 'dodaj akcju',
+ 'Event name' => 'Naziv događaja',
+ 'Action name' => 'Naziv akcije',
+ 'Action parameters' => 'Parametri akcije',
+ 'Action' => 'Akcija',
+ 'Event' => 'Događaj',
+ 'When the selected event occurs execute the corresponding action.' => 'Kad se događaj desi izvrši odgovarajuću akciju',
+ 'Next step' => 'Sledeći korak',
+ 'Define action parameters' => 'Definiši parametre akcije',
+ 'Save this action' => 'Snimi akciju',
+ 'Do you really want to remove this action: "%s"?' => 'Da li da obrišem akciju "%s"?',
+ 'Remove an automatic action' => 'Obriši automatsku akciju',
+ 'Close the task' => 'Zatvori zadatak',
+ 'Assign the task to a specific user' => 'Dodeli zadatak određenom korisniku',
+ 'Assign the task to the person who does the action' => 'Dodeli zadatak korisniku koji je izvršio akciju',
+ 'Duplicate the task to another project' => 'Kopiraj akciju u drugi projekat',
+ 'Move a task to another column' => 'Premesti zadatak u drugu kolonu',
+ 'Move a task to another position in the same column' => 'Promeni poziciju zadatka u istoj koloni',
+ 'Task modification' => 'Izman zadatka',
+ 'Task creation' => 'Kreiranje zadatka',
+ 'Open a closed task' => 'Otvori zatvoreni zadatak',
+ 'Closing a task' => 'Zatvaranja zadatka',
+ 'Assign a color to a specific user' => 'Dodeli boju korisniku',
+ 'Column title' => 'Naslov kolone',
+ 'Position' => 'Pozicija',
+ 'Move Up' => 'Podigni',
+ 'Move Down' => 'Spusti',
+ 'Duplicate to another project' => 'Kopiraj u drugi projekat',
+ 'Duplicate' => 'Napravi kopiju',
+ 'link' => 'link',
+ 'Update this comment' => 'Ažuriraj komentar',
+ 'Comment updated successfully.' => 'Komentar uspešno ažuriran.',
+ 'Unable to update your comment.' => 'Neuspešno ažuriranje komentara.',
+ 'Remove a comment' => 'Obriši komentar',
+ 'Comment removed successfully.' => 'Komentar je uspešno obrisan.',
+ 'Unable to remove this comment.' => 'Neuspešno brisanje komentara.',
+ 'Do you really want to remove this comment?' => 'Da li da obrišem ovaj komentar?',
+ 'Only administrators or the creator of the comment can access to this page.' => 'Samo administrator i kreator komentara mogu ga obrisati.',
+ 'Details' => 'Detalji',
+ 'Current password for the user "%s"' => 'Trenutna lozinka za korisnika "%s"',
+ 'The current password is required' => 'Trenutna lozinka je obavezna',
+ 'Wrong password' => 'Pogrešna lozinka',
+ 'Reset all tokens' => 'Resetuj tokene',
+ 'All tokens have been regenerated.' => 'Svi tokeni su ponovo generisani.',
+ 'Unknown' => 'Nepoznat',
+ 'Last logins' => 'Poslednja prijava',
+ 'Login date' => 'Datum prijave',
+ 'Authentication method' => 'Metod autentikacije',
+ 'IP address' => 'IP adresa',
+ 'User agent' => 'Browser',
+ 'Persistent connections' => 'Stalna konekcija',
+ 'No session.' => 'Bez sesjie',
+ 'Expiration date' => 'Ističe',
+ 'Remember Me' => 'Zapamti me',
+ 'Creation date' => 'Datum kreiranja',
+ 'Filter by user' => 'Po korisniku',
+ 'Filter by due date' => 'Po terminu',
+ 'Everybody' => 'Svi',
+ 'Open' => 'Otvoreni',
+ 'Closed' => 'Zatvoreni',
+ 'Search' => 'Traži',
+ 'Nothing found.' => 'Ništa nije pronađeno',
+ 'Search in the project "%s"' => 'Traži u prijektu "%s"',
+ 'Due date' => 'Termin',
+ 'Others formats accepted: %s and %s' => 'Ostali formati: %s i %s',
+ 'Description' => 'Opis',
+ '%d comments' => '%d Komentara',
+ '%d comment' => '%d Komentar',
+ 'Email address invalid' => 'Pogrešan e-mail',
+ 'Your Google Account is not linked anymore to your profile.' => 'Tvoj google nalog više nije povezan sa profilom',
+ 'Unable to unlink your Google Account.' => 'Neuspešno ukidanje veze od Google naloga',
+ 'Google authentication failed' => 'Neuspešna Google autentikacija',
+ 'Unable to link your Google Account.' => 'Neuspešno povezivanje sa Google nalogom',
+ 'Your Google Account is linked to your profile successfully.' => 'Vaš Google nalog je uspešno povezan sa vašim profilom',
+ 'Email' => 'E-mail',
+ 'Link my Google Account' => 'Poveži sa Google nalogom',
+ 'Unlink my Google Account' => 'Ukini vezu sa Google nalogom',
+ 'Login with my Google Account' => 'Prijavi se preko Google naloga',
+ 'Project not found.' => 'Projekat nije pronađen.',
+ 'Task #%d' => 'Zadatak #%d',
+ 'Task removed successfully.' => 'Zadatak uspešno uklonjen.',
+ 'Unable to remove this task.' => 'Nemoguće uklanjanje zadatka.',
+ 'Remove a task' => 'Ukloni zadatak',
+ 'Do you really want to remove this task: "%s"?' => 'Da li da obrišem zadatak "%s"?',
+ 'Assign automatically a color based on a category' => 'Automatski dodeli boju po kategoriji',
+ 'Assign automatically a category based on a color' => 'Automatski dodeli kategoriju po boji',
+ 'Task creation or modification' => 'Kreiranje ili izmena zadatka',
+ 'Category' => 'Kategorija',
+ 'Category:' => 'Kategorija:',
+ 'Categories' => 'Kategorije',
+ 'Category not found.' => 'Kategorija nije pronađena',
+ 'Your category have been created successfully.' => 'Uspešno kreirana kategorija.',
+ 'Unable to create your category.' => 'Nije moguće kreirati kategoriju.',
+ 'Your category have been updated successfully.' => 'Kategorija je uspešno izmenjena',
+ 'Unable to update your category.' => 'Nemoguće izmeniti kategoriju',
+ 'Remove a category' => 'Obriši kategoriju',
+ 'Category removed successfully.' => 'Kategorija uspešno uklonjena.',
+ 'Unable to remove this category.' => 'Nije moguće ukloniti kategoriju.',
+ 'Category modification for the project "%s"' => 'Izmena kategorije za projekat "%s"',
+ 'Category Name' => 'Naziv kategorije',
+ 'Categories for the project "%s"' => 'Kategorije u projektu',
+ 'Add a new category' => 'Dodaj novu kategoriju',
+ 'Do you really want to remove this category: "%s"?' => 'Da li zaista želiš da ukloniš kategoriju: "%s"?',
+ 'Filter by category' => 'Po kategoriji',
+ 'All categories' => 'Sve kategorije',
+ 'No category' => 'Bez kategorije',
+ 'The name is required' => 'Naziv je obavezan',
+ 'Remove a file' => 'Ukloni fajl',
+ 'Unable to remove this file.' => 'Fajl nije moguće ukloniti.',
+ 'File removed successfully.' => 'Uspešno uklonjen fajl.',
+ 'Attach a document' => 'Prikači dokument',
+ 'Do you really want to remove this file: "%s"?' => 'Da li da uklonim fajl: "%s"?',
+ 'open' => 'otvori',
+ 'Attachments' => 'Prilozi',
+ 'Edit the task' => 'Izmena Zadatka',
+ 'Edit the description' => 'Izmena opisa',
+ 'Add a comment' => 'Dodaj komentar',
+ 'Edit a comment' => 'Izmeni komentar',
+ 'Summary' => 'Pregled',
+ 'Time tracking' => 'Praćenje vremena',
+ 'Estimate:' => 'Procena:',
+ 'Spent:' => 'Potrošeno:',
+ 'Do you really want to remove this sub-task?' => 'Da li da uklonim pod-zdadatak?',
+ 'Remaining:' => 'Preostalo:',
+ 'hours' => 'sati',
+ 'spent' => 'potrošeno',
+ 'estimated' => 'procenjeno',
+ 'Sub-Tasks' => 'Pod-zadaci',
+ 'Add a sub-task' => 'Dodaj pod-zadatak',
+ 'Original estimate' => 'Originalna procena',
+ 'Create another sub-task' => 'Dodaj novi pod-zadatak',
+ 'Time spent' => 'Utrošeno vreme',
+ 'Edit a sub-task' => 'Izmeni pod-zadatak',
+ 'Remove a sub-task' => 'Ukloni pod-zadatak',
+ 'The time must be a numeric value' => 'Vreme mora biti broj',
+ 'Todo' => 'Za rad',
+ 'In progress' => 'U radu',
+ 'Sub-task removed successfully.' => 'Pod-zadatak uspešno uklonjen.',
+ 'Unable to remove this sub-task.' => 'Nie można usunąć tego pod-zadania.',
+ 'Sub-task updated successfully.' => 'Pod-zadatak zaktualizowane pomyślnie.',
+ 'Unable to update your sub-task.' => 'Nie można zaktalizować tego pod-zadania.',
+ 'Unable to create your sub-task.' => 'Nie można utworzyć tego pod-zadania.',
+ 'Sub-task added successfully.' => 'Pod-zadatak utworzone pomyślnie',
+ 'Maximum size: ' => 'Maksimalna veličina: ',
+ 'Unable to upload the file.' => 'Nije moguće snimiti fajl.',
+ 'Display another project' => 'Prikaži drugi projekat',
+ 'Your GitHub account was successfully linked to your profile.' => 'Konto Github podłączone pomyślnie.',
+ 'Unable to link your GitHub Account.' => 'Nie można połączyć z kontem Github.',
+ 'GitHub authentication failed' => 'Autentykacja Github nieudana',
+ 'Your GitHub account is no longer linked to your profile.' => 'Konto Github nie jest już podłączone do twojego profilu.',
+ 'Unable to unlink your GitHub Account.' => 'Nie można odłączyć konta Github.',
+ 'Login with my GitHub Account' => 'Zaloguj przy użyciu konta Github',
+ 'Link my GitHub Account' => 'Podłącz konto Github',
+ 'Unlink my GitHub Account' => 'Odłącz konto Github',
+ 'Created by %s' => 'Kreirao %s',
+ 'Last modified on %B %e, %Y at %k:%M %p' => 'Poslednja izmena %e %B %Y o %k:%M',
+ 'Tasks Export' => 'Izvoz zadataka',
+ 'Tasks exportation for "%s"' => 'Izvoz zadataka za "%s"',
+ 'Start Date' => 'Početni datum',
+ 'End Date' => 'Krajni datum',
+ 'Execute' => 'Izvrši',
+ 'Task Id' => 'Identifikator Zadatka',
+ 'Creator' => 'Autor',
+ 'Modification date' => 'Datum izmene',
+ 'Completion date' => 'Datum kompletiranja',
+ 'Webhook URL for task creation' => 'Webhook URL zadatka za kreiranje',
+ 'Webhook URL for task modification' => 'Webhook URL zadatka za izmenu',
+ 'Clone' => 'Iskopiraj',
+ 'Clone Project' => 'Iskopiraj projekat',
+ 'Project cloned successfully.' => 'Projekat uspešno iskopiran.',
+ 'Unable to clone this project.' => 'Nije moguće iskopirati projekat.',
+ 'Email notifications' => 'Obaveštenje e-mailom',
+ 'Enable email notifications' => 'Omogući obaveštenja e-mailom',
+ 'Task position:' => 'Pozicija zadatka:',
+ 'The task #%d have been opened.' => 'Zadatak #%d je otvoren.',
+ 'The task #%d have been closed.' => 'Zadatak #$d je zatvoren.',
+ 'Sub-task updated' => 'Pod-zadatak izmenjen',
+ 'Title:' => 'Naslov:',
+ // 'Status:' => '',
+ 'Assignee:' => 'Dodeli:',
+ 'Time tracking:' => 'Praćenje vremena: ',
+ 'New sub-task' => 'Novi Pod-zadatak',
+ 'New attachment added "%s"' => 'Novi prilog ubačen "%s"',
+ 'Comment updated' => 'Komentar izmenjen',
+ 'New comment posted by %s' => 'Novi komentar ostavio %s',
+ 'List of due tasks for the project "%s"' => 'Spisak dospelih zadataka za projekat "%s"',
+ // 'New attachment' => '',
+ // 'New comment' => '',
+ // 'New subtask' => '',
+ // 'Subtask updated' => '',
+ // 'Task updated' => '',
+ 'Task closed' => 'Zadatak je zatvoren',
+ 'Task opened' => 'Zadatak je otvoren',
+ '[%s][Due tasks]' => '[%s][Dospeli zadaci]',
+ '[Kanboard] Notification' => '[Kanboard] Obaveštenja',
+ 'I want to receive notifications only for those projects:' => 'Želim obaveštenja samo za ovaj projekat:',
+ 'view the task on Kanboard' => 'Pregledaj zadatke',
+ 'Public access' => 'Javni pristup',
+ 'Category management' => 'Uređivanje kategorija',
+ 'User management' => 'Uređivanje korisnika',
+ 'Active tasks' => 'Aktivni zadaci',
+ 'Disable public access' => 'Zabrani javni pristup',
+ 'Enable public access' => 'Dozvoli javni pristup',
+ 'Active projects' => 'Aktivni projekti',
+ 'Inactive projects' => 'Neaktivni projekti',
+ 'Public access disabled' => 'Javni pristup onemogućen!',
+ 'Do you really want to disable this project: "%s"?' => 'Da li zaista želiš da deaktiviraš projekat: "%s"?',
+ 'Do you really want to duplicate this project: "%s"?' => 'Da li da napravim kopiju ovog projekta: "%s"?',
+ 'Do you really want to enable this project: "%s"?' => 'Da li zaista želiš da aktiviraš projekat: "%s"?',
+ 'Project activation' => 'Aktivacija projekta',
+ 'Move the task to another project' => 'Premesti zadatak u drugi projekat',
+ 'Move to another project' => 'Premesti u drugi projekat',
+ 'Do you really want to duplicate this task?' => 'Da li da napravim kopiju ovog projekta: "%s"?',
+ 'Duplicate a task' => 'Kopiraj zadatak',
+ 'External accounts' => 'Spoljni nalozi',
+ 'Account type' => 'Tip naloga',
+ 'Local' => 'Lokalno',
+ 'Remote' => 'Udaljno',
+ 'Enabled' => 'Omogući',
+ 'Disabled' => 'Onemogući',
+ 'Google account linked' => 'Połączone konto Google',
+ 'Github account linked' => 'Połączone konto Github',
+ 'Username:' => 'Korisničko ime:',
+ 'Name:' => 'Ime i Prezime',
+ 'Email:' => 'Email: ',
+ 'Default project:' => 'Osnovni projekat:',
+ 'Notifications:' => 'Obaveštenja: ',
+ 'Notifications' => 'Obaveštenja',
+ 'Group:' => 'Grupa:',
+ 'Regular user' => 'Standardni korisnik',
+ 'Account type:' => 'Vrsta naloga:',
+ 'Edit profile' => 'Izmeni profil',
+ 'Change password' => 'Izmeni lozinku',
+ 'Password modification' => 'Izmena lozinke',
+ 'External authentications' => 'Spoljne akcije',
+ 'Google Account' => 'Google nalog',
+ 'Github Account' => 'Github nalog',
+ 'Never connected.' => 'Bez konekcija.',
+ 'No account linked.' => 'Bez povezanih naloga.',
+ 'Account linked.' => 'Nalog povezan.',
+ 'No external authentication enabled.' => 'Bez omogućenih spoljnih autentikacija.',
+ 'Password modified successfully.' => 'Uspešna izmena lozinke.',
+ 'Unable to change the password.' => 'Nije moguće izmeniti lozinku.',
+ 'Change category for the task "%s"' => 'Izmeni kategoriju zadatka "%s"',
+ 'Change category' => 'Izmeni kategoriju',
+ '%s updated the task %s' => '%s izmeni zadatak %s',
+ '%s opened the task %s' => '%s aktivni zadaci %s',
+ '%s moved the task %s to the position #%d in the column "%s"' => '%s premešten zadatak %s na poziciju #%d u koloni "%s"',
+ '%s moved the task %s to the column "%s"' => '%s premešten zadatak %s u kolonu "%s"',
+ '%s created the task %s' => '%s kreirao zadatak %s',
+ '%s closed the task %s' => '%s zatvorio zadatak %s',
+ '%s created a subtask for the task %s' => '%s kreiran pod-zadatak zadatka %s',
+ '%s updated a subtask for the task %s' => '%s izmenjen pod-zadatak zadatka %s',
+ 'Assigned to %s with an estimate of %s/%sh' => 'Dodeljen korisniku %s uz procenu vremena %s/%sh',
+ 'Not assigned, estimate of %sh' => 'Ne dodeljen, procenjeno vreme %sh',
+ '%s updated a comment on the task %s' => '%s izmenjen komentar zadatka %s',
+ '%s commented the task %s' => '%s komentarisao zadatak %s',
+ '%s\'s activity' => 'Aktivnosti %s',
+ 'No activity.' => 'Bez aktivnosti.',
+ 'RSS feed' => 'RSS kanal',
+ '%s updated a comment on the task #%d' => '%s izmenjen komentar zadatka #%d',
+ '%s commented on the task #%d' => '%s komentarisao zadatak #%d',
+ '%s updated a subtask for the task #%d' => '%s izmenjen pod-zadatak zadatka #%d',
+ '%s created a subtask for the task #%d' => '%s kreirao pod-zadatak zadatka #%d',
+ '%s updated the task #%d' => '%s izmenjen zadatak #%d',
+ '%s created the task #%d' => '%s kreirao zadatak #%d',
+ '%s closed the task #%d' => '%s zatvorio zadatak #%d',
+ '%s open the task #%d' => '%s otvorio zadatak #%d',
+ '%s moved the task #%d to the column "%s"' => '%s premestio zadatak #%d u kolonu "%s"',
+ '%s moved the task #%d to the position %d in the column "%s"' => '%s premestio zadatak #%d na pozycję %d w kolmnie "%s"',
+ 'Activity' => 'Aktivnosti',
+ 'Default values are "%s"' => 'Osnovne vrednosti su: "%s"',
+ 'Default columns for new projects (Comma-separated)' => 'Osnovne kolone za novi projekat (Odvojeni zarezom)',
+ 'Task assignee change' => 'Zmień osobę odpowiedzialną',
+ '%s change the assignee of the task #%d to %s' => '%s zamena dodele za zadatak #%d na %s',
+ '%s changed the assignee of the task %s to %s' => '%s zamena dodele za zadatak %s na %s',
+ // 'Column Change' => '',
+ // 'Position Change' => '',
+ // 'Assignee Change' => '',
+ 'New password for the user "%s"' => 'Nova lozinka za korisnika "%s"',
+ 'Choose an event' => 'Izaberi događaj',
+ // 'Github commit received' => '',
+ // 'Github issue opened' => '',
+ // 'Github issue closed' => '',
+ // 'Github issue reopened' => '',
+ // 'Github issue assignee change' => '',
+ // 'Github issue label change' => '',
+ 'Create a task from an external provider' => 'Kreiraj zadatak preko posrednika',
+ 'Change the assignee based on an external username' => 'Zmień osobę odpowiedzialną na podstawie zewnętrznej nazwy użytkownika',
+ 'Change the category based on an external label' => 'Zmień kategorię na podstawie zewnętrzenj etykiety',
+ // 'Reference' => '',
+ // 'Reference: %s' => '',
+ 'Label' => 'Etikieta',
+ 'Database' => 'Baza',
+ 'About' => 'Informacje',
+ 'Database driver:' => 'Database driver:',
+ 'Board settings' => 'Podešavanje table',
+ 'URL and token' => 'URL i token',
+ // 'Webhook settings' => '',
+ 'URL for task creation:' => 'URL za kreiranje zadataka',
+ 'Reset token' => 'Resetuj token',
+ // 'API endpoint:' => '',
+ 'Refresh interval for private board' => 'Interval osvežavanja privatnih tabli',
+ 'Refresh interval for public board' => 'Interval osvežavanja javnih tabli',
+ 'Task highlight period' => 'Task highlight period',
+ // 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
+ // 'Frequency in second (60 seconds by default)' => '',
+ // 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
+ 'Application URL' => 'Adres URL aplikacji',
+ 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Primer: http://example.kanboard.net/ (koristi se u obaveštenjima putem mail-a)',
+ 'Token regenerated.' => 'Token wygenerowany ponownie.',
+ 'Date format' => 'Format daty',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'Format ISO je uvek prihvatljiv, primer: "%s", "%s"',
+ 'New private project' => 'Novi privatni projekat',
+ 'This project is private' => 'Ovaj projekat je privatan',
+ 'Type here to create a new sub-task' => 'Kucaj ovde za kreiranje novog pod-zadatka',
+ 'Add' => 'Dodaj',
+ 'Estimated time: %s hours' => 'Procenjeno vreme: %s godzin',
+ 'Time spent: %s hours' => 'Utrošeno vreme: %s godzin',
+ 'Started on %B %e, %Y' => 'Započeto dana %e %B %Y',
+ 'Start date' => 'Datum početka',
+ 'Time estimated' => 'Procenjeno vreme',
+ 'There is nothing assigned to you.' => 'Ništa vam nije dodeljeno',
+ 'My tasks' => 'Moji zadaci',
+ 'Activity stream' => 'Spisak aktinosti',
+ 'Dashboard' => 'Panel',
+ 'Confirmation' => 'Potvrda',
+ 'Allow everybody to access to this project' => 'Dozvoli svima pristup projektu',
+ 'Everybody have access to this project.' => 'Svima je dozvoljen pristup.',
+ // 'Webhooks' => '',
+ // 'API' => '',
+ 'Integration' => 'Integracja',
+ // 'Github webhooks' => '',
+ // 'Help on Github webhooks' => '',
+ // 'Create a comment from an external provider' => '',
+ // 'Github issue comment created' => '',
+ 'Configure' => 'Podesi',
+ 'Project management' => 'Uređivanje projekata',
+ 'My projects' => 'Moji projekti',
+ 'Columns' => 'Kolone',
+ 'Task' => 'Zadaci',
+ 'Your are not member of any project.' => 'Nisi član ni jednog projekta',
+ 'Percentage' => 'Procenat',
+ 'Number of tasks' => 'Broj zadataka',
+ 'Task distribution' => 'Podela zadataka',
+ 'Reportings' => 'Izveštaji',
+ 'Task repartition for "%s"' => 'Zaduženja zadataka za "%s"',
+ 'Analytics' => 'Analiza',
+ 'Subtask' => 'Pod-zadatak',
+ 'My subtasks' => 'Moji pod-zadaci',
+ 'User repartition' => 'Zaduženja korisnika',
+ 'User repartition for "%s"' => 'Zaduženja korisnika za "%s"',
+ 'Clone this project' => 'Kopiraj projekat',
+ 'Column removed successfully.' => 'Kolumna usunięta pomyslnie.',
+ 'Edit Project' => 'Izmeni projekat',
+ // 'Github Issue' => '',
+ 'Not enough data to show the graph.' => 'Nedovoljno podataka za grafikon.',
+ 'Previous' => 'Prethodni',
+ 'The id must be an integer' => 'ID musi być liczbą całkowitą',
+ 'The project id must be an integer' => 'ID projektu musi być liczbą całkowitą',
+ 'The status must be an integer' => 'Status musi być liczbą całkowitą',
+ 'The subtask id is required' => 'ID pod-zadatak jest wymagane',
+ 'The subtask id must be an integer' => 'ID pod-zadania musi być liczbą całkowitą',
+ 'The task id is required' => 'ID zadania jest wymagane',
+ 'The task id must be an integer' => 'ID zadatka mora biti broj',
+ 'The user id must be an integer' => 'ID korisnika mora biti broj',
+ 'This value is required' => 'Vrednost je obavezna',
+ 'This value must be numeric' => 'Vrednost mora biti broj',
+ 'Unable to create this task.' => 'Nije moguće kreirati zadatak.',
+ 'Cumulative flow diagram' => 'Zbirni dijagram toka',
+ 'Cumulative flow diagram for "%s"' => 'Zbirni dijagram toka za "%s"',
+ 'Daily project summary' => 'Zbirni pregled po danima',
+ 'Daily project summary export' => 'Izvoz zbirnog pregleda po danima',
+ 'Daily project summary export for "%s"' => 'Izvoz zbirnig pregleda po danima za "%s"',
+ 'Exports' => 'Izvoz',
+ // 'This export contains the number of tasks per column grouped per day.' => '',
+ 'Nothing to preview...' => 'Ništa za prikazivanje...',
+ 'Preview' => 'Pregled',
+ 'Write' => 'Piši',
+ 'Active swimlanes' => 'Aktivni razdelnik',
+ 'Add a new swimlane' => 'Dodaj razdelnik',
+ 'Change default swimlane' => 'Zameni osnovni razdelnik',
+ 'Default swimlane' => 'Osnovni razdelnik',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Da li da uklonim razdelnik: "%s"?',
+ 'Inactive swimlanes' => 'Neaktivni razdelniki',
+ 'Set project manager' => 'Podesi menadžera projekta',
+ 'Set project member' => 'Podesi učesnika projekat',
+ 'Remove a swimlane' => 'Ukloni razdelnik',
+ 'Rename' => 'Preimenuj',
+ 'Show default swimlane' => 'Prikaži osnovni razdelnik',
+ 'Swimlane modification for the project "%s"' => 'Izmena razdelnika za projekat "%s"',
+ 'Swimlane not found.' => 'Razdelnik nije pronađen.',
+ 'Swimlane removed successfully.' => 'Razdelnik uspešno uklonjen.',
+ 'Swimlanes' => 'Razdelnici',
+ 'Swimlane updated successfully.' => 'Razdelnik zaktualizowany pomyślnie.',
+ // 'The default swimlane have been updated successfully.' => '',
+ // 'Unable to create your swimlane.' => '',
+ // 'Unable to remove this swimlane.' => '',
+ // 'Unable to update this swimlane.' => '',
+ 'Your swimlane have been created successfully.' => 'Razdelnik je uspešno kreiran.',
+ 'Example: "Bug, Feature Request, Improvement"' => 'Npr: "Greška, Zahtev za izmenama, Poboljšanje"',
+ 'Default categories for new projects (Comma-separated)' => 'Osnovne kategorije za projekat',
+ // 'Gitlab commit received' => '',
+ // 'Gitlab issue opened' => '',
+ // 'Gitlab issue closed' => '',
+ // 'Gitlab webhooks' => '',
+ // 'Help on Gitlab webhooks' => '',
+ 'Integrations' => 'Integracje',
+ 'Integration with third-party services' => 'Integracja sa uslugama spoljnih servisa',
+ 'Role for this project' => 'Uloga u ovom projektu',
+ 'Project manager' => 'Manadžer projekta',
+ 'Project member' => 'Učesnik projekta',
+ // 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
+ // 'Gitlab Issue' => '',
+ 'Subtask Id' => 'ID pod-zadania',
+ 'Subtasks' => 'Pod-zadataka',
+ 'Subtasks Export' => 'Eksport pod-zadań',
+ 'Subtasks exportation for "%s"' => 'Izvoz pod-zadań dla "%s"',
+ 'Task Title' => 'Naslov zadatka',
+ 'Untitled' => 'Bez naslova',
+ 'Application default' => 'Postavke aplikacje',
+ 'Language:' => 'Jezik:',
+ 'Timezone:' => 'Vremenska zona:',
+ 'All columns' => 'Sve kolone',
+ 'Calendar for "%s"' => 'Kalendar za "%s"',
+ 'Filter by column' => 'Po koloni',
+ 'Filter by status' => 'Po statusu',
+ 'Calendar' => 'Kalendar',
+ 'Next' => 'Sledeći',
+ // '#%d' => '',
+ 'Filter by color' => 'Po boji',
+ 'Filter by swimlane' => 'Po razdelniku',
+ 'All swimlanes' => 'Svi razdelniki',
+ 'All colors' => 'Sve boje',
+ 'All status' => 'Svi statusi',
+ 'Add a comment logging moving the task between columns' => 'Dodaj logovanje premeštanja zadataka po kolonama',
+ 'Moved to column %s' => 'Premešten u kolonu %s',
+ // 'Change description' => '',
+ 'User dashboard' => 'Korisnički panel',
+ // 'Allow only one subtask in progress at the same time for a user' => '',
+ // 'Edit column "%s"' => '',
+ // 'Enable time tracking for subtasks' => '',
+ // 'Select the new status of the subtask: "%s"' => '',
+ // 'Subtask timesheet' => '',
+ 'There is nothing to show.' => 'Nema podataka',
+ 'Time Tracking' => 'Praćenje vremena',
+ // 'You already have one subtask in progress' => '',
+ 'Which parts of the project do you want to duplicate?' => 'Koje delove projekta želite da kopirate',
+ // 'Change dashboard view' => '',
+ // 'Show/hide activities' => '',
+ // 'Show/hide projects' => '',
+ // 'Show/hide subtasks' => '',
+ // 'Show/hide tasks' => '',
+ // 'Disable login form' => '',
+ // 'Show/hide calendar' => '',
+ // 'User calendar' => '',
+ // 'Bitbucket commit received' => '',
+ // 'Bitbucket webhooks' => '',
+ // 'Help on Bitbucket webhooks' => '',
+ // 'Start' => '',
+ // 'End' => '',
+ // 'Task age in days' => '',
+ // 'Days in this column' => '',
+ // '%dd' => '',
+ 'Add a link' => 'Dodaj link',
+ // 'Add a new link' => '',
+ // 'Do you really want to remove this link: "%s"?' => '',
+ // 'Do you really want to remove this link with task #%d?' => '',
+ // 'Field required' => '',
+ // 'Link added successfully.' => '',
+ // 'Link updated successfully.' => '',
+ // 'Link removed successfully.' => '',
+ // 'Link labels' => '',
+ // 'Link modification' => '',
+ // 'Links' => '',
+ // 'Link settings' => '',
+ // 'Opposite label' => '',
+ // 'Remove a link' => '',
+ // 'Task\'s links' => '',
+ // 'The labels must be different' => '',
+ // 'There is no link.' => '',
+ // 'This label must be unique' => '',
+ // 'Unable to create your link.' => '',
+ // 'Unable to update your link.' => '',
+ // 'Unable to remove this link.' => '',
+ // 'relates to' => '',
+ // 'blocks' => '',
+ // 'is blocked by' => '',
+ // 'duplicates' => '',
+ // 'is duplicated by' => '',
+ // 'is a child of' => '',
+ // 'is a parent of' => '',
+ // 'targets milestone' => '',
+ // 'is a milestone of' => '',
+ // 'fixes' => '',
+ // 'is fixed by' => '',
+ // 'This task' => '',
+ // '<1h' => '',
+ // '%dh' => '',
+ // '%b %e' => '',
+ // 'Expand tasks' => '',
+ // 'Collapse tasks' => '',
+ // 'Expand/collapse tasks' => '',
+ // 'Close dialog box' => '',
+ // 'Submit a form' => '',
+ // 'Board view' => '',
+ // 'Keyboard shortcuts' => '',
+ // 'Open board switcher' => '',
+ // 'Application' => '',
+ // 'Filter recently updated' => '',
+ // 'since %B %e, %Y at %k:%M %p' => '',
+ // 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
+);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 2fcc3ce5..5b3b31c3 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'Ingen',
'edit' => 'redigera',
'Edit' => 'Redigera',
@@ -408,13 +410,13 @@ return array(
'Comment updated' => 'Kommentaren har uppdaterats',
'New comment posted by %s' => 'Ny kommentar postad av %s',
'List of due tasks for the project "%s"' => 'Lista med uppgifter för projektet "%s"',
- // 'New attachment' => '',
- // 'New comment' => '',
- // 'New subtask' => '',
- // 'Subtask updated' => '',
- // 'Task updated' => '',
- // 'Task closed' => '',
- // 'Task opened' => '',
+ 'New attachment' => 'Ny bifogning',
+ 'New comment' => 'Ny kommentar',
+ 'New subtask' => 'Ny deluppgift',
+ 'Subtask updated' => 'Deluppgiften har uppdaterats',
+ 'Task updated' => 'Uppgiften har uppdaterats',
+ 'Task closed' => 'Uppgiften har stängts',
+ 'Task opened' => 'Uppgiften har öppnats',
'[%s][Due tasks]' => '[%s][Förfallen uppgift]',
'[Kanboard] Notification' => '[Kanboard] Notis',
'I want to receive notifications only for those projects:' => 'Jag vill endast få notiser för dessa projekt:',
@@ -498,9 +500,9 @@ return array(
'Task assignee change' => 'Ändra tilldelning av uppgiften',
'%s change the assignee of the task #%d to %s' => '%s byt tilldelning av uppgiften #%d till %s',
'%s changed the assignee of the task %s to %s' => '%s byt tilldelning av uppgiften %s till %s',
- // 'Column Change' => '',
- // 'Position Change' => '',
- // 'Assignee Change' => '',
+ 'Column Change' => 'Ändring av kolumn',
+ 'Position Change' => 'Ändring av position',
+ 'Assignee Change' => 'Ändring av tilldelning',
'New password for the user "%s"' => 'Nytt lösenord för användaren "%s"',
'Choose an event' => 'Välj en händelse',
'Github commit received' => 'Github-bidrag mottaget',
@@ -645,93 +647,161 @@ return array(
'Application default' => 'Applikationsstandard',
'Language:' => 'Språk',
'Timezone:' => 'Tidszon',
- // 'All columns' => '',
- // 'Calendar for "%s"' => '',
- // 'Filter by column' => '',
- // 'Filter by status' => '',
- // 'Calendar' => '',
+ 'All columns' => 'Alla kolumner',
+ 'Calendar for "%s"' => 'Kalender för "%s"',
+ 'Filter by column' => 'Filtrera på kolumn',
+ 'Filter by status' => 'Filtrera på status',
+ 'Calendar' => 'Kalender',
'Next' => 'Nästa',
- // '#%d' => '',
- // 'Filter by color' => '',
- // 'Filter by swimlane' => '',
- // 'All swimlanes' => '',
- // 'All colors' => '',
- // 'All status' => '',
- // 'Add a comment logging moving the task between columns' => '',
- // 'Moved to column %s' => '',
- // 'Change description' => '',
- // 'User dashboard' => '',
- // 'Allow only one subtask in progress at the same time for a user' => '',
- // 'Edit column "%s"' => '',
- // 'Enable time tracking for subtasks' => '',
- // 'Select the new status of the subtask: "%s"' => '',
- // 'Subtask timesheet' => '',
- // 'There is nothing to show.' => '',
- // 'Time Tracking' => '',
- // 'You already have one subtask in progress' => '',
- // 'Which parts of the project do you want to duplicate?' => '',
- // 'Change dashboard view' => '',
- // 'Show/hide activities' => '',
- // 'Show/hide projects' => '',
- // 'Show/hide subtasks' => '',
- // 'Show/hide tasks' => '',
- // 'Disable login form' => '',
- // 'Show/hide calendar' => '',
- // 'User calendar' => '',
- // 'Bitbucket commit received' => '',
- // 'Bitbucket webhooks' => '',
- // 'Help on Bitbucket webhooks' => '',
- // 'Start' => '',
- // 'End' => '',
- // 'Task age in days' => '',
- // 'Days in this column' => '',
- // '%dd' => '',
- // 'Add a link' => '',
- // 'Add a new link' => '',
- // 'Do you really want to remove this link: "%s"?' => '',
- // 'Do you really want to remove this link with task #%d?' => '',
- // 'Field required' => '',
- // 'Link added successfully.' => '',
- // 'Link updated successfully.' => '',
- // 'Link removed successfully.' => '',
- // 'Link labels' => '',
- // 'Link modification' => '',
- // 'Links' => '',
- // 'Link settings' => '',
- // 'Opposite label' => '',
- // 'Remove a link' => '',
- // 'Task\'s links' => '',
- // 'The labels must be different' => '',
- // 'There is no link.' => '',
- // 'This label must be unique' => '',
- // 'Unable to create your link.' => '',
- // 'Unable to update your link.' => '',
- // 'Unable to remove this link.' => '',
- // 'relates to' => '',
- // 'blocks' => '',
- // 'is blocked by' => '',
- // 'duplicates' => '',
- // 'is duplicated by' => '',
- // 'is a child of' => '',
- // 'is a parent of' => '',
- // 'targets milestone' => '',
- // 'is a milestone of' => '',
- // 'fixes' => '',
- // 'is fixed by' => '',
- // 'This task' => '',
- // '<1h' => '',
- // '%dh' => '',
- // '%b %e' => '',
- // 'Expand tasks' => '',
- // 'Collapse tasks' => '',
- // 'Expand/collapse tasks' => '',
- // 'Close dialog box' => '',
- // 'Submit a form' => '',
- // 'Board view' => '',
- // 'Keyboard shortcuts' => '',
- // 'Open board switcher' => '',
- // 'Application' => '',
- // 'Filter recently updated' => '',
- // 'since %B %e, %Y at %k:%M %p' => '',
- // 'More filters' => '',
+ '#%d' => '#%d',
+ 'Filter by color' => 'Filtrera på färg',
+ 'Filter by swimlane' => 'Filtrera på swimlane',
+ 'All swimlanes' => 'Alla swimlanes',
+ 'All colors' => 'Alla färger',
+ 'All status' => 'Alla status',
+ 'Add a comment logging moving the task between columns' => 'Lägg till en kommentar för att logga förflyttning av en uppgift mellan kolumner',
+ 'Moved to column %s' => 'Flyttad till kolumn %s',
+ 'Change description' => 'Ändra beskrivning',
+ 'User dashboard' => 'Användardashboard',
+ 'Allow only one subtask in progress at the same time for a user' => 'Tillåt endast en deluppgift igång samtidigt för en användare',
+ 'Edit column "%s"' => 'Ändra kolumn "%s"',
+ 'Enable time tracking for subtasks' => 'Aktivera tidsbevakning för deluppgifter',
+ 'Select the new status of the subtask: "%s"' => 'Välj ny status för deluppgiften: "%s"',
+ 'Subtask timesheet' => 'Tidrapport för deluppgiften',
+ 'There is nothing to show.' => 'Det finns inget att visa',
+ 'Time Tracking' => 'Tidsbevakning',
+ 'You already have one subtask in progress' => 'Du har redan en deluppgift igång',
+ 'Which parts of the project do you want to duplicate?' => 'Vilka delar av projektet vill du duplicera?',
+ 'Change dashboard view' => 'Ändra dashboard vy',
+ 'Show/hide activities' => 'Visa/dölj aktiviteter',
+ 'Show/hide projects' => 'Visa/dölj projekt',
+ 'Show/hide subtasks' => 'Visa/dölj deluppgifter',
+ 'Show/hide tasks' => 'Visa/dölj uppgifter',
+ 'Disable login form' => 'Inaktivera loginformuläret',
+ 'Show/hide calendar' => 'Visa/dölj kalender',
+ 'User calendar' => 'Användarkalender',
+ 'Bitbucket commit received' => 'Bitbucket bidrag mottaget',
+ 'Bitbucket webhooks' => 'Bitbucket webhooks',
+ 'Help on Bitbucket webhooks' => 'Hjälp för Bitbucket webhooks',
+ 'Start' => 'Start',
+ 'End' => 'Slut',
+ 'Task age in days' => 'Uppgiftsålder i dagar',
+ 'Days in this column' => 'Dagar i denna kolumn',
+ '%dd' => '%dd',
+ 'Add a link' => 'Lägg till länk',
+ 'Add a new link' => 'Lägg till ny länk',
+ 'Do you really want to remove this link: "%s"?' => 'Vill du verkligen ta bort länken: "%s"?',
+ 'Do you really want to remove this link with task #%d?' => 'Vill du verkligen ta bort länken till uppgiften #%d?',
+ 'Field required' => 'Fältet krävs',
+ 'Link added successfully.' => 'Länken har lagts till',
+ 'Link updated successfully.' => 'Länken har uppdaterats',
+ 'Link removed successfully.' => 'Länken har tagits bort',
+ 'Link labels' => 'Länketiketter',
+ 'Link modification' => 'Länkändring',
+ 'Links' => 'Länkar',
+ 'Link settings' => 'Länkinställningar',
+ 'Opposite label' => 'Motpartslänk',
+ 'Remove a link' => 'Ta bort en länk',
+ 'Task\'s links' => 'Uppgiftslänkar',
+ 'The labels must be different' => 'Etiketterna måste vara olika',
+ 'There is no link.' => 'Det finns ingen länk',
+ 'This label must be unique' => 'Länken måste vara unik',
+ 'Unable to create your link.' => 'Kunde inte skapa din länk',
+ 'Unable to update your link.' => 'Kunde inte uppdatera din länk',
+ 'Unable to remove this link.' => 'Kunde inte ta bort din länk',
+ 'relates to' => 'relaterar till',
+ 'blocks' => 'blockerar',
+ 'is blocked by' => 'blockeras av',
+ 'duplicates' => 'dupplicerar',
+ 'is duplicated by' => 'är duplicerad av',
+ 'is a child of' => 'är underliggande till',
+ 'is a parent of' => 'är överliggande till',
+ 'targets milestone' => 'milstolpemål',
+ 'is a milestone of' => 'är en milstolpe för',
+ 'fixes' => 'åtgärdar',
+ 'is fixed by' => 'åtgärdas av',
+ 'This task' => 'Denna uppgift',
+ '<1h' => '<1h',
+ '%dh' => '%dh',
+ '%b %e' => '%b %e',
+ 'Expand tasks' => 'Expandera uppgifter',
+ 'Collapse tasks' => 'Minimera uppgifter',
+ 'Expand/collapse tasks' => 'Expandera/minimera uppgifter',
+ 'Close dialog box' => 'Stäng dialogruta',
+ 'Submit a form' => 'Sänd formulär',
+ 'Board view' => 'Tavelvy',
+ 'Keyboard shortcuts' => 'Tangentbordsgenvägar',
+ 'Open board switcher' => 'Växling av öppen tavla',
+ 'Application' => 'Applikation',
+ 'Filter recently updated' => 'Filter som uppdaterats nyligen',
+ 'since %B %e, %Y at %k:%M %p' => 'sedan %B %e, %Y at %k:%M %p',
+ 'More filters' => 'Fler filter',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 1945f043..4b41e625 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => 'ไม่มี',
'edit' => 'แก้ไข',
'Edit' => 'แก้ไข',
@@ -734,4 +736,72 @@ return array(
// 'Filter recently updated' => '',
// 'since %B %e, %Y at %k:%M %p' => '',
// 'More filters' => '',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
new file mode 100644
index 00000000..488526f0
--- /dev/null
+++ b/app/Locale/tr_TR/translations.php
@@ -0,0 +1,807 @@
+<?php
+
+return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
+ 'None' => 'Hiçbiri',
+ 'edit' => 'düzenle',
+ 'Edit' => 'Düzenle',
+ 'remove' => 'sil',
+ 'Remove' => 'Sil',
+ 'Update' => 'Güncelle',
+ 'Yes' => 'Evet',
+ 'No' => 'Hayır',
+ 'cancel' => 'İptal',
+ 'or' => 'veya',
+ 'Yellow' => 'Sarı',
+ 'Blue' => 'Mavi',
+ 'Green' => 'Yeşil',
+ 'Purple' => 'Mor',
+ 'Red' => 'Kırmızı',
+ 'Orange' => 'Turuncu',
+ 'Grey' => 'Gri',
+ 'Save' => 'Kaydet',
+ 'Login' => 'Giriş',
+ 'Official website:' => 'Resmi internet sitesi:',
+ 'Unassigned' => 'Atanmamış',
+ 'View this task' => 'Bu görevi görüntüle',
+ 'Remove user' => 'Kullanıcıyı kaldır',
+ 'Do you really want to remove this user: "%s"?' => 'Bu kullanıcıyı gerçekten silmek istiyor musunuz: "%s"?',
+ 'New user' => 'Yeni kullanıcı',
+ 'All users' => 'Tüm kullanıcılar',
+ 'Username' => 'Kullanıcı adı',
+ 'Password' => 'Şifre',
+ // 'Default project' => '',
+ 'Administrator' => 'Yönetici',
+ 'Sign in' => 'Giriş yap',
+ 'Users' => 'Kullanıcılar',
+ 'No user' => 'Kullanıcı yok',
+ 'Forbidden' => 'Yasak',
+ 'Access Forbidden' => 'Erişim yasak',
+ 'Only administrators can access to this page.' => 'Bu sayfaya yalnızca yöneticiler erişebilir.',
+ 'Edit user' => 'Kullanıcıyı düzenle',
+ 'Logout' => 'Çıkış yap',
+ 'Bad username or password' => 'Hatalı kullanıcı adı veya şifre',
+ 'users' => 'kullanıcılar',
+ 'projects' => 'projeler',
+ 'Edit project' => 'Projeyi düzenle',
+ 'Name' => 'İsim',
+ 'Activated' => 'Aktif',
+ 'Projects' => 'Projeler',
+ 'No project' => 'Proje yok',
+ 'Project' => 'Proje',
+ 'Status' => 'Durum',
+ 'Tasks' => 'Görevler',
+ 'Board' => 'Tablo',
+ 'Actions' => 'İşlemler',
+ 'Inactive' => 'Aktif değil',
+ 'Active' => 'Aktif',
+ 'Column %d' => 'Sütun %d',
+ 'Add this column' => 'Bu sütunu ekle',
+ '%d tasks on the board' => '%d görev bu tabloda',
+ '%d tasks in total' => '%d görev toplam',
+ 'Unable to update this board.' => 'Bu tablo güncellenemiyor.',
+ 'Edit board' => 'Tabloyu düzenle',
+ 'Disable' => 'Devre dışı bırak',
+ 'Enable' => 'Etkinleştir',
+ 'New project' => 'Yeni proje',
+ 'Do you really want to remove this project: "%s"?' => 'Bu projeyi gerçekten silmek istiyor musunuz: "%s"?',
+ 'Remove project' => 'Projeyi sil',
+ 'Boards' => 'Tablolar',
+ 'Edit the board for "%s"' => 'Tabloyu "%s" için güncelle',
+ 'All projects' => 'Tüm projeler',
+ 'Change columns' => 'Sütunları değiştir',
+ 'Add a new column' => 'Yeni sütun ekle',
+ 'Title' => 'Başlık',
+ 'Add Column' => 'Sütun ekle',
+ 'Project "%s"' => 'Proje "%s"',
+ 'Nobody assigned' => 'Kullanıcı atanmamış',
+ 'Assigned to %s' => '%s kullanıcısına atanmış',
+ 'Remove a column' => 'Bir sütunu sil',
+ 'Remove a column from a board' => 'Tablodan bir sütunu sil',
+ 'Unable to remove this column.' => 'Bu sütun silinemiyor.',
+ 'Do you really want to remove this column: "%s"?' => 'Bu sütunu gerçekten silmek istiyor musunuz: "%s"?',
+ 'This action will REMOVE ALL TASKS associated to this column!' => 'Bu komut sütun içindeki TÜM GÖREVLERİ silecek!',
+ 'Settings' => 'Ayarlar',
+ 'Application settings' => 'Uygulama ayarları',
+ 'Language' => 'Dil',
+ // 'Webhook token:' => '',
+ 'API token:' => 'API Token:',
+ 'More information' => 'Daha fazla bilgi',
+ 'Database size:' => 'Veritabanı boyutu :',
+ 'Download the database' => 'Veritabanını indir',
+ 'Optimize the database' => 'Veritabanını optimize et',
+ '(VACUUM command)' => '(VACUUM komutu)',
+ '(Gzip compressed Sqlite file)' => '(Gzip ile sıkıştırılmış Sqlite dosyası)',
+ 'User settings' => 'Kullanıcı ayarları',
+ 'My default project:' => 'Benim varsayılan projem:',
+ 'Close a task' => 'Bir görevi kapat',
+ 'Do you really want to close this task: "%s"?' => 'Bu görevi gerçekten kapatmak istiyor musunuz: "%s"?',
+ 'Edit a task' => 'Bir görevi düzenle',
+ 'Column' => 'Sütun',
+ 'Color' => 'Renk',
+ 'Assignee' => 'Atanan',
+ 'Create another task' => 'Başka bir görev oluştur',
+ 'New task' => 'Nouvelle tâche',
+ 'Open a task' => 'Bir görevi aç',
+ 'Do you really want to open this task: "%s"?' => 'Bu görevi gerçekten açmak istiyor musunuz: "%s"?',
+ 'Back to the board' => 'Tabloya dön',
+ // 'Created on %B %e, %Y at %k:%M %p' => '',
+ 'There is nobody assigned' => 'Kimse atanmamış',
+ 'Column on the board:' => 'Tablodaki sütun:',
+ 'Status is open' => 'Açık durumda',
+ 'Status is closed' => 'Kapalı durumda',
+ 'Close this task' => 'Görevi kapat',
+ 'Open this task' => 'Görevi aç',
+ 'There is no description.' => 'Açıklama yok.',
+ 'Add a new task' => 'Yeni görev ekle',
+ 'The username is required' => 'Kullanıcı adı gerekli',
+ 'The maximum length is %d characters' => 'Maksimum uzunluk %d karakterdir',
+ 'The minimum length is %d characters' => 'Minimum uzunluk %d karakterdir',
+ 'The password is required' => 'Şifre gerekli',
+ 'This value must be an integer' => 'Bu değer bir rakam olmak zorunda',
+ 'The username must be unique' => 'Kullanıcı adı daha önceden var',
+ 'The username must be alphanumeric' => 'Kullanıcı adı alfanumerik olmalı (geçersiz karakter var)',
+ 'The user id is required' => 'Kullanıcı kodu gerekli',
+ 'Passwords don\'t match' => 'Şifreler uyuşmuyor',
+ 'The confirmation is required' => 'Onay gerekli',
+ 'The column is required' => 'Sütun gerekli',
+ 'The project is required' => 'Proje gerekli',
+ 'The color is required' => 'Renk gerekli',
+ 'The id is required' => 'Kod gerekli',
+ 'The project id is required' => 'Proje kodu gerekli',
+ 'The project name is required' => 'Proje adı gerekli',
+ 'This project must be unique' => 'Bu projenin tekil olması gerekli',
+ 'The title is required' => 'Başlık gerekli',
+ 'The language is required' => 'Dil seçimi gerekli',
+ 'There is no active project, the first step is to create a new project.' => 'Aktif bir proje yok. İlk aşama yeni bir proje oluşturmak olmalı.',
+ 'Settings saved successfully.' => 'Ayarlar başarıyla kaydedildi.',
+ 'Unable to save your settings.' => 'Ayarlarınız kaydedilemedi.',
+ 'Database optimization done.' => 'Veritabanı optimizasyonu tamamlandı.',
+ 'Your project have been created successfully.' => 'Projeniz başarıyla oluşturuldu.',
+ 'Unable to create your project.' => 'Proje oluşturulamadı.',
+ 'Project updated successfully.' => 'Proje başarıyla güncellendi.',
+ 'Unable to update this project.' => 'Bu proje güncellenemedi.',
+ 'Unable to remove this project.' => 'Bu proje silinemedi.',
+ 'Project removed successfully.' => 'Proje başarıyla silindi.',
+ 'Project activated successfully.' => 'Proje başarıyla aktive edildi.',
+ 'Unable to activate this project.' => 'Bu proje aktive edilemedi.',
+ 'Project disabled successfully.' => 'Proje devre dışı bırakıldı.',
+ 'Unable to disable this project.' => 'Bu proje devre dışı bırakılamadı.',
+ 'Unable to open this task.' => 'Bu görev açılamıyor.',
+ 'Task opened successfully.' => 'Görev başarıyla açıldı.',
+ 'Unable to close this task.' => 'Bu görev kapatılamıyor.',
+ 'Task closed successfully.' => 'Görev başarıyla kapatıldı.',
+ 'Unable to update your task.' => 'Görev güncellenemiyor.',
+ 'Task updated successfully.' => 'Görev başarıyla güncellendi.',
+ 'Unable to create your task.' => 'Görev oluşturulamadı.',
+ 'Task created successfully.' => 'Görev başarıyla oluşturuldu.',
+ 'User created successfully.' => 'Kullanıcı başarıyla oluşturuldu',
+ 'Unable to create your user.' => 'Kullanıcı oluşturulamıyor.',
+ 'User updated successfully.' => 'Kullanıcı başarıyla güncellendi.',
+ 'Unable to update your user.' => 'Kullanıcı güncellenemiyor.',
+ 'User removed successfully.' => 'Kullanıcı silindi.',
+ 'Unable to remove this user.' => 'Bu kullanıcı silinemiyor.',
+ 'Board updated successfully.' => 'Tablo başarıyla güncellendi.',
+ 'Ready' => 'Hazır',
+ 'Backlog' => 'Bekleme listesi',
+ 'Work in progress' => 'İşlemde',
+ 'Done' => 'Tamamlandı',
+ 'Application version:' => 'Uygulama versiyonu:',
+ // 'Completed on %B %e, %Y at %k:%M %p' => '',
+ // '%B %e, %Y at %k:%M %p' => '',
+ 'Date created' => 'Oluşturulma tarihi',
+ 'Date completed' => 'Tamamlanma tarihi',
+ 'Id' => 'Kod',
+ 'No task' => 'Görev yok',
+ 'Completed tasks' => 'Tamamlanan görevler',
+ 'List of projects' => 'Proje listesi',
+ 'Completed tasks for "%s"' => '"%s" için tamamlanan görevler',
+ '%d closed tasks' => '%d kapatılmış görevler',
+ // 'No task for this project' => '',
+ 'Public link' => 'Dışa açık link',
+ 'There is no column in your project!' => 'Projenizde hiç sütun yok',
+ 'Change assignee' => 'Atanmış Kullanıcıyı değiştir',
+ 'Change assignee for the task "%s"' => '"%s" görevi için atanmış kullanıcıyı değiştir',
+ 'Timezone' => 'Saat dilimi',
+ // 'Sorry, I didn\'t find this information in my database!' => '',
+ 'Page not found' => 'Sayfa bulunamadı',
+ 'Complexity' => 'Zorluk seviyesi',
+ 'limit' => 'limit',
+ 'Task limit' => 'Görev limiti',
+ 'Task count' => 'Görev sayısı',
+ 'This value must be greater than %d' => 'Bu değer %d den büyük olmalı',
+ 'Edit project access list' => 'Proje erişim listesini düzenle',
+ 'Edit users access' => 'Kullanıcı erişim haklarını düzenle',
+ 'Allow this user' => 'Bu kullanıcıya izin ver',
+ 'Only those users have access to this project:' => 'Bu projeye yalnızca şu kullanıcılar erişebilir:',
+ 'Don\'t forget that administrators have access to everything.' => 'Dikkat: Yöneticilerin herşeye erişimi olduğunu unutmayın!',
+ 'Revoke' => 'Iptal et',
+ 'List of authorized users' => 'Yetkili kullanıcıların listesi',
+ 'User' => 'Kullanıcı',
+ 'Nobody have access to this project.' => 'Bu projeye kimsenin erişimi yok.',
+ 'You are not allowed to access to this project.' => 'Bu projeye giriş yetkiniz yok.',
+ 'Comments' => 'Yorumlar',
+ 'Post comment' => 'Yorum ekle',
+ 'Write your text in Markdown' => 'Yazınızı Markdown ile yazın',
+ 'Leave a comment' => 'Bir yorum ekle',
+ 'Comment is required' => 'Yorum gerekli',
+ 'Leave a description' => 'Açıklama ekleyin',
+ 'Comment added successfully.' => 'Yorum eklendi',
+ 'Unable to create your comment.' => 'Yorumunuz oluşturulamadı',
+ 'The description is required' => 'Açıklama gerekli',
+ 'Edit this task' => 'Bu görevi değiştir',
+ 'Due Date' => 'Termin',
+ 'Invalid date' => 'Geçersiz tarihi',
+ // 'Must be done before %B %e, %Y' => '',
+ '%B %e, %Y' => '%d %B %Y',
+ '%b %e, %Y' => '%d/%m/%Y',
+ 'Automatic actions' => 'Otomatik işlemler',
+ 'Your automatic action have been created successfully.' => 'Otomatik işlem başarıyla oluşturuldu',
+ 'Unable to create your automatic action.' => 'Otomatik işleminiz oluşturulamadı',
+ 'Remove an action' => 'Bir işlemi sil',
+ 'Unable to remove this action.' => 'Bu işlem silinemedi',
+ 'Action removed successfully.' => 'İşlem başarıyla silindi',
+ 'Automatic actions for the project "%s"' => '"%s" projesi için otomatik işlemler',
+ 'Defined actions' => 'Tanımlanan işlemler',
+ 'Add an action' => 'İşlem ekle',
+ 'Event name' => 'Durum adı',
+ 'Action name' => 'İşlem adı',
+ 'Action parameters' => 'İşlem parametreleri',
+ 'Action' => 'İşlem',
+ 'Event' => 'Durum',
+ 'When the selected event occurs execute the corresponding action.' => 'Seçilen durum oluştuğunda ilgili eylemi gerçekleştir.',
+ 'Next step' => 'Sonraki adım',
+ 'Define action parameters' => 'İşlem parametrelerini düzenle',
+ 'Save this action' => 'Bu işlemi kaydet',
+ 'Do you really want to remove this action: "%s"?' => 'Bu işlemi silmek istediğinize emin misiniz: "%s"?',
+ 'Remove an automatic action' => 'Bir otomatik işlemi sil',
+ 'Close the task' => 'Görevi kapat',
+ 'Assign the task to a specific user' => 'Görevi bir kullanıcıya ata',
+ 'Assign the task to the person who does the action' => 'Görevi, işlemi gerçekleştiren kullanıcıya ata',
+ 'Duplicate the task to another project' => 'Görevi bir başka projeye kopyala',
+ 'Move a task to another column' => 'Bir görevi başka bir sütuna taşı',
+ 'Move a task to another position in the same column' => 'Bir görevin aynı sütunda yerini değiştir',
+ 'Task modification' => 'Görev düzenleme',
+ 'Task creation' => 'Görev oluşturma',
+ 'Open a closed task' => 'Kapalı bir görevi aç',
+ 'Closing a task' => 'Bir görev kapatılıyor',
+ 'Assign a color to a specific user' => 'Bir kullanıcıya renk tanımla',
+ 'Column title' => 'Sütun başlığı',
+ 'Position' => 'Pozisyon',
+ 'Move Up' => 'Yukarı taşı',
+ 'Move Down' => 'Aşağı taşı',
+ 'Duplicate to another project' => 'Başka bir projeye kopyala',
+ 'Duplicate' => 'Kopya oluştur',
+ 'link' => 'link',
+ 'Update this comment' => 'Bu yorumu güncelle',
+ 'Comment updated successfully.' => 'Yorum güncellendi.',
+ 'Unable to update your comment.' => 'Yorum güncellenemedi.',
+ 'Remove a comment' => 'Bir yorumu sil',
+ 'Comment removed successfully.' => 'Yorum silindi.',
+ 'Unable to remove this comment.' => 'Bu yorum silinemiyor.',
+ 'Do you really want to remove this comment?' => 'Bu yorumu silmek istediğinize emin misiniz?',
+ 'Only administrators or the creator of the comment can access to this page.' => 'Bu sayfaya yalnızca yorum sahibi ve yöneticiler erişebilir.',
+ 'Details' => 'Detaylar',
+ 'Current password for the user "%s"' => 'Kullanıcı için mevcut şifre "%s"',
+ 'The current password is required' => 'Mevcut şifre gerekli',
+ 'Wrong password' => 'Yanlış Şifre',
+ 'Reset all tokens' => 'Tüm fişleri sıfırla',
+ 'All tokens have been regenerated.' => 'Tüm fişler yeniden oluşturuldu.',
+ 'Unknown' => 'Bilinmeyen',
+ 'Last logins' => 'Son kullanıcı girişleri',
+ 'Login date' => 'Giriş tarihi',
+ 'Authentication method' => 'Doğrulama yöntemi',
+ 'IP address' => 'IP adresi',
+ 'User agent' => 'Kullanıcı sistemi',
+ 'Persistent connections' => 'Kalıcı bağlantılar',
+ // 'No session.' => '',
+ 'Expiration date' => 'Geçerlilik sonu',
+ 'Remember Me' => 'Beni hatırla',
+ 'Creation date' => 'Oluşturulma tarihi',
+ 'Filter by user' => 'Kullanıcıya göre filtrele',
+ 'Filter by due date' => 'Termine göre filtrele',
+ 'Everybody' => 'Herkes',
+ 'Open' => 'Açık',
+ 'Closed' => 'Kapalı',
+ 'Search' => 'Ara',
+ 'Nothing found.' => 'Hiçbir şey bulunamadı',
+ 'Search in the project "%s"' => '"%s" Projesinde ara',
+ 'Due date' => 'Termin',
+ 'Others formats accepted: %s and %s' => 'Diğer kabul edilen formatlar: %s ve %s',
+ 'Description' => 'Açıklama',
+ '%d comments' => '%d yorumlar',
+ '%d comment' => '%d yorum',
+ 'Email address invalid' => 'E-Posta adresi geçersiz',
+ 'Your Google Account is not linked anymore to your profile.' => 'Google hesabınız artık profilinize bağlı değil',
+ 'Unable to unlink your Google Account.' => 'Google hesabınızla bağ koparılamadı',
+ 'Google authentication failed' => 'Google hesap doğrulaması başarısız',
+ 'Unable to link your Google Account.' => 'Google hesabınızla bağ oluşturulamadı',
+ 'Your Google Account is linked to your profile successfully.' => 'Google hesabınız profilinize başarıyla bağlandı',
+ 'Email' => 'E-Posta',
+ 'Link my Google Account' => 'Google hesabımla bağ oluştur',
+ 'Unlink my Google Account' => 'Google hesabımla bağı kaldır',
+ 'Login with my Google Account' => 'Google hesabımla giriş yap',
+ 'Project not found.' => 'Proje bulunamadı',
+ 'Task #%d' => 'Görev #%d',
+ 'Task removed successfully.' => 'Görev silindi',
+ 'Unable to remove this task.' => 'Görev silinemiyor',
+ 'Remove a task' => 'Bir görevi sil',
+ 'Do you really want to remove this task: "%s"?' => 'Bu görevi silmek istediğinize emin misiniz: "%s"?',
+ 'Assign automatically a color based on a category' => 'Kategoriye göre otomatik renk ata',
+ 'Assign automatically a category based on a color' => 'Rengine göre otomatik kategori ata',
+ 'Task creation or modification' => 'Görev oluşturma veya değiştirme',
+ 'Category' => 'Kategori',
+ 'Category:' => 'Kategori:',
+ 'Categories' => 'Kategoriler',
+ 'Category not found.' => 'Kategori bulunamadı',
+ 'Your category have been created successfully.' => 'Kategori oluşturuldu',
+ 'Unable to create your category.' => 'Kategori oluşturulamadı',
+ 'Your category have been updated successfully.' => 'Kategori başarıyla güncellendi',
+ 'Unable to update your category.' => 'Kategori güncellenemedi',
+ 'Remove a category' => 'Bir kategoriyi sil',
+ 'Category removed successfully.' => 'Kategori silindi',
+ 'Unable to remove this category.' => 'Bu kategori silinemedi',
+ 'Category modification for the project "%s"' => '"%s" projesi için kategori değiştirme',
+ 'Category Name' => 'Kategori adı',
+ 'Categories for the project "%s"' => '"%s" Projesi için kategoriler',
+ 'Add a new category' => 'Yeni kategori ekle',
+ 'Do you really want to remove this category: "%s"?' => 'Bu kategoriyi silmek istediğinize emin misiniz: "%s"?',
+ 'Filter by category' => 'Kategoriye göre filtrele',
+ 'All categories' => 'Tüm kategoriler',
+ 'No category' => 'Kategori Yok',
+ 'The name is required' => 'İsim gerekli',
+ 'Remove a file' => 'Dosya sil',
+ 'Unable to remove this file.' => 'Dosya silinemedi',
+ 'File removed successfully.' => 'Dosya silindi',
+ 'Attach a document' => 'Dosya ekle',
+ 'Do you really want to remove this file: "%s"?' => 'Bu dosyayı silmek istediğinize emin misiniz: "%s"?',
+ 'open' => 'aç',
+ 'Attachments' => 'Ekler',
+ 'Edit the task' => 'Görevi değiştir',
+ 'Edit the description' => 'Açıklamayı değiştir',
+ 'Add a comment' => 'Yorum ekle',
+ 'Edit a comment' => 'Yorum değiştir',
+ 'Summary' => 'Özet',
+ 'Time tracking' => 'Zaman takibi',
+ 'Estimate:' => 'Tahmini:',
+ 'Spent:' => 'Harcanan:',
+ 'Do you really want to remove this sub-task?' => 'Bu alt görevi silmek istediğinize emin misiniz',
+ 'Remaining:' => 'Kalan',
+ 'hours' => 'saat',
+ 'spent' => 'harcanan',
+ 'estimated' => 'tahmini',
+ 'Sub-Tasks' => 'Alt Görev',
+ 'Add a sub-task' => 'Alt görev ekle',
+ // 'Original estimate' => '',
+ 'Create another sub-task' => 'Başka bir alt görev daha oluştur',
+ // 'Time spent' => '',
+ 'Edit a sub-task' => 'Alt görev düzenle',
+ 'Remove a sub-task' => 'Alt görev sil',
+ 'The time must be a numeric value' => 'Zaman alfanumerik bir değer olmalı',
+ 'Todo' => 'Yapılacaklar',
+ 'In progress' => 'İşlemde',
+ 'Sub-task removed successfully.' => 'Alt görev silindi',
+ 'Unable to remove this sub-task.' => 'Alt görev silinemedi',
+ 'Sub-task updated successfully.' => 'Alt görev güncellendi',
+ 'Unable to update your sub-task.' => 'Alt görev güncellenemiyor',
+ 'Unable to create your sub-task.' => 'Alt görev oluşturulamadı',
+ 'Sub-task added successfully.' => 'Alt görev başarıyla eklendii',
+ 'Maximum size: ' => 'Maksimum boyutu',
+ 'Unable to upload the file.' => 'Karşıya yükleme başarısız',
+ 'Display another project' => 'Başka bir proje göster',
+ 'Your GitHub account was successfully linked to your profile.' => 'GitHub Hesabınız Profilinize bağlandı.',
+ 'Unable to link your GitHub Account.' => 'GitHub hesabınızla bağ oluşturulamadı.',
+ // 'GitHub authentication failed' => '',
+ // 'Your GitHub account is no longer linked to your profile.' => '',
+ // 'Unable to unlink your GitHub Account.' => '',
+ // 'Login with my GitHub Account' => '',
+ // 'Link my GitHub Account' => '',
+ // 'Unlink my GitHub Account' => '',
+ 'Created by %s' => '%s tarafından oluşturuldu',
+ 'Last modified on %B %e, %Y at %k:%M %p' => 'Son değişiklik tarihi %d.%m.%Y, saati %H:%M',
+ 'Tasks Export' => 'Görevleri dışa aktar',
+ 'Tasks exportation for "%s"' => '"%s" için görevleri dışa aktar',
+ 'Start Date' => 'Başlangıç tarihi',
+ 'End Date' => 'Bitiş tarihi',
+ 'Execute' => 'Gerçekleştir',
+ 'Task Id' => 'Görev No',
+ 'Creator' => 'Oluşturan',
+ 'Modification date' => 'Değişiklik tarihi',
+ 'Completion date' => 'Tamamlanma tarihi',
+ // 'Webhook URL for task creation' => '',
+ // 'Webhook URL for task modification' => '',
+ 'Clone' => 'Kopya oluştur',
+ 'Clone Project' => 'Projenin kopyasını oluştur',
+ 'Project cloned successfully.' => 'Proje kopyası başarıyla oluşturuldu.',
+ 'Unable to clone this project.' => 'Proje kopyası oluşturulamadı.',
+ 'Email notifications' => 'E-Posta bilgilendirmesi',
+ 'Enable email notifications' => 'E-Posta bilgilendirmesini aç',
+ 'Task position:' => 'Görev pozisyonu',
+ 'The task #%d have been opened.' => '#%d numaralı görev açıldı.',
+ 'The task #%d have been closed.' => '#%d numaralı görev kapatıldı.',
+ 'Sub-task updated' => 'Alt görev güncellendi',
+ 'Title:' => 'Başlık',
+ 'Status:' => 'Durum',
+ 'Assignee:' => 'Sorumlu:',
+ 'Time tracking:' => 'Zaman takibi',
+ 'New sub-task' => 'Yeni alt görev',
+ 'New attachment added "%s"' => 'Yeni dosya "%s" eklendi.',
+ 'Comment updated' => 'Yorum güncellendi',
+ 'New comment posted by %s' => '%s tarafından yeni yorum eklendi',
+ 'List of due tasks for the project "%s"' => '"%s" projesi için ilgili görevlerin listesi',
+ 'New attachment' => 'Yeni dosya eki',
+ 'New comment' => 'Yeni yorum',
+ 'New subtask' => 'Yeni alt görev',
+ 'Subtask updated' => 'Alt görev güncellendi',
+ 'Task updated' => 'Görev güncellendi',
+ 'Task closed' => 'Görev kapatıldı',
+ 'Task opened' => 'Görev açıldı',
+ '[%s][Due tasks]' => '[%s][İlgili görevler]',
+ '[Kanboard] Notification' => '[Kanboard] Bildirim',
+ 'I want to receive notifications only for those projects:' => 'Yalnızca bu projelerle ilgili bildirim almak istiyorum:',
+ 'view the task on Kanboard' => 'bu görevi Kanboard\'da göster',
+ 'Public access' => 'Dışa açık erişim',
+ 'Category management' => 'Kategori yönetimi',
+ 'User management' => 'Kullanıcı yönetimi',
+ 'Active tasks' => 'Aktif görevler',
+ 'Disable public access' => 'Dışa açık erişimi kapat',
+ 'Enable public access' => 'Dışa açık erişimi aç',
+ 'Active projects' => 'Aktif projeler',
+ 'Inactive projects' => 'Aktif olmayan projeler',
+ 'Public access disabled' => 'Dışa açık erişim kapatıldı',
+ 'Do you really want to disable this project: "%s"?' => 'Bu projeyi devre dışı bırakmak istediğinize emin misiniz?: "%s"',
+ 'Do you really want to duplicate this project: "%s"?' => 'Bu projenin kopyasını oluşturmak istediğinize emin misiniz?: "%s"',
+ 'Do you really want to enable this project: "%s"?' => 'Bu projeyi aktive etmek istediğinize emin misiniz?: "%s"',
+ 'Project activation' => 'Proje aktivasyonu',
+ 'Move the task to another project' => 'Görevi başka projeye taşı',
+ 'Move to another project' => 'Başka projeye taşı',
+ 'Do you really want to duplicate this task?' => 'Bu görevin kopyasını oluşturmak istediğinize emin misiniz?',
+ 'Duplicate a task' => 'Görevin kopyasını oluştur',
+ 'External accounts' => 'Dış hesaplar',
+ 'Account type' => 'Hesap türü',
+ 'Local' => 'Yerel',
+ 'Remote' => 'Uzak',
+ 'Enabled' => 'Etkinleştirildi',
+ 'Disabled' => 'Devre dışı bırakıldı',
+ 'Google account linked' => 'Google hesabıyla bağlı',
+ 'Github account linked' => 'Github hesabıyla bağlı',
+ 'Username:' => 'Kullanıcı adı',
+ 'Name:' => 'Ad',
+ 'Email:' => 'E-Posta',
+ 'Default project:' => 'Varsayılan Proje:',
+ 'Notifications:' => 'Bildirimler:',
+ 'Notifications' => 'Bildirimler',
+ 'Group:' => 'Grup',
+ 'Regular user' => 'Varsayılan kullanıcı',
+ 'Account type:' => 'Hesap türü:',
+ 'Edit profile' => 'Profili değiştir',
+ 'Change password' => 'Şifre değiştir',
+ 'Password modification' => 'Şifre değişimi',
+ 'External authentications' => 'Dış kimlik doğrulamaları',
+ 'Google Account' => 'Google hesabı',
+ 'Github Account' => 'Github hesabı',
+ 'Never connected.' => 'Hiç bağlanmamış.',
+ 'No account linked.' => 'Bağlanmış hesap yok.',
+ 'Account linked.' => 'Hesap bağlandı',
+ 'No external authentication enabled.' => 'Dış kimlik doğrulama kapalı.',
+ 'Password modified successfully.' => 'Şifre başarıyla değiştirildi.',
+ 'Unable to change the password.' => 'Şifre değiştirilemedi.',
+ 'Change category for the task "%s"' => '"%s" görevi için kategori değiştirme',
+ 'Change category' => 'Kategori değiştirme',
+ '%s updated the task %s' => '%s kullanıcısı %s görevini güncelledi',
+ '%s opened the task %s' => '%s kullanıcısı %s görevini açtı',
+ '%s moved the task %s to the position #%d in the column "%s"' => '%s kullanıcısı %s görevini #%d pozisyonu "%s" sütununa taşıdı',
+ '%s moved the task %s to the column "%s"' => '%s kullanıcısı %s görevini "%s" sütununa taşıdı',
+ '%s created the task %s' => '%s kullanıcısı %s görevini oluşturdu',
+ '%s closed the task %s' => '%s kullanıcısı %s görevini kapattı',
+ '%s created a subtask for the task %s' => '%s kullanıcısı %s görevi için bir alt görev oluşturdu',
+ '%s updated a subtask for the task %s' => '%s kullanıcısı %s görevinin bir alt görevini güncelledi',
+ 'Assigned to %s with an estimate of %s/%sh' => '%s kullanıcısına tahmini %s/%s saat tamamlanma süresi ile atanmış',
+ 'Not assigned, estimate of %sh' => 'Kimseye atanmamış, tahmini süre %s saat',
+ '%s updated a comment on the task %s' => '%s kullanıcısı %s görevinde bir yorumu güncelledi',
+ '%s commented the task %s' => '%s kullanıcısı %s görevine yorum ekledi',
+ '%s\'s activity' => '%s\'in aktivitesi',
+ 'No activity.' => 'Aktivite yok.',
+ 'RSS feed' => 'RSS kaynağı',
+ '%s updated a comment on the task #%d' => '%s kullanıcısı #%d nolu görevde bir yorumu güncelledi',
+ '%s commented on the task #%d' => '%s kullanıcısı #%d nolu göreve yorum ekledi',
+ '%s updated a subtask for the task #%d' => '%s kullanıcısı #%d nolu görevin bir alt görevini güncelledi',
+ '%s created a subtask for the task #%d' => '%s kullanıcısı #%d nolu göreve bir alt görev ekledi',
+ '%s updated the task #%d' => '%s kullanıcısı #%d nolu görevi güncelledi',
+ '%s created the task #%d' => '%s kullanıcısı #%d nolu görevi oluşturdu',
+ '%s closed the task #%d' => '%s kullanıcısı #%d nolu görevi kapattı',
+ '%s open the task #%d' => '%s kullanıcısı #%d nolu görevi açtı',
+ '%s moved the task #%d to the column "%s"' => '%s kullanıcısı #%d nolu görevi "%s" sütununa taşıdı',
+ '%s moved the task #%d to the position %d in the column "%s"' => '%s kullanıcısı #%d nolu görevi %d pozisyonu "%s" sütununa taşıdı',
+ 'Activity' => 'Aktivite',
+ 'Default values are "%s"' => 'Varsayılan değerler "%s"',
+ 'Default columns for new projects (Comma-separated)' => 'Yeni projeler için varsayılan sütunlar (virgül ile ayrılmış)',
+ 'Task assignee change' => 'Göreve atanan kullanıcı değişikliği',
+ '%s change the assignee of the task #%d to %s' => '%s kullanıcısı #%d nolu görevin sorumlusunu %s olarak değiştirdi',
+ '%s changed the assignee of the task %s to %s' => '%s kullanıcısı %s görevinin sorumlusunu %s olarak değiştirdi',
+ 'Column Change' => 'Sütun değişikliği',
+ 'Position Change' => 'Konum değişikliği',
+ 'Assignee Change' => 'Sorumlu değişikliği',
+ 'New password for the user "%s"' => '"%s" kullanıcısı için yeni şifre',
+ 'Choose an event' => 'Bir durum seçin',
+ // 'Github commit received' => '',
+ // 'Github issue opened' => '',
+ // 'Github issue closed' => '',
+ // 'Github issue reopened' => '',
+ // 'Github issue assignee change' => '',
+ // 'Github issue label change' => '',
+ 'Create a task from an external provider' => 'Dış sağlayıcı ile bir görev oluştur',
+ 'Change the assignee based on an external username' => 'Dış kaynaklı kullanıcı adı ile göreve atananı değiştir',
+ 'Change the category based on an external label' => 'Dış kaynaklı bir etiket ile kategori değiştir',
+ 'Reference' => 'Referans',
+ 'Reference: %s' => 'Referans: %s',
+ 'Label' => 'Etiket',
+ 'Database' => 'Veri bankası',
+ 'About' => 'Hakkında',
+ 'Database driver:' => 'Veri bankası sürücüsü',
+ 'Board settings' => 'Tablo ayarları',
+ 'URL and token' => 'URL veya Token',
+ 'Webhook settings' => 'Webhook ayarları',
+ 'URL for task creation:' => 'Görev oluşturma için URL',
+ 'Reset token' => 'Reset Token',
+ 'API endpoint:' => 'API endpoint',
+ 'Refresh interval for private board' => 'Özel tablolar için yenileme sıklığı',
+ 'Refresh interval for public board' => 'Dışa açık tablolar için yenileme sıklığı',
+ 'Task highlight period' => 'Görevi öne çıkarma süresi',
+ 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Bir görevin yeni değiştirilmiş sayılması için süre (saniye olarak) (Bu özelliği iptal etmek için 0, varsayılan değer 2 gün)',
+ 'Frequency in second (60 seconds by default)' => 'Saniye olarak frekans (varsayılan 60 saniye)',
+ 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Saniye olarak frekans (Bu özelliği iptal etmek için 0, varsayılan değer 10 saniye)',
+ 'Application URL' => 'Uygulama URL',
+ 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Örneğin: http://example.kanboard.net/ (E-posta bildirimleri için kullanılıyor)',
+ 'Token regenerated.' => 'Token yeniden oluşturuldu.',
+ 'Date format' => 'Tarih formatı',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'ISO formatı her zaman kabul edilir, örneğin: "%s" ve "%s"',
+ 'New private project' => 'Yeni özel proje',
+ 'This project is private' => 'Bu proje özel',
+ 'Type here to create a new sub-task' => 'Yeni bir alt görev oluşturmak için buraya yazın',
+ 'Add' => 'Ekle',
+ 'Estimated time: %s hours' => 'Tahmini süre: %s Saat',
+ 'Time spent: %s hours' => 'Kullanılan süre: %s Saat',
+ 'Started on %B %e, %Y' => '%B %e %Y tarihinde başlatıldı',
+ 'Start date' => 'Başlangıç tarihi',
+ 'Time estimated' => 'Tahmini süre',
+ 'There is nothing assigned to you.' => 'Size atanan hiçbir şey yok.',
+ 'My tasks' => 'Görevlerim',
+ 'Activity stream' => 'Güncel olay akışı',
+ 'Dashboard' => 'Anasayfa',
+ 'Confirmation' => 'Onay',
+ 'Allow everybody to access to this project' => 'Bu projeye herkesin erişimine izin ver',
+ 'Everybody have access to this project.' => 'Bu projeye herkesin erişimi var.',
+ 'Webhooks' => 'Webhooks',
+ 'API' => 'API',
+ 'Integration' => 'Entegrasyon',
+ 'Github webhooks' => 'Github Webhook',
+ 'Help on Github webhooks' => 'Github Webhooks hakkında yardım',
+ 'Create a comment from an external provider' => 'Dış sağlayıcı ile bir yorum oluştur',
+ 'Github issue comment created' => 'Github hata yorumu oluşturuldu',
+ 'Configure' => 'Ayarla',
+ 'Project management' => 'Proje yönetimi',
+ 'My projects' => 'Projelerim',
+ 'Columns' => 'Sütunlar',
+ 'Task' => 'Görev',
+ 'Your are not member of any project.' => 'Hiç bir projenin üyesi değilsiniz.',
+ 'Percentage' => 'Yüzde',
+ 'Number of tasks' => 'Görev sayısı',
+ 'Task distribution' => 'Görev dağılımı',
+ 'Reportings' => 'Raporlar',
+ 'Task repartition for "%s"' => '"%s" için görev dağılımı',
+ 'Analytics' => 'Analiz',
+ 'Subtask' => 'Alt görev',
+ 'My subtasks' => 'Alt görevlerim',
+ 'User repartition' => 'Kullanıcı dağılımı',
+ 'User repartition for "%s"' => '"%s" için kullanıcı dağılımı',
+ 'Clone this project' => 'Projenin kopyasını oluştur',
+ 'Column removed successfully.' => 'Sütun başarıyla kaldırıldı.',
+ 'Edit Project' => 'Projeyi düzenle',
+ 'Github Issue' => 'Github Issue',
+ 'Not enough data to show the graph.' => 'Grafik gösterimi için yeterli veri yok.',
+ 'Previous' => 'Önceki',
+ 'The id must be an integer' => 'ID bir tamsayı olmalı',
+ 'The project id must be an integer' => 'Proje numarası bir tam sayı olmalı',
+ 'The status must be an integer' => 'Durum bir tam sayı olmalı',
+ 'The subtask id is required' => 'Alt görev numarası gerekli',
+ 'The subtask id must be an integer' => 'Alt görev numarası bir tam sayı olmalı',
+ 'The task id is required' => 'Görev numarası gerekli',
+ 'The task id must be an integer' => 'Görev numarası bir tam sayı olmalı',
+ 'The user id must be an integer' => 'Kullanıcı numarası bir tam sayı olmalı',
+ 'This value is required' => 'Bu değer gerekli',
+ 'This value must be numeric' => 'Bu değer sayı olmalı',
+ 'Unable to create this task.' => 'Bu görev oluşturulamıyor.',
+ 'Cumulative flow diagram' => 'Kümülatif akış diyagramı',
+ 'Cumulative flow diagram for "%s"' => '"%s" için kümülatif akış diyagramı',
+ 'Daily project summary' => 'Günlük proje özeti',
+ 'Daily project summary export' => 'Günlük proje özetini dışa aktar',
+ 'Daily project summary export for "%s"' => '"%s" için günlük proje özetinin dışa',
+ 'Exports' => 'Dışa aktarımlar',
+ 'This export contains the number of tasks per column grouped per day.' => 'Bu dışa aktarım günlük gruplanmış olarak her sütundaki görev sayısını içerir.',
+ 'Nothing to preview...' => 'Önizleme yapılacak bir şey yok ...',
+ 'Preview' => 'Önizleme',
+ 'Write' => 'Değiştir',
+ 'Active swimlanes' => 'Aktif Kulvar',
+ 'Add a new swimlane' => 'Yeni bir Kulvar ekle',
+ 'Change default swimlane' => 'Varsayılan Kulvarı değiştir',
+ 'Default swimlane' => 'Varsayılan Kulvar',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Bu Kulvarı silmek istediğinize emin misiniz?: "%s"?',
+ 'Inactive swimlanes' => 'Pasif Kulvarlar',
+ 'Set project manager' => 'Proje yöneticisi olarak ata',
+ 'Set project member' => 'Proje üyesi olarak ata',
+ 'Remove a swimlane' => 'Kulvarı sil',
+ 'Rename' => 'Yeniden adlandır',
+ 'Show default swimlane' => 'Varsayılan Kulvarı göster',
+ 'Swimlane modification for the project "%s"' => '"% s" Projesi için Kulvar değişikliği',
+ 'Swimlane not found.' => 'Kulvar bulunamadı',
+ 'Swimlane removed successfully.' => 'Kulvar başarıyla kaldırıldı.',
+ 'Swimlanes' => 'Kulvarlar',
+ 'Swimlane updated successfully.' => 'Kulvar başarıyla güncellendi.',
+ 'The default swimlane have been updated successfully.' => 'Varsayılan Kulvarlar başarıyla güncellendi.',
+ 'Unable to create your swimlane.' => 'Bu Kulvarı oluşturmak mümkün değil.',
+ 'Unable to remove this swimlane.' => 'Bu Kulvarı silmek mümkün değil.',
+ 'Unable to update this swimlane.' => 'Bu Kulvarı değiştirmek mümkün değil.',
+ 'Your swimlane have been created successfully.' => 'Kulvar başarıyla oluşturuldu.',
+ 'Example: "Bug, Feature Request, Improvement"' => 'Örnek: "Sorun, Özellik talebi, İyileştirme"',
+ 'Default categories for new projects (Comma-separated)' => 'Yeni projeler için varsayılan kategoriler (Virgül ile ayrılmış)',
+ // 'Gitlab commit received' => '',
+ // 'Gitlab issue opened' => '',
+ // 'Gitlab issue closed' => '',
+ // 'Gitlab webhooks' => '',
+ // 'Help on Gitlab webhooks' => '',
+ 'Integrations' => 'Entegrasyon',
+ 'Integration with third-party services' => 'Dış servislerle entegrasyon',
+ 'Role for this project' => 'Bu proje için rol',
+ 'Project manager' => 'Proje Yöneticisi',
+ 'Project member' => 'Proje Üyesi',
+ 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Bir Proje Yöneticisi proje ayarlarını değiştirebilir ve bir üyeden daha fazla yetkiye sahiptir.',
+ // 'Gitlab Issue' => '',
+ 'Subtask Id' => 'Alt görev No:',
+ 'Subtasks' => 'Alt görevler',
+ 'Subtasks Export' => 'Alt görevleri dışa aktar',
+ 'Subtasks exportation for "%s"' => '"%s" için alt görevleri dışa aktarımı',
+ 'Task Title' => 'Görev Başlığı',
+ 'Untitled' => 'Başlıksız',
+ 'Application default' => 'Uygulama varsayılanları',
+ 'Language:' => 'Dil:',
+ 'Timezone:' => 'Saat dilimi:',
+ 'All columns' => 'Tüm sütunlar',
+ 'Calendar for "%s"' => '"%s" için takvim',
+ 'Filter by column' => 'Sütuna göre filtrele',
+ 'Filter by status' => 'Duruma göre filtrele',
+ 'Calendar' => 'Takvim',
+ 'Next' => 'Sonraki',
+ '#%d' => '#%d',
+ 'Filter by color' => 'Renklere göre filtrele',
+ 'Filter by swimlane' => 'Kulvara göre filtrele',
+ 'All swimlanes' => 'Tüm Kulvarlar',
+ 'All colors' => 'Tüm Renkler',
+ 'All status' => 'Tüm Durumlar',
+ 'Add a comment logging moving the task between columns' => 'Sütun değiştiğinde kayıt olarak yorum ekle',
+ 'Moved to column %s' => '%s Sütununa taşındı',
+ 'Change description' => 'Açıklamayı değiştir',
+ 'User dashboard' => 'Kullanıcı Anasayfası',
+ 'Allow only one subtask in progress at the same time for a user' => 'Bir kullanıcı için aynı anda yalnızca bir alt göreve izin ver',
+ 'Edit column "%s"' => '"%s" sütununu değiştir',
+ 'Enable time tracking for subtasks' => 'Alt görevler için zaman takibini etkinleştir',
+ 'Select the new status of the subtask: "%s"' => '"%s" alt görevi için yeni durum seçin.',
+ 'Subtask timesheet' => 'Alt görev için zaman takip tablosu',
+ 'There is nothing to show.' => 'Gösterilecek hiçbir şey yok.',
+ 'Time Tracking' => 'Zaman takibi',
+ 'You already have one subtask in progress' => 'Zaten işlemde olan bir alt görev var',
+ 'Which parts of the project do you want to duplicate?' => 'Projenin hangi kısımlarının kopyasını oluşturmak istiyorsunuz?',
+ 'Change dashboard view' => 'Anasayfa görünümünü değiştir',
+ 'Show/hide activities' => 'Aktiviteleri göster/gizle',
+ 'Show/hide projects' => 'Projeleri göster/gizle',
+ 'Show/hide subtasks' => 'Alt görevleri göster/gizle',
+ 'Show/hide tasks' => 'Görevleri göster/gizle',
+ 'Disable login form' => 'Giriş formunu devre dışı bırak',
+ 'Show/hide calendar' => 'Takvimi göster/gizle',
+ 'User calendar' => 'Kullanıcı takvimi',
+ 'Bitbucket commit received' => 'Bitbucket commit alındı',
+ 'Bitbucket webhooks' => 'Bitbucket webhooks',
+ 'Help on Bitbucket webhooks' => 'Bitbucket webhooks için yardım',
+ 'Start' => 'Başlangıç',
+ 'End' => 'Son',
+ 'Task age in days' => 'Görev yaşı gün olarak',
+ 'Days in this column' => 'Bu sütunda geçirilen gün',
+ '%dd' => '%dG',
+ 'Add a link' => 'Link ekle',
+ 'Add a new link' => 'Yeni link ekle',
+ 'Do you really want to remove this link: "%s"?' => '"%s" linkini gerçekten silmek istiyor musunuz?',
+ 'Do you really want to remove this link with task #%d?' => '#%d numaralı görev ile linki gerçekten silmek istiyor musunuz?',
+ 'Field required' => 'Bu alan gerekli',
+ 'Link added successfully.' => 'Link başarıyla eklendi.',
+ 'Link updated successfully.' => 'Link başarıyla güncellendi.',
+ 'Link removed successfully.' => 'Link başarıyla silindi.',
+ 'Link labels' => 'Link etiketleri',
+ 'Link modification' => 'Link değiştirme',
+ 'Links' => 'Links',
+ 'Link settings' => 'Link ayarları',
+ 'Opposite label' => 'Zıt etiket',
+ 'Remove a link' => 'Bir link silmek',
+ 'Task\'s links' => 'Görevin linkleri',
+ 'The labels must be different' => 'Etiketler farklı olmalı',
+ 'There is no link.' => 'Hiç bir bağ yok',
+ 'This label must be unique' => 'Bu etiket tek olmalı',
+ 'Unable to create your link.' => 'Link oluşturulamadı.',
+ 'Unable to update your link.' => 'Link güncellenemiyor.',
+ 'Unable to remove this link.' => 'Link kaldırılamıyor',
+ 'relates to' => 'şununla ilgili',
+ 'blocks' => 'şunu engelliyor',
+ 'is blocked by' => 'şunun tarafından engelleniyor',
+ 'duplicates' => 'şunun kopyasını oluşturuyor',
+ 'is duplicated by' => 'şunun tarafından kopyası oluşturuluyor',
+ 'is a child of' => 'şunun astı',
+ 'is a parent of' => 'şunun üstü',
+ 'targets milestone' => 'şu kilometre taşını hedefliyor',
+ 'is a milestone of' => 'şunun için bir kilometre taşı',
+ 'fixes' => 'düzeltiyor',
+ 'is fixed by' => 'şunun tarafından düzeltildi',
+ 'This task' => 'Bu görev',
+ '<1h' => '<1s',
+ '%dh' => '%ds',
+ // '%b %e' => '',
+ 'Expand tasks' => 'Görevleri genişlet',
+ 'Collapse tasks' => 'Görevleri daralt',
+ 'Expand/collapse tasks' => 'Görevleri genişlet/daralt',
+ 'Close dialog box' => 'İletiyi kapat',
+ 'Submit a form' => 'Formu gönder',
+ 'Board view' => 'Tablo görünümü',
+ 'Keyboard shortcuts' => 'Klavye kısayolları',
+ 'Open board switcher' => 'Tablo seçim listesini aç',
+ 'Application' => 'Uygulama',
+ 'Filter recently updated' => 'Son güncellenenleri göster',
+ 'since %B %e, %Y at %k:%M %p' => '%B %e, %Y saat %k:%M %p\'den beri',
+ 'More filters' => 'Daha fazla filtre',
+ 'Compact view' => 'Ekrana sığdır',
+ 'Horizontal scrolling' => 'Geniş görünüm',
+ 'Compact/wide view' => 'Ekrana sığdır / Geniş görünüm',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
+);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index cd1e2ebe..31d63632 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -1,6 +1,8 @@
<?php
return array(
+ // 'number.decimals_separator' => '',
+ // 'number.thousands_separator' => '',
'None' => '无',
'edit' => '编辑',
'Edit' => '编辑',
@@ -379,7 +381,7 @@ return array(
'Created by %s' => '创建者:%s',
'Last modified on %B %e, %Y at %k:%M %p' => '最后修改:%Y/%m/%d/ %H:%M',
'Tasks Export' => '任务导出',
- 'Tasks exportation for "%s"' => '导出任务"%s"',
+ 'Tasks exportation for "%s"' => '导出"%s"的任务',
'Start Date' => '开始时间',
'End Date' => '结束时间',
'Execute' => '执行',
@@ -408,13 +410,13 @@ return array(
'Comment updated' => '更新了评论',
'New comment posted by %s' => '%s 的新评论',
'List of due tasks for the project "%s"' => '项目"%s"的到期任务列表',
- // 'New attachment' => '',
- // 'New comment' => '',
- // 'New subtask' => '',
- // 'Subtask updated' => '',
- // 'Task updated' => '',
- // 'Task closed' => '',
- // 'Task opened' => '',
+ 'New attachment' => '新建附件',
+ 'New comment' => '新建评论',
+ 'New subtask' => '新建子任务',
+ 'Subtask updated' => '子任务更新',
+ 'Task updated' => '任务更新',
+ 'Task closed' => '任务关闭',
+ 'Task opened' => '任务开启',
'[%s][Due tasks]' => '[%s][到期任务]',
'[Kanboard] Notification' => '[Kanboard] 通知',
'I want to receive notifications only for those projects:' => '我仅需要收到下面项目的通知:',
@@ -498,9 +500,9 @@ return array(
'Task assignee change' => '任务分配变更',
'%s change the assignee of the task #%d to %s' => '%s 将任务 #%d 分配给了 %s',
'%s changed the assignee of the task %s to %s' => '%s 将任务 %s 分配给 %s',
- // 'Column Change' => '',
- // 'Position Change' => '',
- // 'Assignee Change' => '',
+ 'Column Change' => '栏目变更',
+ 'Position Change' => '位置变更',
+ 'Assignee Change' => '负责人变更',
'New password for the user "%s"' => '用户"%s"的新密码',
'Choose an event' => '选择一个事件',
'Github commit received' => '收到了Github提交',
@@ -607,8 +609,8 @@ return array(
'Default swimlane' => '默认泳道',
'Do you really want to remove this swimlane: "%s"?' => '确定要删除泳道:"%s"?',
'Inactive swimlanes' => '非活动泳道',
- // 'Set project manager' => '',
- // 'Set project member' => '',
+ 'Set project manager' => '设为项目经理',
+ 'Set project member' => '设为项目成员',
'Remove a swimlane' => '删除泳道',
'Rename' => '重命名',
'Show default swimlane' => '显示默认泳道',
@@ -622,92 +624,92 @@ return array(
'Unable to remove this swimlane.' => '无法删除此泳道',
'Unable to update this swimlane.' => '无法更新此泳道',
'Your swimlane have been created successfully.' => '已经成功创建泳道。',
- // 'Example: "Bug, Feature Request, Improvement"' => '',
- // 'Default categories for new projects (Comma-separated)' => '',
- // 'Gitlab commit received' => '',
- // 'Gitlab issue opened' => '',
- // 'Gitlab issue closed' => '',
- // 'Gitlab webhooks' => '',
- // 'Help on Gitlab webhooks' => '',
- // 'Integrations' => '',
- // 'Integration with third-party services' => '',
- // 'Role for this project' => '',
- // 'Project manager' => '',
- // 'Project member' => '',
- // 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
- // 'Gitlab Issue' => '',
- // 'Subtask Id' => '',
- // 'Subtasks' => '',
- // 'Subtasks Export' => '',
- // 'Subtasks exportation for "%s"' => '',
- // 'Task Title' => '',
- // 'Untitled' => '',
- // 'Application default' => '',
- // 'Language:' => '',
- // 'Timezone:' => '',
- // 'All columns' => '',
- // 'Calendar for "%s"' => '',
- // 'Filter by column' => '',
- // 'Filter by status' => '',
- // 'Calendar' => '',
- // 'Next' => '',
- // '#%d' => '',
- // 'Filter by color' => '',
- // 'Filter by swimlane' => '',
- // 'All swimlanes' => '',
- // 'All colors' => '',
- // 'All status' => '',
- // 'Add a comment logging moving the task between columns' => '',
- // 'Moved to column %s' => '',
- // 'Change description' => '',
- // 'User dashboard' => '',
- // 'Allow only one subtask in progress at the same time for a user' => '',
- // 'Edit column "%s"' => '',
- // 'Enable time tracking for subtasks' => '',
- // 'Select the new status of the subtask: "%s"' => '',
- // 'Subtask timesheet' => '',
- // 'There is nothing to show.' => '',
- // 'Time Tracking' => '',
- // 'You already have one subtask in progress' => '',
- // 'Which parts of the project do you want to duplicate?' => '',
- // 'Change dashboard view' => '',
- // 'Show/hide activities' => '',
- // 'Show/hide projects' => '',
- // 'Show/hide subtasks' => '',
- // 'Show/hide tasks' => '',
- // 'Disable login form' => '',
- // 'Show/hide calendar' => '',
- // 'User calendar' => '',
- // 'Bitbucket commit received' => '',
- // 'Bitbucket webhooks' => '',
- // 'Help on Bitbucket webhooks' => '',
- // 'Start' => '',
- // 'End' => '',
- // 'Task age in days' => '',
- // 'Days in this column' => '',
- // '%dd' => '',
- // 'Add a link' => '',
- // 'Add a new link' => '',
- // 'Do you really want to remove this link: "%s"?' => '',
- // 'Do you really want to remove this link with task #%d?' => '',
- // 'Field required' => '',
- // 'Link added successfully.' => '',
- // 'Link updated successfully.' => '',
- // 'Link removed successfully.' => '',
- // 'Link labels' => '',
- // 'Link modification' => '',
- // 'Links' => '',
- // 'Link settings' => '',
- // 'Opposite label' => '',
- // 'Remove a link' => '',
- // 'Task\'s links' => '',
- // 'The labels must be different' => '',
- // 'There is no link.' => '',
- // 'This label must be unique' => '',
- // 'Unable to create your link.' => '',
- // 'Unable to update your link.' => '',
- // 'Unable to remove this link.' => '',
- // 'relates to' => '',
+ 'Example: "Bug, Feature Request, Improvement"' => '示例:“缺陷,功能需求,提升',
+ 'Default categories for new projects (Comma-separated)' => '新项目的默认分类(用逗号分隔)',
+ 'Gitlab commit received' => '收到 Gitlab 提交',
+ 'Gitlab issue opened' => '开启 Gitlab 问题',
+ 'Gitlab issue closed' => '关闭 Gitlab 问题',
+ 'Gitlab webhooks' => 'Gitlab 网络钩子',
+ 'Help on Gitlab webhooks' => 'Gitlab 网络钩子帮助',
+ 'Integrations' => '整合',
+ 'Integration with third-party services' => '与第三方服务进行整合',
+ 'Role for this project' => '项目角色',
+ 'Project manager' => '项目管理员',
+ 'Project member' => '项目成员',
+ 'A project manager can change the settings of the project and have more privileges than a standard user.' => '项目经理可以修改项目的设置,比标准用户多了一些权限',
+ 'Gitlab Issue' => 'Gitlab 问题',
+ 'Subtask Id' => '子任务 Id',
+ 'Subtasks' => '子任务',
+ 'Subtasks Export' => '子任务导出',
+ 'Subtasks exportation for "%s"' => '导出"%s"的子任务',
+ 'Task Title' => '任务标题',
+ 'Untitled' => '无标题',
+ 'Application default' => '程序默认',
+ 'Language:' => '语言:',
+ 'Timezone:' => '时区:',
+ 'All columns' => '全部栏目',
+ 'Calendar for "%s"' => '"%s"的日程表',
+ 'Filter by column' => '按栏目过滤',
+ 'Filter by status' => '按状态过滤',
+ 'Calendar' => '日程表',
+ 'Next' => '前进',
+ '#%d' => '#%d',
+ 'Filter by color' => '按颜色过滤',
+ 'Filter by swimlane' => '按泳道过滤',
+ 'All swimlanes' => '全部泳道',
+ 'All colors' => '全部颜色',
+ 'All status' => '全部状态',
+ 'Add a comment logging moving the task between columns' => '在不同栏目间移动任务时添加一个评论',
+ 'Moved to column %s' => '移动到栏目 %s',
+ 'Change description' => '修改描述',
+ 'User dashboard' => '用户仪表板',
+ 'Allow only one subtask in progress at the same time for a user' => '每用户同时仅有一个活动子任务',
+ 'Edit column "%s"' => '编辑栏目"%s"',
+ 'Enable time tracking for subtasks' => '启用子任务的时间记录',
+ 'Select the new status of the subtask: "%s"' => '选择子任务的新状态:"%s"',
+ 'Subtask timesheet' => '子任务时间',
+ 'There is nothing to show.' => '无内容。',
+ 'Time Tracking' => '时间记录',
+ 'You already have one subtask in progress' => '你已经有了一个进行中的子任务',
+ 'Which parts of the project do you want to duplicate?' => '要复制项目的哪些内容?',
+ 'Change dashboard view' => '修改仪表板视图',
+ 'Show/hide activities' => '显示/隐藏活动',
+ 'Show/hide projects' => '显示/隐藏项目',
+ 'Show/hide subtasks' => '显示/隐藏子任务',
+ 'Show/hide tasks' => '显示/隐藏任务',
+ 'Disable login form' => '禁用登录界面',
+ 'Show/hide calendar' => '显示/隐藏日程表',
+ 'User calendar' => '用户日程表',
+ 'Bitbucket commit received' => '收到Bitbucket提交',
+ 'Bitbucket webhooks' => 'Bitbucket网络钩子',
+ 'Help on Bitbucket webhooks' => 'Bitbucket网络钩子帮助',
+ 'Start' => '开始',
+ 'End' => '结束',
+ 'Task age in days' => '任务存在天数',
+ 'Days in this column' => '在此栏目的天数',
+ '%dd' => '%d天',
+ 'Add a link' => '添加一个关联',
+ 'Add a new link' => '添加一个新关联',
+ 'Do you really want to remove this link: "%s"?' => '确认要删除此关联吗:"%s"?',
+ 'Do you really want to remove this link with task #%d?' => '确认要删除到任务 #%d 的关联吗?',
+ 'Field required' => '必须的字段',
+ 'Link added successfully.' => '成功添加关联。',
+ 'Link updated successfully.' => '成功更新关联。',
+ 'Link removed successfully.' => '成功删除关联。',
+ 'Link labels' => '关联标签',
+ 'Link modification' => '关联修改',
+ 'Links' => '关联',
+ 'Link settings' => '关联设置',
+ 'Opposite label' => '反向标签',
+ 'Remove a link' => '删除关联',
+ 'Task\'s links' => '任务的关联',
+ 'The labels must be different' => '标签不能一样',
+ 'There is no link.' => '没有关联',
+ 'This label must be unique' => '关联必须唯一',
+ 'Unable to create your link.' => '无法创建关联。',
+ 'Unable to update your link.' => '无法更新关联。',
+ 'Unable to remove this link.' => '无法删除关联。',
+ 'relates to' => '关联到',
// 'blocks' => '',
// 'is blocked by' => '',
// 'duplicates' => '',
@@ -718,20 +720,88 @@ return array(
// 'is a milestone of' => '',
// 'fixes' => '',
// 'is fixed by' => '',
- // 'This task' => '',
+ 'This task' => '此任务',
// '<1h' => '',
// '%dh' => '',
// '%b %e' => '',
- // 'Expand tasks' => '',
- // 'Collapse tasks' => '',
- // 'Expand/collapse tasks' => '',
- // 'Close dialog box' => '',
- // 'Submit a form' => '',
- // 'Board view' => '',
- // 'Keyboard shortcuts' => '',
- // 'Open board switcher' => '',
- // 'Application' => '',
- // 'Filter recently updated' => '',
+ 'Expand tasks' => '展开任务',
+ 'Collapse tasks' => '收缩任务',
+ 'Expand/collapse tasks' => '展开/收缩任务',
+ 'Close dialog box' => '关闭对话框',
+ 'Submit a form' => '提交表单',
+ 'Board view' => '面板视图',
+ 'Keyboard shortcuts' => '键盘快捷方式',
+ 'Open board switcher' => '打开面板切换器',
+ 'Application' => '应用程序',
+ 'Filter recently updated' => '过滤最近的更新',
// 'since %B %e, %Y at %k:%M %p' => '',
- // 'More filters' => '',
+ 'More filters' => '更多过滤',
+ // 'Compact view' => '',
+ // 'Horizontal scrolling' => '',
+ // 'Compact/wide view' => '',
+ // 'No results match:' => '',
+ // 'Remove hourly rate' => '',
+ // 'Do you really want to remove this hourly rate?' => '',
+ // 'Hourly rates' => '',
+ // 'Hourly rate' => '',
+ // 'Currency' => '',
+ // 'Effective date' => '',
+ // 'Add new rate' => '',
+ // 'Rate removed successfully.' => '',
+ // 'Unable to remove this rate.' => '',
+ // 'Unable to save the hourly rate.' => '',
+ // 'Hourly rate created successfully.' => '',
+ // 'Start time' => '',
+ // 'End time' => '',
+ // 'Comment' => '',
+ // 'All day' => '',
+ // 'Day' => '',
+ // 'Manage timetable' => '',
+ // 'Overtime timetable' => '',
+ // 'Time off timetable' => '',
+ // 'Timetable' => '',
+ // 'Work timetable' => '',
+ // 'Week timetable' => '',
+ // 'Day timetable' => '',
+ // 'From' => '',
+ // 'To' => '',
+ // 'Time slot created successfully.' => '',
+ // 'Unable to save this time slot.' => '',
+ // 'Time slot removed successfully.' => '',
+ // 'Unable to remove this time slot.' => '',
+ // 'Do you really want to remove this time slot?' => '',
+ // 'Remove time slot' => '',
+ // 'Add new time slot' => '',
+ // 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
+ // 'Files' => '',
+ // 'Images' => '',
+ // 'Private project' => '',
+ // 'Amount' => '',
+ // 'AUD - Australian Dollar' => '',
+ // 'Budget' => '',
+ // 'Budget line' => '',
+ // 'Budget line removed successfully.' => '',
+ // 'Budget lines' => '',
+ // 'CAD - Canadian Dollar' => '',
+ // 'CHF - Swiss Francs' => '',
+ // 'Cost' => '',
+ // 'Cost breakdown' => '',
+ // 'Custom Stylesheet' => '',
+ // 'download' => '',
+ // 'Do you really want to remove this budget line?' => '',
+ // 'EUR - Euro' => '',
+ // 'Expenses' => '',
+ // 'GBP - British Pound' => '',
+ // 'INR - Indian Rupee' => '',
+ // 'JPY - Japanese Yen' => '',
+ // 'New budget line' => '',
+ // 'NZD - New Zealand Dollar' => '',
+ // 'Remove a budget line' => '',
+ // 'Remove budget line' => '',
+ // 'RSD - Serbian dinar' => '',
+ // 'The budget line have been created successfully.' => '',
+ // 'Unable to create the budget line.' => '',
+ // 'Unable to remove this budget line.' => '',
+ // 'USD - US Dollar' => '',
+ // 'Remaining' => '',
);
diff --git a/app/Model/Acl.php b/app/Model/Acl.php
index 9fc81747..b52a7864 100644
--- a/app/Model/Acl.php
+++ b/app/Model/Acl.php
@@ -56,6 +56,7 @@ class Acl extends Base
'export' => array('tasks', 'subtasks', 'summary'),
'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
'swimlane' => '*',
+ 'budget' => '*',
);
/**
@@ -70,6 +71,7 @@ class Acl extends Base
'config' => '*',
'link' => '*',
'project' => array('remove'),
+ 'hourlyrate' => '*',
);
/**
diff --git a/app/Model/Action.php b/app/Model/Action.php
index c1662fad..0e132d73 100644
--- a/app/Model/Action.php
+++ b/app/Model/Action.php
@@ -213,7 +213,7 @@ class Action extends Base
*
* @access public
* @param array $values Required parameters to save an action
- * @return bool Success or not
+ * @return integer
*/
public function create(array $values)
{
@@ -250,7 +250,7 @@ class Action extends Base
// $this->container['fileCache']->remove('proxy_action_getAll');
- return true;
+ return $action_id;
}
/**
diff --git a/app/Model/Base.php b/app/Model/Base.php
index f836231c..0217aae3 100644
--- a/app/Model/Base.php
+++ b/app/Model/Base.php
@@ -16,6 +16,7 @@ use Pimple\Container;
* @property \Model\Action $action
* @property \Model\Authentication $authentication
* @property \Model\Board $board
+ * @property \Model\Budget $budget
* @property \Model\Category $category
* @property \Model\Comment $comment
* @property \Model\CommentHistory $commentHistory
@@ -42,7 +43,7 @@ use Pimple\Container;
* @property \Model\TaskLink $taskLink
* @property \Model\TaskPosition $taskPosition
* @property \Model\TaskValidator $taskValidator
- * @property \Model\TimeTracking $timeTracking
+ * @property \Model\Timetable $timetable
* @property \Model\SubtaskTimeTracking $subtaskTimeTracking
* @property \Model\User $user
* @property \Model\UserSession $userSession
diff --git a/app/Model/Budget.php b/app/Model/Budget.php
new file mode 100644
index 00000000..84cadf6e
--- /dev/null
+++ b/app/Model/Budget.php
@@ -0,0 +1,210 @@
+<?php
+
+namespace Model;
+
+use DateInterval;
+use DateTime;
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Budget
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class Budget extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'budget_lines';
+
+ /**
+ * Get all budget lines for a project
+ *
+ * @access public
+ * @param integer $project_id
+ * @return array
+ */
+ public function getAll($project_id)
+ {
+ return $this->db->table(self::TABLE)->eq('project_id', $project_id)->desc('date')->findAll();
+ }
+
+ /**
+ * Get the current total of the budget
+ *
+ * @access public
+ * @param integer $project_id
+ * @return float
+ */
+ public function getTotal($project_id)
+ {
+ $result = $this->db->table(self::TABLE)->columns('SUM(amount) as total')->eq('project_id', $project_id)->findOne();
+ return isset($result['total']) ? (float) $result['total'] : 0;
+ }
+
+ /**
+ * Get breakdown by tasks/subtasks/users
+ *
+ * @access public
+ * @param integer $project_id
+ * @return \PicoDb\Table
+ */
+ public function getSubtaskBreakdown($project_id)
+ {
+ return $this->db
+ ->table(SubtaskTimeTracking::TABLE)
+ ->columns(
+ SubtaskTimeTracking::TABLE.'.id',
+ SubtaskTimeTracking::TABLE.'.user_id',
+ SubtaskTimeTracking::TABLE.'.subtask_id',
+ SubtaskTimeTracking::TABLE.'.start',
+ SubtaskTimeTracking::TABLE.'.time_spent',
+ Subtask::TABLE.'.task_id',
+ Subtask::TABLE.'.title AS subtask_title',
+ Task::TABLE.'.title AS task_title',
+ Task::TABLE.'.project_id',
+ User::TABLE.'.username',
+ User::TABLE.'.name'
+ )
+ ->join(Subtask::TABLE, 'id', 'subtask_id')
+ ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE)
+ ->join(User::TABLE, 'id', 'user_id')
+ ->eq(Task::TABLE.'.project_id', $project_id)
+ ->filter(array($this, 'applyUserRate'));
+ }
+
+ /**
+ * Gather necessary information to display the budget graph
+ *
+ * @access public
+ * @param integer $project_id
+ * @return array
+ */
+ public function getDailyBudgetBreakdown($project_id)
+ {
+ $out = array();
+ $in = $this->db->hashtable(self::TABLE)->eq('project_id', $project_id)->gt('amount', 0)->asc('date')->getAll('date', 'amount');
+ $time_slots = $this->getSubtaskBreakdown($project_id)->findAll();
+
+ foreach ($time_slots as $slot) {
+ $date = date('Y-m-d', $slot['start']);
+
+ if (! isset($out[$date])) {
+ $out[$date] = 0;
+ }
+
+ $out[$date] += $slot['cost'];
+ }
+
+ $start = key($in) ?: key($out);
+ $end = new DateTime;
+ $left = 0;
+ $serie = array();
+
+ for ($today = new DateTime($start); $today <= $end; $today->add(new DateInterval('P1D'))) {
+
+ $date = $today->format('Y-m-d');
+ $today_in = isset($in[$date]) ? (int) $in[$date] : 0;
+ $today_out = isset($out[$date]) ? (int) $out[$date] : 0;
+ $left += $today_in;
+ $left -= $today_out;
+
+ $serie[] = array(
+ 'date' => $date,
+ 'in' => $today_in,
+ 'out' => -$today_out,
+ 'left' => $left,
+ );
+ }
+
+ return $serie;
+ }
+
+ /**
+ * Filter callback to apply the rate according to the effective date
+ *
+ * @access public
+ * @param array $records
+ * @return array
+ */
+ public function applyUserRate(array $records)
+ {
+ $rates = $this->hourlyRate->getAllByProject($records[0]['project_id']);
+
+ foreach ($records as &$record) {
+
+ $hourly_price = 0;
+
+ foreach ($rates as $rate) {
+
+ if ($rate['user_id'] == $record['user_id'] && date('Y-m-d', $rate['date_effective']) <= date('Y-m-d', $record['start'])) {
+ $hourly_price = $rate['rate'];
+ break;
+ }
+ }
+
+ $record['cost'] = $hourly_price * $record['time_spent'];
+ }
+
+ return $records;
+ }
+
+ /**
+ * Add a new budget line in the database
+ *
+ * @access public
+ * @param integer $project_id
+ * @param float $amount
+ * @param string $comment
+ * @param string $date
+ * @return boolean|integer
+ */
+ public function create($project_id, $amount, $comment, $date = '')
+ {
+ $values = array(
+ 'project_id' => $project_id,
+ 'amount' => $amount,
+ 'comment' => $comment,
+ 'date' => $date ?: date('Y-m-d'),
+ );
+
+ return $this->persist(self::TABLE, $values);
+ }
+
+ /**
+ * Remove a specific budget line
+ *
+ * @access public
+ * @param integer $budget_id
+ * @return boolean
+ */
+ public function remove($budget_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $budget_id)->remove();
+ }
+
+ /**
+ * Validate creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('project_id', t('Field required')),
+ new Validators\Required('amount', t('Field required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+} \ No newline at end of file
diff --git a/app/Model/Config.php b/app/Model/Config.php
index 48640f4e..736ae08d 100644
--- a/app/Model/Config.php
+++ b/app/Model/Config.php
@@ -22,6 +22,28 @@ class Config extends Base
const TABLE = 'settings';
/**
+ * Get available currencies
+ *
+ * @access public
+ * @return array
+ */
+ public function getCurrencies()
+ {
+ return array(
+ 'USD' => t('USD - US Dollar'),
+ 'EUR' => t('EUR - Euro'),
+ 'GBP' => t('GBP - British Pound'),
+ 'CHF' => t('CHF - Swiss Francs'),
+ 'CAD' => t('CAD - Canadian Dollar'),
+ 'AUD' => t('AUD - Australian Dollar'),
+ 'NZD' => t('NZD - New Zealand Dollar'),
+ 'INR' => t('INR - Indian Rupee'),
+ 'JPY' => t('JPY - Japanese Yen'),
+ 'RSD' => t('RSD - Serbian dinar'),
+ );
+ }
+
+ /**
* Get available timezones
*
* @access public
@@ -58,11 +80,14 @@ class Config extends Base
'fr_FR' => 'Français',
'it_IT' => 'Italiano',
'hu_HU' => 'Magyar',
+ 'nl_NL' => 'Nederlands',
'pl_PL' => 'Polski',
'pt_BR' => 'Português (Brasil)',
'ru_RU' => 'Русский',
+ 'sr_Latn_RS' => 'Srpski',
'fi_FI' => 'Suomi',
'sv_SE' => 'Svenska',
+ 'tr_TR' => 'Türkçe',
'zh_CN' => '中文(简体)',
'ja_JP' => '日本語',
'th_TH' => 'ไทย',
@@ -99,6 +124,7 @@ class Config extends Base
'zh_CN' => 'zh-cn',
'ja_JP' => 'ja',
'th_TH' => 'th',
+ 'tr_TR' => 'tr',
);
$lang = $this->getCurrentLanguage();
diff --git a/app/Model/DateParser.php b/app/Model/DateParser.php
index 8a4d3edd..a0d10a36 100644
--- a/app/Model/DateParser.php
+++ b/app/Model/DateParser.php
@@ -13,6 +13,47 @@ use DateTime;
class DateParser extends Base
{
/**
+ * Return true if the date is within the date range
+ *
+ * @access public
+ * @param DateTime $date
+ * @param DateTime $start
+ * @param DateTime $end
+ * @return boolean
+ */
+ public function withinDateRange(DateTime $date, DateTime $start, DateTime $end)
+ {
+ return $date >= $start && $date <= $end;
+ }
+
+ /**
+ * Get the total number of hours between 2 datetime objects
+ * Minutes are rounded to the nearest quarter
+ *
+ * @access public
+ * @param DateTime $d1
+ * @param DateTime $d2
+ * @return float
+ */
+ public function getHours(DateTime $d1, DateTime $d2)
+ {
+ $seconds = $this->getRoundedSeconds(abs($d1->getTimestamp() - $d2->getTimestamp()));
+ return round($seconds / 3600, 2);
+ }
+
+ /**
+ * Round the timestamp to the nearest quarter
+ *
+ * @access public
+ * @param integer $seconds Timestamp
+ * @return integer
+ */
+ public function getRoundedSeconds($seconds)
+ {
+ return (int) round($seconds / (15 * 60)) * (15 * 60);
+ }
+
+ /**
* Return a timestamp if the given date format is correct otherwise return 0
*
* @access public
diff --git a/app/Model/File.php b/app/Model/File.php
index 1b9351db..a8cce9f4 100644
--- a/app/Model/File.php
+++ b/app/Model/File.php
@@ -17,7 +17,7 @@ class File extends Base
*
* @var string
*/
- const TABLE = 'task_has_files';
+ const TABLE = 'files';
/**
* Events
@@ -113,6 +113,38 @@ class File extends Base
}
/**
+ * Get all images for a given task
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return array
+ */
+ public function getAllImages($task_id)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('task_id', $task_id)
+ ->eq('is_image', 1)
+ ->asc('name')
+ ->findAll();
+ }
+
+ /**
+ * Get all files without images for a given task
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return array
+ */
+ public function getAllDocuments($task_id)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('task_id', $task_id)
+ ->eq('is_image', 0)
+ ->asc('name')
+ ->findAll();
+ }
+
+ /**
* Check if a filename is an image
*
* @access public
@@ -121,7 +153,17 @@ class File extends Base
*/
public function isImage($filename)
{
- return getimagesize($filename) !== false;
+ $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ switch ($extension) {
+ case 'jpeg':
+ case 'jpg':
+ case 'png':
+ case 'gif':
+ return true;
+ }
+
+ return false;
}
/**
@@ -188,7 +230,7 @@ class File extends Base
$task_id,
$original_filename,
$destination_filename,
- $this->isImage(FILES_DIR.$destination_filename)
+ $this->isImage($original_filename)
);
}
}
diff --git a/app/Model/HourlyRate.php b/app/Model/HourlyRate.php
new file mode 100644
index 00000000..1550bdae
--- /dev/null
+++ b/app/Model/HourlyRate.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Model;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Hourly Rate
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class HourlyRate extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'hourly_rates';
+
+ /**
+ * Get all user rates for a given project
+ *
+ * @access public
+ * @param integer $project_id
+ * @return array
+ */
+ public function getAllByProject($project_id)
+ {
+ $members = $this->projectPermission->getMembers($project_id);
+
+ if (empty($members)) {
+ return array();
+ }
+
+ return $this->db->table(self::TABLE)->in('user_id', array_keys($members))->desc('date_effective')->findAll();
+ }
+
+ /**
+ * Get all rates for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return array
+ */
+ public function getAllByUser($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findAll();
+ }
+
+ /**
+ * Get current rate for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return float
+ */
+ public function getCurrentRate($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findOneColumn('rate') ?: 0;
+ }
+
+ /**
+ * Add a new rate in the database
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param float $rate Hourly rate
+ * @param string $currency Currency code
+ * @param string $date ISO8601 date format
+ * @return boolean|integer
+ */
+ public function create($user_id, $rate, $currency, $date)
+ {
+ $values = array(
+ 'user_id' => $user_id,
+ 'rate' => $rate,
+ 'currency' => $currency,
+ 'date_effective' => $this->dateParser->removeTimeFromTimestamp($this->dateParser->getTimestamp($date)),
+ );
+
+ return $this->persist(self::TABLE, $values);
+ }
+
+ /**
+ * Remove a specific rate
+ *
+ * @access public
+ * @param integer $rate_id
+ * @return boolean
+ */
+ public function remove($rate_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $rate_id)->remove();
+ }
+
+ /**
+ * Validate creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('user_id', t('Field required')),
+ new Validators\Required('rate', t('Field required')),
+ new Validators\Numeric('rate', t('This value must be numeric')),
+ new Validators\Required('date_effective', t('Field required')),
+ new Validators\Required('currency', t('Field required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php
index 12bd9309..d4f44f66 100644
--- a/app/Model/ProjectPermission.php
+++ b/app/Model/ProjectPermission.php
@@ -316,7 +316,10 @@ class ProjectPermission extends Base
{
return $this->db
->hashtable(Project::TABLE)
- ->eq('user_id', $user_id)
+ ->beginOr()
+ ->eq(self::TABLE.'.user_id', $user_id)
+ ->eq(Project::TABLE.'.is_everybody_allowed', 1)
+ ->closeOr()
->join(self::TABLE, 'project_id', 'id')
->getAll('projects.id', 'name');
}
@@ -332,7 +335,10 @@ class ProjectPermission extends Base
{
return $this->db
->table(Project::TABLE)
- ->eq('user_id', $user_id)
+ ->beginOr()
+ ->eq(self::TABLE.'.user_id', $user_id)
+ ->eq(Project::TABLE.'.is_everybody_allowed', 1)
+ ->closeOr()
->join(self::TABLE, 'project_id', 'id')
->findAllByColumn('projects.id');
}
@@ -348,7 +354,10 @@ class ProjectPermission extends Base
{
return $this->db
->table(Project::TABLE)
- ->eq('user_id', $user_id)
+ ->beginOr()
+ ->eq(self::TABLE.'.user_id', $user_id)
+ ->eq(Project::TABLE.'.is_everybody_allowed', 1)
+ ->closeOr()
->eq(Project::TABLE.'.is_active', Project::ACTIVE)
->join(self::TABLE, 'project_id', 'id')
->findAllByColumn('projects.id');
@@ -365,7 +374,10 @@ class ProjectPermission extends Base
{
return $this->db
->hashtable(Project::TABLE)
- ->eq('user_id', $user_id)
+ ->beginOr()
+ ->eq(self::TABLE.'.user_id', $user_id)
+ ->eq(Project::TABLE.'.is_everybody_allowed', 1)
+ ->closeOr()
->eq(Project::TABLE.'.is_active', Project::ACTIVE)
->join(self::TABLE, 'project_id', 'id')
->getAll('projects.id', 'name');
diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php
index 048594bd..e33373e0 100644
--- a/app/Model/Subtask.php
+++ b/app/Model/Subtask.php
@@ -19,7 +19,7 @@ class Subtask extends Base
*
* @var string
*/
- const TABLE = 'task_has_subtasks';
+ const TABLE = 'subtasks';
/**
* Task "done" status
@@ -122,7 +122,7 @@ class Subtask extends Base
->eq('task_id', $task_id)
->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
->join(User::TABLE, 'id', 'user_id')
- ->asc(self::TABLE.'.id')
+ ->asc(self::TABLE.'.position')
->filter(array($this, 'addStatusName'))
->findAll();
}
@@ -164,6 +164,22 @@ class Subtask extends Base
}
/**
+ * Get the position of the last column for a given project
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return integer
+ */
+ public function getLastPosition($task_id)
+ {
+ return (int) $this->db
+ ->table(self::TABLE)
+ ->eq('task_id', $task_id)
+ ->desc('position')
+ ->findOneColumn('position');
+ }
+
+ /**
* Create a new subtask
*
* @access public
@@ -173,6 +189,8 @@ class Subtask extends Base
public function create(array $values)
{
$this->prepare($values);
+ $values['position'] = $this->getLastPosition($values['task_id']) + 1;
+
$subtask_id = $this->persist(self::TABLE, $values);
if ($subtask_id) {
@@ -209,6 +227,64 @@ class Subtask extends Base
}
/**
+ * Move a subtask down, increment the position value
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $subtask_id
+ * @return boolean
+ */
+ public function moveDown($task_id, $subtask_id)
+ {
+ $subtasks = $this->db->hashtable(self::TABLE)->eq('task_id', $task_id)->asc('position')->getAll('id', 'position');
+ $positions = array_flip($subtasks);
+
+ if (isset($subtasks[$subtask_id]) && $subtasks[$subtask_id] < count($subtasks)) {
+
+ $position = ++$subtasks[$subtask_id];
+ $subtasks[$positions[$position]]--;
+
+ $this->db->startTransaction();
+ $this->db->table(self::TABLE)->eq('id', $subtask_id)->update(array('position' => $position));
+ $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $subtasks[$positions[$position]]));
+ $this->db->closeTransaction();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move a subtask up, decrement the position value
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $subtask_id
+ * @return boolean
+ */
+ public function moveUp($task_id, $subtask_id)
+ {
+ $subtasks = $this->db->hashtable(self::TABLE)->eq('task_id', $task_id)->asc('position')->getAll('id', 'position');
+ $positions = array_flip($subtasks);
+
+ if (isset($subtasks[$subtask_id]) && $subtasks[$subtask_id] > 1) {
+
+ $position = --$subtasks[$subtask_id];
+ $subtasks[$positions[$position]]++;
+
+ $this->db->startTransaction();
+ $this->db->table(self::TABLE)->eq('id', $subtask_id)->update(array('position' => $position));
+ $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $subtasks[$positions[$position]]));
+ $this->db->closeTransaction();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Change the status of subtask
*
* Todo -> In progress -> Done -> Todo -> etc...
@@ -286,9 +362,9 @@ class Subtask extends Base
return $this->db->transaction(function ($db) use ($src_task_id, $dst_task_id) {
$subtasks = $db->table(Subtask::TABLE)
- ->columns('title', 'time_estimated')
+ ->columns('title', 'time_estimated', 'position')
->eq('task_id', $src_task_id)
- ->asc('id') // Explicit sorting for postgresql
+ ->asc('position')
->findAll();
foreach ($subtasks as &$subtask) {
@@ -380,7 +456,7 @@ class Subtask extends Base
return array(
new Validators\Integer('id', t('The subtask id must be an integer')),
new Validators\Integer('task_id', t('The task id must be an integer')),
- new Validators\MaxLength('title', t('The maximum length is %d characters', 100), 100),
+ new Validators\MaxLength('title', t('The maximum length is %d characters', 255), 255),
new Validators\Integer('user_id', t('The user id must be an integer')),
new Validators\Integer('status', t('The status must be an integer')),
new Validators\Numeric('time_estimated', t('The time must be a numeric value')),
diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php
index 8b197c46..a984533f 100644
--- a/app/Model/SubtaskTimeTracking.php
+++ b/app/Model/SubtaskTimeTracking.php
@@ -2,6 +2,8 @@
namespace Model;
+use DateTime;
+
/**
* Subtask timesheet
*
@@ -33,6 +35,7 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.subtask_id',
self::TABLE.'.end',
self::TABLE.'.start',
+ self::TABLE.'.time_spent',
Subtask::TABLE.'.task_id',
Subtask::TABLE.'.title AS subtask_title',
Task::TABLE.'.title AS task_title',
@@ -60,6 +63,7 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.subtask_id',
self::TABLE.'.end',
self::TABLE.'.start',
+ self::TABLE.'.time_spent',
self::TABLE.'.user_id',
Subtask::TABLE.'.task_id',
Subtask::TABLE.'.title AS subtask_title',
@@ -89,6 +93,7 @@ class SubtaskTimeTracking extends Base
self::TABLE.'.subtask_id',
self::TABLE.'.end',
self::TABLE.'.start',
+ self::TABLE.'.time_spent',
self::TABLE.'.user_id',
Subtask::TABLE.'.task_id',
Subtask::TABLE.'.title AS subtask_title',
@@ -133,6 +138,8 @@ class SubtaskTimeTracking extends Base
->addCondition($this->getCalendarCondition($start, $end))
->findAll();
+ $result = $this->timetable->calculateEventsIntersect($user_id, $result, $start, $end);
+
return $this->toCalendarEvents($result);
}
@@ -235,7 +242,11 @@ class SubtaskTimeTracking extends Base
*/
public function logEndTime($subtask_id, $user_id)
{
- $this->updateSubtaskTimeSpent($subtask_id, $user_id);
+ $time_spent = $this->getTimeSpent($subtask_id, $user_id);
+
+ if ($time_spent > 0) {
+ $this->updateSubtaskTimeSpent($subtask_id, $time_spent);
+ }
return $this->db
->table(self::TABLE)
@@ -243,11 +254,60 @@ class SubtaskTimeTracking extends Base
->eq('user_id', $user_id)
->eq('end', 0)
->update(array(
- 'end' => time()
+ 'end' => time(),
+ 'time_spent' => $time_spent,
));
}
/**
+ * Calculate the time spent when the clock is stopped
+ *
+ * @access public
+ * @param integer $subtask_id
+ * @param integer $user_id
+ * @return float
+ */
+ public function getTimeSpent($subtask_id, $user_id)
+ {
+ $start_time = $this->db
+ ->table(self::TABLE)
+ ->eq('subtask_id', $subtask_id)
+ ->eq('user_id', $user_id)
+ ->eq('end', 0)
+ ->findOneColumn('start');
+
+ if ($start_time) {
+
+ $start = new DateTime;
+ $start->setTimestamp($start_time);
+
+ return $this->timetable->calculateEffectiveDuration($user_id, $start, new DateTime);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Update subtask time spent
+ *
+ * @access public
+ * @param integer $subtask_id
+ * @param float $time_spent
+ * @return bool
+ */
+ public function updateSubtaskTimeSpent($subtask_id, $time_spent)
+ {
+ $subtask = $this->subtask->getById($subtask_id);
+
+ // Fire the event subtask.update
+ return $this->subtask->update(array(
+ 'id' => $subtask['id'],
+ 'time_spent' => $subtask['time_spent'] + $time_spent,
+ 'task_id' => $subtask['task_id'],
+ ));
+ }
+
+ /**
* Update task time tracking based on subtasks time tracking
*
* @access public
@@ -289,31 +349,4 @@ class SubtaskTimeTracking extends Base
)
->findOne();
}
-
- /**
- * Update subtask time spent based on the punch clock table
- *
- * @access public
- * @param integer $subtask_id
- * @param integer $user_id
- * @return bool
- */
- public function updateSubtaskTimeSpent($subtask_id, $user_id)
- {
- $start_time = $this->db
- ->table(self::TABLE)
- ->eq('subtask_id', $subtask_id)
- ->eq('user_id', $user_id)
- ->eq('end', 0)
- ->findOneColumn('start');
-
- $subtask = $this->subtask->getById($subtask_id);
-
- return $start_time &&
- $this->subtask->update(array( // Fire the event subtask.update
- 'id' => $subtask['id'],
- 'time_spent' => $subtask['time_spent'] + round((time() - $start_time) / 3600, 1),
- 'task_id' => $subtask['task_id'],
- ));
- }
}
diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php
index c9bc43e1..cf2103c2 100644
--- a/app/Model/Swimlane.php
+++ b/app/Model/Swimlane.php
@@ -75,6 +75,22 @@ class Swimlane extends Base
}
/**
+ * Get a swimlane by the project and the name
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @param string $name Swimlane name
+ * @return array
+ */
+ public function getByName($project_id, $name)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('project_id', $project_id)
+ ->eq('name', $name)
+ ->findAll();
+ }
+
+ /**
* Get default swimlane properties
*
* @access public
@@ -83,10 +99,16 @@ class Swimlane extends Base
*/
public function getDefault($project_id)
{
- return $this->db->table(Project::TABLE)
- ->eq('id', $project_id)
- ->columns('id', 'default_swimlane', 'show_default_swimlane')
- ->findOne();
+ $result = $this->db->table(Project::TABLE)
+ ->eq('id', $project_id)
+ ->columns('id', 'default_swimlane', 'show_default_swimlane')
+ ->findOne();
+
+ if ($result['default_swimlane'] === 'Default swimlane') {
+ $result['default_swimlane'] = t($result['default_swimlane']);
+ }
+
+ return $result;
}
/**
@@ -150,6 +172,11 @@ class Swimlane extends Base
->findOneColumn('default_swimlane');
if ($default_swimlane) {
+
+ if ($default_swimlane === 'Default swimlane') {
+ $default_swimlane = t($default_swimlane);
+ }
+
array_unshift($swimlanes, array('id' => 0, 'name' => $default_swimlane));
}
@@ -167,14 +194,17 @@ class Swimlane extends Base
public function getList($project_id, $prepend = false)
{
$swimlanes = array();
- $swimlanes[] = $this->db->table(Project::TABLE)->eq('id', $project_id)->findOneColumn('default_swimlane');
+ $default = $this->db->table(Project::TABLE)->eq('id', $project_id)->eq('show_default_swimlane', 1)->findOneColumn('default_swimlane');
- $swimlanes = array_merge(
- $swimlanes,
- $this->db->hashtable(self::TABLE)->eq('project_id', $project_id)->orderBy('name', 'asc')->getAll('id', 'name')
- );
+ if ($prepend) {
+ $swimlanes[-1] = t('All swimlanes');
+ }
+
+ if (! empty($default)) {
+ $swimlanes[0] = $default === 'Default swimlane' ? t($default) : $default;
+ }
- return $prepend ? array(-1 => t('All swimlanes')) + $swimlanes : $swimlanes;
+ return $swimlanes + $this->db->hashtable(self::TABLE)->eq('project_id', $project_id)->orderBy('position', 'asc')->getAll('id', 'name');
}
/**
diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php
index 98ece4e1..7216e92a 100644
--- a/app/Model/TaskFinder.php
+++ b/app/Model/TaskFinder.php
@@ -80,11 +80,11 @@ class TaskFinder extends Base
return $this->db
->table(Task::TABLE)
->columns(
- '(SELECT count(*) FROM comments WHERE task_id=tasks.id) AS nb_comments',
- '(SELECT count(*) FROM task_has_files WHERE task_id=tasks.id) AS nb_files',
- '(SELECT count(*) FROM task_has_subtasks WHERE task_id=tasks.id) AS nb_subtasks',
- '(SELECT count(*) FROM task_has_subtasks WHERE 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 count(*) FROM '.Comment::TABLE.' WHERE task_id=tasks.id) AS nb_comments',
+ '(SELECT count(*) FROM '.File::TABLE.' WHERE task_id=tasks.id) AS nb_files',
+ '(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',
'tasks.id',
'tasks.reference',
'tasks.title',
diff --git a/app/Model/TaskLink.php b/app/Model/TaskLink.php
index f8e9f99e..62391371 100644
--- a/app/Model/TaskLink.php
+++ b/app/Model/TaskLink.php
@@ -4,6 +4,7 @@ namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
+use PicoDb\Table;
/**
* TaskLink model
@@ -57,6 +58,7 @@ class TaskLink extends Base
->join(Link::TABLE, 'id', 'link_id')
->join(Task::TABLE, 'id', 'opposite_task_id')
->join(Board::TABLE, 'id', 'column_id', Task::TABLE)
+ ->orderBy(Link::TABLE.'.id ASC, '.Board::TABLE.'.position ASC, '.Task::TABLE.'.is_active DESC, '.Task::TABLE.'.id', Table::SORT_ASC)
->findAll();
}
diff --git a/app/Model/Timetable.php b/app/Model/Timetable.php
new file mode 100644
index 00000000..da2ec10c
--- /dev/null
+++ b/app/Model/Timetable.php
@@ -0,0 +1,358 @@
+<?php
+
+namespace Model;
+
+use DateTime;
+use DateInterval;
+
+/**
+ * Timetable
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class Timetable extends Base
+{
+ /**
+ * User time slots
+ *
+ * @access private
+ * @var array
+ */
+ private $day;
+ private $week;
+ private $overtime;
+ private $timeoff;
+
+ /**
+ * Get a set of events by using the intersection between the timetable and the time tracking data
+ *
+ * @access public
+ * @param integer $user_id
+ * @param array $events Time tracking data
+ * @param string $start ISO8601 date
+ * @param string $end ISO8601 date
+ * @return array
+ */
+ public function calculateEventsIntersect($user_id, array $events, $start, $end)
+ {
+ $start_dt = new DateTime($start);
+ $start_dt->setTime(0, 0);
+
+ $end_dt = new DateTime($end);
+ $end_dt->setTime(23, 59);
+
+ $timetable = $this->calculate($user_id, $start_dt, $end_dt);
+
+ // The user has no timetable
+ if (empty($this->week)) {
+ return $events;
+ }
+
+ $results = array();
+
+ foreach ($events as $event) {
+ $results = array_merge($results, $this->calculateEventIntersect($event, $timetable));
+ }
+
+ return $results;
+ }
+
+ /**
+ * Get a serie of events based on the timetable and the provided event
+ *
+ * @access public
+ * @param integer $user_id
+ * @param array $events Time tracking data
+ * @param string $start ISO8601 date
+ * @param string $end ISO8601 date
+ * @return array
+ */
+ public function calculateEventIntersect(array $event, array $timetable)
+ {
+ $events = array();
+
+ foreach ($timetable as $slot) {
+
+ $start_ts = $slot[0]->getTimestamp();
+ $end_ts = $slot[1]->getTimestamp();
+
+ if ($start_ts > $event['end']) {
+ break;
+ }
+
+ if ($event['start'] <= $start_ts) {
+ $event['start'] = $start_ts;
+ }
+
+ if ($event['start'] >= $start_ts && $event['start'] <= $end_ts) {
+
+ if ($event['end'] >= $end_ts) {
+ $events[] = array_merge($event, array('end' => $end_ts));
+ }
+ else {
+ $events[] = $event;
+ break;
+ }
+ }
+ }
+
+ return $events;
+ }
+
+ /**
+ * Calculate effective worked hours by taking into consideration the timetable
+ *
+ * @access public
+ * @param integer $user_id
+ * @param \DateTime $start
+ * @param \DateTime $end
+ * @return float
+ */
+ public function calculateEffectiveDuration($user_id, DateTime $start, DateTime $end)
+ {
+ $end_timetable = clone($end);
+ $end_timetable->setTime(23, 59);
+
+ $timetable = $this->calculate($user_id, $start, $end_timetable);
+ $found_start = false;
+ $hours = 0;
+
+ // The user has no timetable
+ if (empty($this->week)) {
+ return $this->dateParser->getHours($start, $end);
+ }
+
+ foreach ($timetable as $slot) {
+
+ $isStartSlot = $this->dateParser->withinDateRange($start, $slot[0], $slot[1]);
+ $isEndSlot = $this->dateParser->withinDateRange($end, $slot[0], $slot[1]);
+
+ // Start and end are within the same time slot
+ if ($isStartSlot && $isEndSlot) {
+ return $this->dateParser->getHours($start, $end);
+ }
+
+ // We found the start slot
+ if (! $found_start && $isStartSlot) {
+ $found_start = true;
+ $hours = $this->dateParser->getHours($start, $slot[1]);
+ }
+ else if ($found_start) {
+
+ // We found the end slot
+ if ($isEndSlot) {
+ $hours += $this->dateParser->getHours($slot[0], $end);
+ break;
+ }
+ else {
+
+ // Sum hours of the intermediate time slots
+ $hours += $this->dateParser->getHours($slot[0], $slot[1]);
+ }
+ }
+ }
+
+ // The start date was not found in regular hours so we get the nearest time slot
+ if (! empty($timetable) && ! $found_start) {
+ $slot = $this->findClosestTimeSlot($start, $timetable);
+
+ if ($start < $slot[0]) {
+ return $this->calculateEffectiveDuration($user_id, $slot[0], $end);
+ }
+ }
+
+ return $hours;
+ }
+
+ /**
+ * Find the nearest time slot
+ *
+ * @access public
+ * @param DateTime $date
+ * @param array $timetable
+ * @return array
+ */
+ public function findClosestTimeSlot(DateTime $date, array $timetable)
+ {
+ $values = array();
+
+ foreach ($timetable as $slot) {
+ $t1 = abs($slot[0]->getTimestamp() - $date->getTimestamp());
+ $t2 = abs($slot[1]->getTimestamp() - $date->getTimestamp());
+
+ $values[] = min($t1, $t2);
+ }
+
+ asort($values);
+ return $timetable[key($values)];
+ }
+
+ /**
+ * Get the timetable for a user for a given date range
+ *
+ * @access public
+ * @param integer $user_id
+ * @param \DateTime $start
+ * @param \DateTime $end
+ * @return array
+ */
+ public function calculate($user_id, DateTime $start, DateTime $end)
+ {
+ $timetable = array();
+
+ $this->day = $this->timetableDay->getByUser($user_id);
+ $this->week = $this->timetableWeek->getByUser($user_id);
+ $this->overtime = $this->timetableExtra->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
+ $this->timeoff = $this->timetableOff->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
+
+ for ($today = clone($start); $today <= $end; $today->add(new DateInterval('P1D'))) {
+ $week_day = $today->format('N');
+ $timetable = array_merge($timetable, $this->getWeekSlots($today, $week_day));
+ $timetable = array_merge($timetable, $this->getOvertimeSlots($today, $week_day));
+ }
+
+ return $timetable;
+ }
+
+ /**
+ * Return worked time slots for the given day
+ *
+ * @access public
+ * @param \DateTime $today
+ * @param string $week_day
+ * @return array
+ */
+ public function getWeekSlots(DateTime $today, $week_day)
+ {
+ $slots = array();
+ $dayoff = $this->getDayOff($today);
+
+ if (! empty($dayoff) && $dayoff['all_day'] == 1) {
+ return array();
+ }
+
+ foreach ($this->week as $slot) {
+ if ($week_day == $slot['day']) {
+ $slots = array_merge($slots, $this->getDayWorkSlots($slot, $dayoff, $today));
+ }
+ }
+
+ return $slots;
+ }
+
+ /**
+ * Get the overtime time slots for the given day
+ *
+ * @access public
+ * @param \DateTime $today
+ * @param string $week_day
+ * @return array
+ */
+ public function getOvertimeSlots(DateTime $today, $week_day)
+ {
+ $slots = array();
+
+ foreach ($this->overtime as $slot) {
+
+ $day = new DateTime($slot['date']);
+
+ if ($week_day == $day->format('N')) {
+
+ if ($slot['all_day'] == 1) {
+ $slots = array_merge($slots, $this->getDaySlots($today));
+ }
+ else {
+ $slots[] = $this->getTimeSlot($slot, $day);
+ }
+ }
+ }
+
+ return $slots;
+ }
+
+ /**
+ * Get worked time slots and remove time off
+ *
+ * @access public
+ * @param array $slot
+ * @param array $dayoff
+ * @param \DateTime $today
+ * @return array
+ */
+ public function getDayWorkSlots(array $slot, array $dayoff, DateTime $today)
+ {
+ $slots = array();
+
+ if (! empty($dayoff) && $dayoff['start'] < $slot['end']) {
+
+ if ($dayoff['start'] > $slot['start']) {
+ $slots[] = $this->getTimeSlot(array('end' => $dayoff['start']) + $slot, $today);
+ }
+
+ if ($dayoff['end'] < $slot['end']) {
+ $slots[] = $this->getTimeSlot(array('start' => $dayoff['end']) + $slot, $today);
+ }
+ }
+ else {
+ $slots[] = $this->getTimeSlot($slot, $today);
+ }
+
+ return $slots;
+ }
+
+ /**
+ * Get regular day work time slots
+ *
+ * @access public
+ * @param \DateTime $today
+ * @return array
+ */
+ public function getDaySlots(DateTime $today)
+ {
+ $slots = array();
+
+ foreach ($this->day as $day) {
+ $slots[] = $this->getTimeSlot($day, $today);
+ }
+
+ return $slots;
+ }
+
+ /**
+ * Get the start and end time slot for a given day
+ *
+ * @access public
+ * @param array $slot
+ * @param \DateTime $today
+ * @return array
+ */
+ public function getTimeSlot(array $slot, DateTime $today)
+ {
+ $date = $today->format('Y-m-d');
+
+ return array(
+ new DateTime($date.' '.$slot['start']),
+ new DateTime($date.' '.$slot['end']),
+ );
+ }
+
+ /**
+ * Return day off time slot
+ *
+ * @access public
+ * @param \DateTime $today
+ * @return array
+ */
+ public function getDayOff(DateTime $today)
+ {
+ foreach ($this->timeoff as $day) {
+
+ if ($day['date'] === $today->format('Y-m-d')) {
+ return $day;
+ }
+ }
+
+ return array();
+ }
+}
diff --git a/app/Model/TimetableDay.php b/app/Model/TimetableDay.php
new file mode 100644
index 00000000..0c7bf20b
--- /dev/null
+++ b/app/Model/TimetableDay.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Model;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Timetable Workweek
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class TimetableDay extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'timetable_day';
+
+ /**
+ * Get the timetable for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return array
+ */
+ public function getByUser($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('start')->findAll();
+ }
+
+ /**
+ * Add a new time slot in the database
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param string $start Start hour (24h format)
+ * @param string $end End hour (24h format)
+ * @return boolean|integer
+ */
+ public function create($user_id, $start, $end)
+ {
+ $values = array(
+ 'user_id' => $user_id,
+ 'start' => $start,
+ 'end' => $end,
+ );
+
+ return $this->persist(self::TABLE, $values);
+ }
+
+ /**
+ * Remove a specific time slot
+ *
+ * @access public
+ * @param integer $slot_id
+ * @return boolean
+ */
+ public function remove($slot_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
+ }
+
+ /**
+ * Validate creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('user_id', t('Field required')),
+ new Validators\Required('start', t('Field required')),
+ new Validators\Required('end', t('Field required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Model/TimetableExtra.php b/app/Model/TimetableExtra.php
new file mode 100644
index 00000000..48db662d
--- /dev/null
+++ b/app/Model/TimetableExtra.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Model;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Timetable over-time
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class TimetableExtra extends TimetableOff
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'timetable_extra';
+}
diff --git a/app/Model/TimetableOff.php b/app/Model/TimetableOff.php
new file mode 100644
index 00000000..aa064f05
--- /dev/null
+++ b/app/Model/TimetableOff.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Model;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Timetable time off
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class TimetableOff extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'timetable_off';
+
+ /**
+ * Get query to fetch everything (pagination)
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return \PicoDb\Table
+ */
+ public function getUserQuery($user_id)
+ {
+ return $this->db->table(static::TABLE)->eq('user_id', $user_id);
+ }
+
+ /**
+ * Get the timetable for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return array
+ */
+ public function getByUser($user_id)
+ {
+ return $this->db->table(static::TABLE)->eq('user_id', $user_id)->desc('date')->asc('start')->findAll();
+ }
+
+ /**
+ * Get the timetable for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param string $start_date
+ * @param string $end_date
+ * @return array
+ */
+ public function getByUserAndDate($user_id, $start_date, $end_date)
+ {
+ return $this->db->table(static::TABLE)
+ ->eq('user_id', $user_id)
+ ->gte('date', $start_date)
+ ->lte('date', $end_date)
+ ->desc('date')
+ ->asc('start')
+ ->findAll();
+ }
+
+ /**
+ * Add a new time slot in the database
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param string $date Day (ISO8601 format)
+ * @param boolean $all_day All day flag
+ * @param float $start Start hour (24h format)
+ * @param float $end End hour (24h format)
+ * @param string $comment
+ * @return boolean|integer
+ */
+ public function create($user_id, $date, $all_day, $start = '', $end = '', $comment = '')
+ {
+ $values = array(
+ 'user_id' => $user_id,
+ 'date' => $date,
+ 'all_day' => $all_day,
+ 'start' => $all_day ? '' : $start,
+ 'end' => $all_day ? '' : $end,
+ 'comment' => $comment,
+ );
+
+ return $this->persist(static::TABLE, $values);
+ }
+
+ /**
+ * Remove a specific time slot
+ *
+ * @access public
+ * @param integer $slot_id
+ * @return boolean
+ */
+ public function remove($slot_id)
+ {
+ return $this->db->table(static::TABLE)->eq('id', $slot_id)->remove();
+ }
+
+ /**
+ * Validate creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('user_id', t('Field required')),
+ new Validators\Required('date', t('Field required')),
+ new Validators\Numeric('all_day', t('This value must be numeric')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Model/TimetableWeek.php b/app/Model/TimetableWeek.php
new file mode 100644
index 00000000..b22b3b7e
--- /dev/null
+++ b/app/Model/TimetableWeek.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Model;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Timetable Workweek
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class TimetableWeek extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'timetable_week';
+
+ /**
+ * Get the timetable for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return array
+ */
+ public function getByUser($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('day')->asc('start')->findAll();
+ }
+
+ /**
+ * Add a new time slot in the database
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param string $day Day of the week (ISO-8601)
+ * @param string $start Start hour (24h format)
+ * @param string $end End hour (24h format)
+ * @return boolean|integer
+ */
+ public function create($user_id, $day, $start, $end)
+ {
+ $values = array(
+ 'user_id' => $user_id,
+ 'day' => $day,
+ 'start' => $start,
+ 'end' => $end,
+ );
+
+ return $this->persist(self::TABLE, $values);
+ }
+
+ /**
+ * Remove a specific time slot
+ *
+ * @access public
+ * @param integer $slot_id
+ * @return boolean
+ */
+ public function remove($slot_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
+ }
+
+ /**
+ * Validate creation
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('user_id', t('Field required')),
+ new Validators\Required('day', t('Field required')),
+ new Validators\Numeric('day', t('This value must be numeric')),
+ new Validators\Required('start', t('Field required')),
+ new Validators\Required('end', t('Field required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index 947a62b3..a78ffacf 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,123 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 46;
+const VERSION = 54;
+
+function version_54($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('application_stylesheet', ''));
+}
+
+function version_53($pdo)
+{
+ $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent FLOAT DEFAULT 0");
+}
+
+function version_52($pdo)
+{
+ $pdo->exec('CREATE TABLE budget_lines (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `project_id` INT NOT NULL,
+ `amount` FLOAT NOT NULL,
+ `date` VARCHAR(10) NOT NULL,
+ `comment` TEXT,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+}
+
+function version_51($pdo)
+{
+ $pdo->exec('CREATE TABLE timetable_day (
+ id INT NOT NULL AUTO_INCREMENT,
+ user_id INT NOT NULL,
+ start VARCHAR(5) NOT NULL,
+ end VARCHAR(5) NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+
+ $pdo->exec('CREATE TABLE timetable_week (
+ id INT NOT NULL AUTO_INCREMENT,
+ user_id INTEGER NOT NULL,
+ day INT NOT NULL,
+ start VARCHAR(5) NOT NULL,
+ end VARCHAR(5) NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+
+ $pdo->exec('CREATE TABLE timetable_off (
+ id INT NOT NULL AUTO_INCREMENT,
+ user_id INT NOT NULL,
+ date VARCHAR(10) NOT NULL,
+ all_day TINYINT(1) DEFAULT 0,
+ start VARCHAR(5) DEFAULT 0,
+ end VARCHAR(5) DEFAULT 0,
+ comment TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+
+ $pdo->exec('CREATE TABLE timetable_extra (
+ id INT NOT NULL AUTO_INCREMENT,
+ user_id INT NOT NULL,
+ date VARCHAR(10) NOT NULL,
+ all_day TINYINT(1) DEFAULT 0,
+ start VARCHAR(5) DEFAULT 0,
+ end VARCHAR(5) DEFAULT 0,
+ comment TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8');
+}
+
+function version_50($pdo)
+{
+ $pdo->exec("CREATE TABLE hourly_rates (
+ id INT NOT NULL AUTO_INCREMENT,
+ user_id INT NOT NULL,
+ rate FLOAT DEFAULT 0,
+ date_effective INTEGER NOT NULL,
+ currency TEXT NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
+ PRIMARY KEY(id)
+ ) ENGINE=InnoDB CHARSET=utf8");
+}
+
+function version_49($pdo)
+{
+ $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
+
+ $task_id = 0;
+ $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?');
+
+ $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC');
+ $rq->execute();
+
+ foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) {
+
+ if ($task_id != $subtask['task_id']) {
+ $position = 1;
+ $task_id = $subtask['task_id'];
+ }
+
+ $urq->execute(array($position, $subtask['id']));
+ $position++;
+ }
+}
+
+function version_48($pdo)
+{
+ $pdo->exec('RENAME TABLE task_has_files TO files');
+ $pdo->exec('RENAME TABLE task_has_subtasks TO subtasks');
+}
+
+function version_47($pdo)
+{
+ $pdo->exec('ALTER TABLE projects ADD COLUMN description TEXT');
+}
function version_46($pdo)
{
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 027401ff..2396000f 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,117 @@ use PDO;
use Core\Security;
use Model\Link;
-const VERSION = 27;
+const VERSION = 35;
+
+function version_35($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('application_stylesheet', ''));
+}
+
+function version_34($pdo)
+{
+ $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0");
+}
+
+function version_33($pdo)
+{
+ $pdo->exec('CREATE TABLE budget_lines (
+ "id" SERIAL PRIMARY KEY,
+ "project_id" INTEGER NOT NULL,
+ "amount" REAL NOT NULL,
+ "date" VARCHAR(10) NOT NULL,
+ "comment" TEXT,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
+ )');
+}
+
+function version_32($pdo)
+{
+ $pdo->exec('CREATE TABLE timetable_day (
+ "id" SERIAL PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "start" VARCHAR(5) NOT NULL,
+ "end" VARCHAR(5) NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_week (
+ "id" SERIAL PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "day" INTEGER NOT NULL,
+ "start" VARCHAR(5) NOT NULL,
+ "end" VARCHAR(5) NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_off (
+ "id" SERIAL PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "date" VARCHAR(10) NOT NULL,
+ "all_day" BOOLEAN DEFAULT \'0\',
+ "start" VARCHAR(5) DEFAULT 0,
+ "end" VARCHAR(5) DEFAULT 0,
+ "comment" TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_extra (
+ "id" SERIAL PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "date" VARCHAR(10) NOT NULL,
+ "all_day" BOOLEAN DEFAULT \'0\',
+ "start" VARCHAR(5) DEFAULT 0,
+ "end" VARCHAR(5) DEFAULT 0,
+ "comment" TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+}
+
+function version_31($pdo)
+{
+ $pdo->exec("CREATE TABLE hourly_rates (
+ id SERIAL PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ rate REAL DEFAULT 0,
+ date_effective INTEGER NOT NULL,
+ currency TEXT NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )");
+}
+
+function version_30($pdo)
+{
+ $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
+
+ $task_id = 0;
+ $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?');
+
+ $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC');
+ $rq->execute();
+
+ foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) {
+
+ if ($task_id != $subtask['task_id']) {
+ $position = 1;
+ $task_id = $subtask['task_id'];
+ }
+
+ $urq->execute(array($position, $subtask['id']));
+ $position++;
+ }
+}
+
+function version_29($pdo)
+{
+ $pdo->exec('ALTER TABLE task_has_files RENAME TO files');
+ $pdo->exec('ALTER TABLE task_has_subtasks RENAME TO subtasks');
+}
+
+function version_28($pdo)
+{
+ $pdo->exec('ALTER TABLE projects ADD COLUMN description TEXT');
+}
function version_27($pdo)
{
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index c6dec33f..0e0512d0 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,119 @@ use Core\Security;
use PDO;
use Model\Link;
-const VERSION = 45;
+const VERSION = 53;
+
+function version_53($pdo)
+{
+ $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
+ $rq->execute(array('application_stylesheet', ''));
+}
+
+function version_52($pdo)
+{
+ $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0");
+}
+
+function version_51($pdo)
+{
+ $pdo->exec('CREATE TABLE budget_lines (
+ "id" INTEGER PRIMARY KEY,
+ "project_id" INTEGER NOT NULL,
+ "amount" REAL NOT NULL,
+ "date" TEXT NOT NULL,
+ "comment" TEXT,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
+ )');
+}
+
+function version_50($pdo)
+{
+ $pdo->exec('CREATE TABLE timetable_day (
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "start" TEXT NOT NULL,
+ "end" TEXT NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_week (
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "day" INTEGER NOT NULL,
+ "start" TEXT NOT NULL,
+ "end" TEXT NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_off (
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "date" TEXT NOT NULL,
+ "all_day" INTEGER DEFAULT 0,
+ "start" TEXT DEFAULT 0,
+ "end" TEXT DEFAULT 0,
+ "comment" TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+
+ $pdo->exec('CREATE TABLE timetable_extra (
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL,
+ "date" TEXT NOT NULL,
+ "all_day" INTEGER DEFAULT 0,
+ "start" TEXT DEFAULT 0,
+ "end" TEXT DEFAULT 0,
+ "comment" TEXT,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )');
+}
+
+function version_49($pdo)
+{
+ $pdo->exec("CREATE TABLE hourly_rates (
+ id INTEGER PRIMARY KEY,
+ user_id INTEGER NOT NULL,
+ rate REAL DEFAULT 0,
+ date_effective INTEGER NOT NULL,
+ currency TEXT NOT NULL,
+ FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
+ )");
+}
+
+function version_48($pdo)
+{
+ $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1');
+
+ // Migrate all subtasks position
+
+ $task_id = 0;
+ $urq = $pdo->prepare('UPDATE subtasks SET position=? WHERE id=?');
+
+ $rq = $pdo->prepare('SELECT * FROM subtasks ORDER BY task_id, id ASC');
+ $rq->execute();
+
+ foreach ($rq->fetchAll(PDO::FETCH_ASSOC) as $subtask) {
+
+ if ($task_id != $subtask['task_id']) {
+ $position = 1;
+ $task_id = $subtask['task_id'];
+ }
+
+ $urq->execute(array($position, $subtask['id']));
+ $position++;
+ }
+}
+
+function version_47($pdo)
+{
+ $pdo->exec('ALTER TABLE task_has_files RENAME TO files');
+ $pdo->exec('ALTER TABLE task_has_subtasks RENAME TO subtasks');
+}
+
+function version_46($pdo)
+{
+ $pdo->exec('ALTER TABLE projects ADD COLUMN description TEXT');
+}
function version_45($pdo)
{
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 213972ed..fc71ebf9 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -17,12 +17,14 @@ class ClassProvider implements ServiceProviderInterface
'Action',
'Authentication',
'Board',
+ 'Budget',
'Category',
'Color',
'Comment',
'Config',
'DateParser',
'File',
+ 'HourlyRate',
'LastLogin',
'Link',
'Notification',
@@ -48,7 +50,11 @@ class ClassProvider implements ServiceProviderInterface
'TaskPosition',
'TaskStatus',
'TaskValidator',
- 'TimeTracking',
+ 'Timetable',
+ 'TimetableDay',
+ 'TimetableWeek',
+ 'TimetableOff',
+ 'TimetableExtra',
'User',
'UserSession',
'Webhook',
diff --git a/app/ServiceProvider/DatabaseProvider.php b/app/ServiceProvider/DatabaseProvider.php
index 4218f5ff..7ee35d5f 100644
--- a/app/ServiceProvider/DatabaseProvider.php
+++ b/app/ServiceProvider/DatabaseProvider.php
@@ -79,6 +79,7 @@ class DatabaseProvider implements ServiceProviderInterface
'password' => DB_PASSWORD,
'database' => DB_NAME,
'charset' => 'utf8',
+ 'port' => DB_PORT,
));
}
@@ -97,6 +98,7 @@ class DatabaseProvider implements ServiceProviderInterface
'username' => DB_USERNAME,
'password' => DB_PASSWORD,
'database' => DB_NAME,
+ 'port' => DB_PORT,
));
}
}
diff --git a/app/Template/analytic/layout.php b/app/Template/analytic/layout.php
index 8c946699..c6e3a962 100644
--- a/app/Template/analytic/layout.php
+++ b/app/Template/analytic/layout.php
@@ -1,5 +1,5 @@
<?= $this->js('assets/js/vendor/d3.v3.4.8.min.js') ?>
-<?= $this->js('assets/js/vendor/dimple.v2.1.0.min.js') ?>
+<?= $this->js('assets/js/vendor/dimple.v2.1.2.min.js') ?>
<section id="main">
<div class="page-header">
diff --git a/app/Template/app/dashboard.php b/app/Template/app/dashboard.php
index e6f124e1..5b83540c 100644
--- a/app/Template/app/dashboard.php
+++ b/app/Template/app/dashboard.php
@@ -11,8 +11,8 @@
<li><i class="fa fa-cog fa-fw"></i><?= $this->a(t('Settings'), 'config', 'index') ?></li>
<?php endif ?>
<li>
- <ul class="dropdown">
- <li>
+ <span class="dropdown">
+ <span>
<i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Change dashboard view') ?></a>
<ul>
<li>
@@ -31,8 +31,8 @@
<a href="#" class="dashboard-toggle" data-toggle="activities"><?= t('Show/hide activities') ?></a>
</li>
</ul>
- </li>
- </ul>
+ </span>
+ </span>
</li>
</ul>
</div>
diff --git a/app/Template/app/projects.php b/app/Template/app/projects.php
index 4740c4b8..b2744644 100644
--- a/app/Template/app/projects.php
+++ b/app/Template/app/projects.php
@@ -17,9 +17,15 @@
<?php if ($this->isManager($project['id'])): ?>
<?= $this->a('<i class="fa fa-cog"></i>', 'project', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Settings')) ?>&nbsp;
<?php endif ?>
-
+
<?= $this->a('<i class="fa fa-calendar"></i>', 'calendar', 'show', array('project_id' => $project['id']), false, 'dashboard-table-link', t('Calendar')) ?>&nbsp;
+
<?= $this->a($this->e($project['name']), 'board', 'show', array('project_id' => $project['id'])) ?>
+ <?php if (! empty($project['description'])): ?>
+ <span class="column-tooltip" title='<?= $this->e($this->markdown($project['description'])) ?>'>
+ <i class="fa fa-info-circle"></i>
+ </span>
+ <?php endif ?>
</td>
<td class="dashboard-project-stats">
<?php foreach ($project['columns'] as $column): ?>
@@ -32,4 +38,4 @@
</table>
<?= $paginator ?>
-<?php endif ?> \ No newline at end of file
+<?php endif ?>
diff --git a/app/Template/board/edit.php b/app/Template/board/edit.php
index b9b1788a..a6df1000 100644
--- a/app/Template/board/edit.php
+++ b/app/Template/board/edit.php
@@ -13,7 +13,7 @@
<tr>
<td class="column-60"><?= $this->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
- <span class="column-tooltip" title="<?= $this->markdown($column['description']) ?>">
+ <span class="column-tooltip" title='<?= $this->e($this->markdown($column['description'])) ?>'>
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
@@ -52,12 +52,12 @@
<?= $this->formLabel(t('Title'), 'title') ?>
<?= $this->formText('title', $values, $errors, array('required', 'maxlength="50"')) ?>
-
+
<?= $this->formLabel(t('Task limit'), 'task_limit') ?>
<?= $this->formNumber('task_limit', $values, $errors) ?>
-
+
<?= $this->formLabel(t('Description'), 'description') ?>
-
+
<div class="form-tabs">
<div class="write-area">
<?= $this->formTextarea('description', $values, $errors) ?>
diff --git a/app/Template/board/files.php b/app/Template/board/files.php
index 278b906b..851a118d 100644
--- a/app/Template/board/files.php
+++ b/app/Template/board/files.php
@@ -1,14 +1,31 @@
<section>
- <?php foreach ($files as $file): ?>
- <i class="fa fa-file-o fa-fw"></i>
-
- <?= $this->a(
- $this->e($file['name']),
- 'file',
- 'download',
- array('file_id' => $file['id'], 'task_id' => $file['task_id'], 'project_id' => $task['project_id'])
- ) ?>
-
- <br/>
- <?php endforeach ?>
+ <table>
+ <?php if (! empty($images)): ?>
+ <?php foreach ($images as $file): ?>
+ <tr>
+ <td class="column-70">
+ <i class="fa fa-file-image-o fa-fw"></i>
+ <?= $this->e($file['name']) ?>
+ </td>
+ <td>
+ <i class="fa fa-download"></i> <?= $this->a(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <i class="fa fa-eye"></i> <?= $this->a(t('open'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ <?php endif ?>
+ <?php if (! empty($files)): ?>
+ <?php foreach ($files as $file): ?>
+ <tr>
+ <td>
+ <i class="fa <?= $this->getFileIcon($file['name']) ?> fa-fw"></i>
+ <?= $this->e($file['name']) ?>
+ </td>
+ <td>
+ <i class="fa fa-download"></i> <?= $this->a(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ <?php endif ?>
+ </table>
</section>
diff --git a/app/Template/board/filters.php b/app/Template/board/filters.php
index a0de5fd9..47304d7d 100644
--- a/app/Template/board/filters.php
+++ b/app/Template/board/filters.php
@@ -1,8 +1,8 @@
<div class="page-header">
<ul class="board-filters">
<li>
- <ul class="dropdown">
- <li>
+ <span class="dropdown">
+ <span>
<i class="fa fa-caret-down"></i> <a href="#" class="dropdown-menu"><?= t('Actions') ?></a>
<ul>
<li>
@@ -14,6 +14,14 @@
</span>
</li>
<li>
+ <span class="filter-compact">
+ <i class="fa fa-th fa-fw"></i> <a href="#" class="filter-toggle-scrolling"><?= t('Compact view') ?></a>
+ </span>
+ <span class="filter-wide" style="display: none">
+ <i class="fa fa-arrows-h fa-fw"></i> <a href="#" class="filter-toggle-scrolling"><?= t('Horizontal scrolling') ?></a>
+ </span>
+ </li>
+ <li>
<i class="fa fa-search fa-fw"></i>
<?= $this->a(t('Search'), 'project', 'search', array('project_id' => $project['id'])) ?>
</li>
@@ -40,22 +48,26 @@
<?= $this->a(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
</li>
<li>
+ <i class="fa fa-pie-chart fa-fw"></i>
+ <?= $this->a(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?>
+ </li>
+ <li>
<i class="fa fa-cog fa-fw"></i>
<?= $this->a(t('Configure'), 'project', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
</ul>
- </li>
- </ul>
+ </span>
+ </span>
</li>
<li>
- <?= $this->formSelect('user_id', $users, array(), array(), array('data-placeholder="'.t('Filter by user').'"'), 'apply-filters chosen-select') ?>
+ <?= $this->formSelect('user_id', $users, array(), array(), array('data-placeholder="'.t('Filter by user').'"', 'data-notfound="'.t('No results match:').'"'), 'apply-filters chosen-select') ?>
</li>
<li>
- <?= $this->formSelect('category_id', $categories, array(), array(), array('data-placeholder="'.t('Filter by category').'"'), 'apply-filters chosen-select') ?>
+ <?= $this->formSelect('category_id', $categories, array(), array(), array('data-placeholder="'.t('Filter by category').'"', 'data-notfound="'.t('No results match:').'"'), 'apply-filters chosen-select') ?>
</li>
<li>
- <select id="more-filters" multiple data-placeholder="<?= t('More filters') ?>" class="apply-filters chosen-select hide-mobile">
+ <select id="more-filters" multiple data-placeholder="<?= t('More filters') ?>" data-notfound="<?= t('No results match:') ?>" class="apply-filters chosen-select hide-mobile">
<option value=""></option>
<option value="filter-due-date"><?= t('Filter by due date') ?></option>
<option value="filter-recent"><?= t('Filter recently updated') ?></option>
diff --git a/app/Template/board/show.php b/app/Template/board/show.php
index f1607d26..6f81fe2e 100644
--- a/app/Template/board/show.php
+++ b/app/Template/board/show.php
@@ -1,8 +1,9 @@
<div id="board-container">
<?php if (isset($not_editable)): ?>
- <table id="board">
+ <table id="board" class="board-project-<?= $project['id'] ?>">
<?php else: ?>
<table id="board"
+ class="board-project-<?= $project['id'] ?>"
data-project-id="<?= $project['id'] ?>"
data-check-interval="<?= $board_private_refresh_interval ?>"
data-save-url="<?= $this->u('board', 'save', array('project_id' => $project['id'])) ?>"
diff --git a/app/Template/board/swimlane.php b/app/Template/board/swimlane.php
index ec298e24..744610ab 100644
--- a/app/Template/board/swimlane.php
+++ b/app/Template/board/swimlane.php
@@ -28,7 +28,7 @@
<?= $this->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
- <span class="column-tooltip pull-right" title="<?= $this->markdown($column['description']) ?>">
+ <span class="column-tooltip pull-right" title='<?= $this->e($this->markdown($column['description'])) ?>'>
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
diff --git a/app/Template/board/task_footer.php b/app/Template/board/task_footer.php
index d413692c..635ed31f 100644
--- a/app/Template/board/task_footer.php
+++ b/app/Template/board/task_footer.php
@@ -22,19 +22,19 @@
<?php endif ?>
<?php if (! empty($task['nb_links'])): ?>
- <span title="<?= t('Links') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_links'] ?> <i class="fa fa-code-fork"></i></span>
+ <span title="<?= t('Links') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'tasklinks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-code-fork"></i>&nbsp;<?= $task['nb_links'] ?></span>
<?php endif ?>
<?php if (! empty($task['nb_subtasks'])): ?>
- <span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?> <i class="fa fa-bars"></i></span>
+ <span title="<?= t('Sub-Tasks') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'subtasks', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-bars"></i>&nbsp;<?= round($task['nb_completed_subtasks']/$task['nb_subtasks']*100, 0).'%' ?></span>
<?php endif ?>
<?php if (! empty($task['nb_files'])): ?>
- <span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_files'] ?> <i class="fa fa-paperclip"></i></span>
+ <span title="<?= t('Attachments') ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'attachments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-paperclip"></i>&nbsp;<?= $task['nb_files'] ?></span>
<?php endif ?>
<?php if (! empty($task['nb_comments'])): ?>
- <span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $task['nb_comments'] ?> <i class="fa fa-comment-o"></i></span>
+ <span title="<?= p($task['nb_comments'], t('%d comment', $task['nb_comments']), t('%d comments', $task['nb_comments'])) ?>" class="task-board-tooltip" data-href="<?= $this->u('board', 'comments', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><i class="fa fa-comment-o"></i>&nbsp;<?= $task['nb_comments'] ?></span>
<?php endif ?>
<?php if (! empty($task['description'])): ?>
@@ -42,4 +42,8 @@
<i class="fa fa-file-text-o"></i>
</span>
<?php endif ?>
-</div> \ No newline at end of file
+
+ <?php if ($task['score']): ?>
+ <span class="task-score"><?= $this->e($task['score']) ?></span>
+ <?php endif ?>
+</div>
diff --git a/app/Template/board/task_menu.php b/app/Template/board/task_menu.php
index e7e0f419..35104b66 100644
--- a/app/Template/board/task_menu.php
+++ b/app/Template/board/task_menu.php
@@ -1,13 +1,14 @@
-<ul class="dropdown">
- <li>
+<span class="dropdown">
+ <span>
<a href="#" class="dropdown-menu"><?= '#'.$task['id'] ?></a>
<ul>
<li><i class="fa fa-user"></i> <?= $this->a(t('Change assignee'), 'board', 'changeAssignee', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-tag"></i> <?= $this->a(t('Change category'), 'board', 'changeCategory', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-align-left"></i> <?= $this->a(t('Change description'), 'task', 'description', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-comment-o"></i> <?= $this->a(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
+ <li><i class="fa fa-code-fork"></i> <?= $this->a(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-pencil-square-o"></i> <?= $this->a(t('Edit this task'), 'task', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-close"></i> <?= $this->a(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
</ul>
- </li>
-</ul> \ No newline at end of file
+ </span>
+</span> \ No newline at end of file
diff --git a/app/Template/board/task_private.php b/app/Template/board/task_private.php
index 71d94fbf..9e7358f0 100644
--- a/app/Template/board/task_private.php
+++ b/app/Template/board/task_private.php
@@ -31,10 +31,6 @@
) ?>
</span>
- <?php if ($task['score']): ?>
- <span class="task-score"><?= $this->e($task['score']) ?></span>
- <?php endif ?>
-
<div class="task-board-days">
<span title="<?= t('Task age in days')?>" class="task-days-age"><?= $this->getTaskAge($task['date_creation']) ?></span>
<span title="<?= t('Days in this column')?>" class="task-days-incolumn"><?= $this->getTaskAge($task['date_moved']) ?></span>
diff --git a/app/Template/board/task_public.php b/app/Template/board/task_public.php
index 650b956d..4e3ad18c 100644
--- a/app/Template/board/task_public.php
+++ b/app/Template/board/task_public.php
@@ -18,10 +18,6 @@
<?php endif ?>
</span>
- <?php if ($task['score']): ?>
- <span class="task-score"><?= $this->e($task['score']) ?></span>
- <?php endif ?>
-
<div class="task-board-title">
<?= $this->a($this->e($task['title']), 'task', 'readonly', array('task_id' => $task['id'], 'token' => $project['token'])) ?>
</div>
diff --git a/app/Template/budget/breakdown.php b/app/Template/budget/breakdown.php
new file mode 100644
index 00000000..d4168406
--- /dev/null
+++ b/app/Template/budget/breakdown.php
@@ -0,0 +1,34 @@
+<div class="page-header">
+ <h2><?= t('Budget') ?></h2>
+ <ul>
+ <li><?= $this->a(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?></li>
+ <li><?= $this->a(t('Cost breakdown'), 'budget', 'breakdown', array('project_id' => $project['id'])) ?></li>
+ </ul>
+</div>
+
+<?php if ($paginator->isEmpty()): ?>
+ <p class="alert"><?= t('There is nothing to show.') ?></p>
+<?php else: ?>
+ <table class="table-fixed">
+ <tr>
+ <th class="column-20"><?= $paginator->order(t('Task'), 'task_title') ?></th>
+ <th class="column-25"><?= $paginator->order(t('Subtask'), 'subtask_title') ?></th>
+ <th class="column-20"><?= $paginator->order(t('User'), 'username') ?></th>
+ <th class="column-10"><?= t('Cost') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Time spent'), 'time_spent') ?></th>
+ <th class="column-15"><?= $paginator->order(t('Date'), 'start') ?></th>
+ </tr>
+ <?php foreach ($paginator->getCollection() as $record): ?>
+ <tr>
+ <td><?= $this->a($this->e($record['task_title']), 'task', 'show', array('project_id' => $project['id'], 'task_id' => $record['task_id'])) ?></td>
+ <td><?= $this->a($this->e($record['subtask_title']), 'task', 'show', array('project_id' => $project['id'], 'task_id' => $record['task_id'])) ?></td>
+ <td><?= $this->e($record['name'] ?: $record['username']) ?></td>
+ <td><?= n($record['cost']) ?></td>
+ <td><?= n($record['time_spent']).' '.t('hours') ?></td>
+ <td><?= dt('%B %e, %Y', $record['start']) ?></td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+
+ <?= $paginator ?>
+<?php endif ?> \ No newline at end of file
diff --git a/app/Template/budget/create.php b/app/Template/budget/create.php
new file mode 100644
index 00000000..5a919ce6
--- /dev/null
+++ b/app/Template/budget/create.php
@@ -0,0 +1,51 @@
+<div class="page-header">
+ <h2><?= t('Budget') ?></h2>
+ <ul>
+ <li><?= $this->a(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?></li>
+ <li><?= $this->a(t('Cost breakdown'), 'budget', 'breakdown', array('project_id' => $project['id'])) ?></li>
+ </ul>
+</div>
+
+<?php if (! empty($lines)): ?>
+<table class="table-fixed table-stripped">
+ <tr>
+ <th class="column-20"><?= t('Budget line') ?></th>
+ <th class="column-20"><?= t('Date') ?></th>
+ <th><?= t('Comment') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($lines as $line): ?>
+ <tr>
+ <td><?= n($line['amount']) ?></td>
+ <td><?= $this->e($line['date']) ?></td>
+ <td><?= $this->e($line['comment']) ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'budget', 'confirm', array('project_id' => $project['id'], 'budget_id' => $line['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<h3><?= t('New budget line') ?></h3>
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('budget', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formHidden('id', $values) ?>
+ <?= $this->formHidden('project_id', $values) ?>
+
+ <?= $this->formLabel(t('Amount'), 'amount') ?>
+ <?= $this->formText('amount', $values, $errors, array('required'), 'form-numeric') ?>
+
+ <?= $this->formLabel(t('Date'), 'date') ?>
+ <?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
+
+ <?= $this->formLabel(t('Comment'), 'comment') ?>
+ <?= $this->formText('comment', $values, $errors) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form> \ No newline at end of file
diff --git a/app/Template/budget/index.php b/app/Template/budget/index.php
new file mode 100644
index 00000000..442a6b64
--- /dev/null
+++ b/app/Template/budget/index.php
@@ -0,0 +1,35 @@
+<?= $this->js('assets/js/vendor/d3.v3.4.8.min.js') ?>
+<?= $this->js('assets/js/vendor/dimple.v2.1.2.min.js') ?>
+
+<div class="page-header">
+ <h2><?= t('Budget') ?></h2>
+ <ul>
+ <li><?= $this->a(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?></li>
+ <li><?= $this->a(t('Cost breakdown'), 'budget', 'breakdown', array('project_id' => $project['id'])) ?></li>
+ </ul>
+</div>
+
+<?php if (! empty($daily_budget)): ?>
+<div id="budget-chart">
+ <div id="chart"
+ data-serie='<?= json_encode($daily_budget) ?>'
+ data-labels='<?= json_encode(array('in' => t('Budget line'), 'out' => t('Expenses'), 'left' => t('Remaining'), 'value' => t('Amount'), 'date' => t('Date'), 'type' => t('Type'))) ?>'></div>
+</div>
+<hr/>
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= t('Date') ?></td>
+ <th><?= t('Budget line') ?></td>
+ <th><?= t('Expenses') ?></td>
+ <th><?= t('Remaining') ?></td>
+ </tr>
+ <?php foreach ($daily_budget as $line): ?>
+ <tr>
+ <td><?= $this->e($line['date']) ?></td>
+ <td><?= n($line['in']) ?></td>
+ <td><?= n($line['out']) ?></td>
+ <td><?= n($line['left']) ?></td>
+ </tr>
+ <?php endforeach ?>
+</table>
+<?php endif ?>
diff --git a/app/Template/budget/remove.php b/app/Template/budget/remove.php
new file mode 100644
index 00000000..97f9c3dc
--- /dev/null
+++ b/app/Template/budget/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove budget line') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this budget line?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'budget', 'remove', array('project_id' => $project['id'], 'budget_id' => $budget_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'budget', 'create', array('project_id' => $project['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/config/about.php b/app/Template/config/about.php
index f6474e21..b6ed43e5 100644
--- a/app/Template/config/about.php
+++ b/app/Template/config/about.php
@@ -46,6 +46,7 @@
<ul>
<li><?= t('New task') ?> = <strong>n</strong></li>
<li><?= t('Expand/collapse tasks') ?> = <strong>s</strong></li>
+ <li><?= t('Compact/wide view') ?> = <strong>c</strong></li>
</ul>
<h3><?= t('Application') ?></h3>
<ul>
diff --git a/app/Template/config/application.php b/app/Template/config/application.php
index 26f3743e..f6c9db94 100644
--- a/app/Template/config/application.php
+++ b/app/Template/config/application.php
@@ -20,6 +20,9 @@
<?= $this->formSelect('application_date_format', $date_formats, $values, $errors) ?><br/>
<p class="form-help"><?= t('ISO format is always accepted, example: "%s" and "%s"', date('Y-m-d'), date('Y_m_d')) ?></p>
+ <?= $this->formLabel(t('Custom Stylesheet'), 'application_stylesheet') ?>
+ <?= $this->formTextarea('application_stylesheet', $values, $errors) ?><br/>
+
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
diff --git a/app/Template/file/show.php b/app/Template/file/show.php
index 298976f6..b181ab54 100644
--- a/app/Template/file/show.php
+++ b/app/Template/file/show.php
@@ -1,23 +1,48 @@
-<?php if (! empty($files)): ?>
+<?php if (! empty($files) || ! empty($images)): ?>
<div id="attachments" class="task-show-section">
<div class="page-header">
<h2><?= t('Attachments') ?></h2>
</div>
+ <?php if (!empty($images)): ?>
+ <h3><?= t('Images') ?></h3>
+ <ul class="task-show-images">
+ <?php foreach ($images as $file): ?>
+ <li>
+ <div class="img_container">
+ <img src="<?= $this->u('file', 'thumbnail', array('width' => 250, 'file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/>
+ </div>
+ <p>
+ <?= $this->e($file['name']) ?>
+ </p>
+ <span class="task-show-file-actions task-show-image-actions">
+ <i class="fa fa-eye"></i> <?= $this->a(t('open'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <i class="fa fa-trash"></i> <?= $this->a(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <i class="fa fa-download"></i> <?= $this->a(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ </span>
+ </li>
+ <?php endforeach ?>
+ </ul>
+ <?php endif ?>
- <ul class="task-show-files">
- <?php foreach ($files as $file): ?>
- <li>
- <?= $this->a($this->e($file['name']), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
- <span class="task-show-file-actions">
- <?php if ($file['is_image']): ?>
- <?= $this->a(t('open'), 'file', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>,
- <?php endif ?>
- <?= $this->a(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
- </span>
- </li>
- <?php endforeach ?>
- </ul>
-
+ <?php if (! empty($files)): ?>
+ <h3><?= t('Files') ?></h3>
+ <table class="task-show-file-table">
+ <?php foreach ($files as $file): ?>
+ <tr>
+ <td><i class="fa <?= $this->getFileIcon($file['name']) ?> fa-fw"></i></td>
+ <td>
+ <?= $this->e($file['name']) ?>
+ </td>
+ <td>
+ <span class="task-show-file-actions">
+ <i class="fa fa-trash"></i> <?= $this->a(t('remove'), 'file', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <i class="fa fa-download"></i> <?= $this->a(t('download'), 'file', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ </span>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+ <?php endif ?>
</div>
<?php endif ?> \ No newline at end of file
diff --git a/app/Template/hourlyrate/index.php b/app/Template/hourlyrate/index.php
new file mode 100644
index 00000000..9d0b77c8
--- /dev/null
+++ b/app/Template/hourlyrate/index.php
@@ -0,0 +1,46 @@
+<div class="page-header">
+ <h2><?= t('Hourly rates') ?></h2>
+</div>
+
+<?php if (! empty($rates)): ?>
+
+<table>
+ <tr>
+ <th><?= t('Hourly rate') ?></th>
+ <th><?= t('Currency') ?></th>
+ <th><?= t('Effective date') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($rates as $rate): ?>
+ <tr>
+ <td><?= n($rate['rate']) ?></td>
+ <td><?= $rate['currency'] ?></td>
+ <td><?= dt('%b %e, %Y', $rate['date_effective']) ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'hourlyrate', 'confirm', array('user_id' => $user['id'], 'rate_id' => $rate['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<h3><?= t('Add new rate') ?></h3>
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('hourlyrate', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->formHidden('user_id', $values) ?>
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formLabel(t('Hourly rate'), 'rate') ?>
+ <?= $this->formText('rate', $values, $errors, array('required'), 'form-numeric') ?>
+
+ <?= $this->formLabel(t('Currency'), 'currency') ?>
+ <?= $this->formSelect('currency', $currencies_list, $values, $errors, array('required')) ?>
+
+ <?= $this->formLabel(t('Effective date'), 'date_effective') ?>
+ <?= $this->formText('date_effective', $values, $errors, array('required'), 'form-date') ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form>
diff --git a/app/Template/hourlyrate/remove.php b/app/Template/hourlyrate/remove.php
new file mode 100644
index 00000000..7f22728e
--- /dev/null
+++ b/app/Template/hourlyrate/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove hourly rate') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this hourly rate?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'hourlyrate', 'remove', array('user_id' => $user['id'], 'rate_id' => $rate_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/layout.php b/app/Template/layout.php
index ad4c4084..ec9f2288 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -17,6 +17,10 @@
<?= $this->css($this->u('app', 'colors'), false) ?>
<?= $this->css('assets/css/app.css') ?>
+ <?php if ($this->config->get('application_stylesheet')): ?>
+ <style><?= $this->config->get('application_stylesheet') ?></style>
+ <?php endif ?>
+
<link rel="icon" type="image/png" href="assets/img/favicon.png">
<link rel="apple-touch-icon" href="assets/img/touch-icon-iphone.png">
<link rel="apple-touch-icon" sizes="72x72" href="assets/img/touch-icon-ipad.png">
@@ -35,11 +39,17 @@
<?php else: ?>
<header>
<nav>
- <h1><?= $this->a('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->summary($this->e($title)) ?></h1>
+ <h1><?= $this->a('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->summary($this->e($title)) ?>
+ <?php if (! empty($description)): ?>
+ <span class="column-tooltip" title='<?= $this->e($this->markdown($description)) ?>'>
+ <i class="fa fa-info-circle"></i>
+ </span>
+ <?php endif ?>
+ </h1>
<ul>
<?php if (isset($board_selector) && ! empty($board_selector)): ?>
<li>
- <select id="board-selector" data-placeholder="<?= t('Display another project') ?>" data-board-url="<?= $this->u('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
+ <select id="board-selector" data-notfound="<?= t('No results match:') ?>" data-placeholder="<?= t('Display another project') ?>" data-board-url="<?= $this->u('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
<option value=""></option>
<?php foreach($board_selector as $board_id => $board_name): ?>
<option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option>
diff --git a/app/Template/project/edit.php b/app/Template/project/edit.php
index a1b945cd..c1f98315 100644
--- a/app/Template/project/edit.php
+++ b/app/Template/project/edit.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit project') ?></h2>
</div>
-<form method="post" action="<?= $this->u('project', 'update', array('project_id' => $values['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->u('project', 'update', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->formCsrf() ?>
<?= $this->formHidden('id', $values) ?>
@@ -9,7 +9,32 @@
<?= $this->formLabel(t('Name'), 'name') ?>
<?= $this->formText('name', $values, $errors, array('required', 'maxlength="50"')) ?>
+ <?= $this->formLabel(t('Description'), 'description') ?>
+
+ <div class="form-tabs">
+
+ <div class="write-area">
+ <?= $this->formTextarea('description', $values, $errors) ?>
+ </div>
+ <div class="preview-area">
+ <div class="markdown"></div>
+ </div>
+ <ul class="form-tabs-nav">
+ <li class="form-tab form-tab-selected">
+ <i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a>
+ </li>
+ <li class="form-tab">
+ <a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a>
+ </li>
+ </ul>
+ </div>
+ <div class="form-help"><a href="http://kanboard.net/documentation/syntax-guide" target="_blank" rel="noreferrer"><?= t('Write your text in Markdown') ?></a></div>
+
+ <?php if ($project['is_private'] == 1 && $this->userSession->isAdmin()): ?>
+ <?= $this->formCheckbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
+ <?php endif ?>
+
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/app/Template/project/index.php b/app/Template/project/index.php
index a36a9ce1..05a7d955 100644
--- a/app/Template/project/index.php
+++ b/app/Template/project/index.php
@@ -39,7 +39,13 @@
<?php if ($project['is_private']): ?>
<i class="fa fa-lock fa-fw"></i>
<?php endif ?>
+
<?= $this->a($this->e($project['name']), 'project', 'show', array('project_id' => $project['id'])) ?>
+ <?php if (! empty($project['description'])): ?>
+ <span class="column-tooltip" title='<?= $this->e($this->markdown($project['description'])) ?>'>
+ <i class="fa fa-info-circle"></i>
+ </span>
+ <?php endif ?>
</td>
<td class="dashboard-project-stats">
<?php foreach ($project['columns'] as $column): ?>
@@ -54,4 +60,4 @@
<?= $paginator ?>
<?php endif ?>
</section>
-</section> \ No newline at end of file
+</section>
diff --git a/app/Template/project/show.php b/app/Template/project/show.php
index b8bfd510..9c6cd1a8 100644
--- a/app/Template/project/show.php
+++ b/app/Template/project/show.php
@@ -50,7 +50,7 @@
<td>
<?= $this->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
- <span class="column-tooltip" title="<?= $this->markdown($column['description']) ?>">
+ <span class="column-tooltip" title='<?= $this->e($this->markdown($column['description'])) ?>'>
<i class="fa fa-info-circle"></i>
</span>
<?php endif ?>
@@ -60,3 +60,13 @@
</tr>
<?php endforeach ?>
</table>
+
+<?php if (! empty($project['description'])): ?>
+ <div class="page-header">
+ <h2><?= t('Description') ?></h2>
+ </div>
+
+ <article class="markdown">
+ <?= $this->markdown($project['description']) ?>
+ </article>
+<?php endif ?>
diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php
index f4809fde..4afc8ba9 100644
--- a/app/Template/project/sidebar.php
+++ b/app/Template/project/sidebar.php
@@ -33,7 +33,10 @@
<?= $this->a(t('Automatic actions'), 'action', 'index', array('project_id' => $project['id'])) ?>
</li>
<li>
- <?= $this->a(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id']), true) ?>
+ <?= $this->a(t('Duplicate'), 'project', 'duplicate', array('project_id' => $project['id'])) ?>
+ </li>
+ <li>
+ <?= $this->a(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?>
</li>
<li>
<?php if ($project['is_active']): ?>
diff --git a/app/Template/subtask/create.php b/app/Template/subtask/create.php
index be7fc311..8c5aae11 100644
--- a/app/Template/subtask/create.php
+++ b/app/Template/subtask/create.php
@@ -9,7 +9,7 @@
<?= $this->formHidden('task_id', $values) ?>
<?= $this->formLabel(t('Title'), 'title') ?>
- <?= $this->formText('title', $values, $errors, array('required', 'autofocus', 'maxlength="50"')) ?><br/>
+ <?= $this->formText('title', $values, $errors, array('required', 'autofocus', 'maxlength="255"')) ?><br/>
<?= $this->formLabel(t('Assignee'), 'user_id') ?>
<?= $this->formSelect('user_id', $users_list, $values, $errors) ?><br/>
diff --git a/app/Template/subtask/edit.php b/app/Template/subtask/edit.php
index f34d9532..3058ff44 100644
--- a/app/Template/subtask/edit.php
+++ b/app/Template/subtask/edit.php
@@ -10,7 +10,7 @@
<?= $this->formHidden('task_id', $values) ?>
<?= $this->formLabel(t('Title'), 'title') ?>
- <?= $this->formText('title', $values, $errors, array('required', 'autofocus', 'maxlength="50"')) ?><br/>
+ <?= $this->formText('title', $values, $errors, array('required', 'autofocus', 'maxlength="255"')) ?><br/>
<?= $this->formLabel(t('Assignee'), 'user_id') ?>
<?= $this->formSelect('user_id', $users_list, $values, $errors) ?><br/>
diff --git a/app/Template/subtask/show.php b/app/Template/subtask/show.php
index 1d55d1ee..c7ac652a 100644
--- a/app/Template/subtask/show.php
+++ b/app/Template/subtask/show.php
@@ -20,7 +20,7 @@
<?php if (! isset($not_editable)): ?>
<?= $this->toggleSubtaskStatus($subtask, 'task') ?>
<?php else: ?>
- <?= $this->render('subtask/icons', array('subtask' => $subtask)) . $this->e($subtask['status_name']) ?>
+ <?= $this->render('subtask/icons', array('subtask' => $subtask)) . $this->e($subtask['title']) ?>
<?php endif ?>
</td>
<td>
@@ -40,6 +40,16 @@
<?php if (! isset($not_editable)): ?>
<td>
<ul>
+ <?php if ($subtask['position'] > 1): ?>
+ <li>
+ <?= $this->a(t('Move Up'), 'subtask', 'movePosition', array('project_id' => $project['id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'direction' => 'up'), true) ?>
+ </li>
+ <?php endif ?>
+ <?php if ($subtask['position'] != 0 && $subtask['position'] != count($subtasks)): ?>
+ <li>
+ <?= $this->a(t('Move Down'), 'subtask', 'movePosition', array('project_id' => $project['id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'direction' => 'down'), true) ?>
+ </li>
+ <?php endif ?>
<li>
<?= $this->a(t('Edit'), 'subtask', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>
</li>
diff --git a/app/Template/task/new.php b/app/Template/task/new.php
index e64effde..4bfb8064 100644
--- a/app/Template/task/new.php
+++ b/app/Template/task/new.php
@@ -47,7 +47,6 @@
<div class="form-column">
<?= $this->formHidden('project_id', $values) ?>
- <?= $this->formHidden('swimlane_id', $values) ?>
<?= $this->formLabel(t('Assignee'), 'owner_id') ?>
<?= $this->formSelect('owner_id', $users_list, $values, $errors) ?><br/>
@@ -55,6 +54,9 @@
<?= $this->formLabel(t('Category'), 'category_id') ?>
<?= $this->formSelect('category_id', $categories_list, $values, $errors) ?><br/>
+ <?= $this->formLabel(t('Swimlane'), 'swimlane_id') ?>
+ <?= $this->formSelect('swimlane_id', $swimlanes_list, $values, $errors) ?><br/>
+
<?= $this->formLabel(t('Column'), 'column_id') ?>
<?= $this->formSelect('column_id', $columns_list, $values, $errors) ?><br/>
diff --git a/app/Template/task/show.php b/app/Template/task/show.php
index 1ff2ef43..50316c9f 100644
--- a/app/Template/task/show.php
+++ b/app/Template/task/show.php
@@ -1,8 +1,8 @@
<?= $this->render('task/details', array('task' => $task, 'project' => $project)) ?>
<?= $this->render('task/time', array('task' => $task, 'values' => $values, 'date_format' => $date_format, 'date_formats' => $date_formats)) ?>
<?= $this->render('task/show_description', array('task' => $task)) ?>
-<?= $this->render('tasklink/show', array('task' => $task, 'links' => $links)) ?>
-<?= $this->render('subtask/show', array('task' => $task, 'subtasks' => $subtasks)) ?>
+<?= $this->render('tasklink/show', array('task' => $task, 'links' => $links, 'link_label_list' => $link_label_list)) ?>
+<?= $this->render('subtask/show', array('task' => $task, 'subtasks' => $subtasks, 'project' => $project)) ?>
<?= $this->render('task/timesheet', array('task' => $task)) ?>
-<?= $this->render('file/show', array('task' => $task, 'files' => $files)) ?>
+<?= $this->render('file/show', array('task' => $task, 'files' => $files, 'images' => $images)) ?>
<?= $this->render('task/comments', array('task' => $task, 'comments' => $comments, 'project' => $project)) ?>
diff --git a/app/Template/task/time_tracking.php b/app/Template/task/time_tracking.php
index 1dea0f0b..55d33e5e 100644
--- a/app/Template/task/time_tracking.php
+++ b/app/Template/task/time_tracking.php
@@ -6,10 +6,11 @@
<?php else: ?>
<table class="table-fixed">
<tr>
- <th class="column-20"><?= $subtask_paginator->order(t('User'), 'username') ?></th>
- <th class="column-30"><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th>
- <th><?= $subtask_paginator->order(t('Start'), 'start') ?></th>
- <th><?= $subtask_paginator->order(t('End'), 'end') ?></th>
+ <th class="column-15"><?= $subtask_paginator->order(t('User'), 'username') ?></th>
+ <th><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th>
+ <th class="column-20"><?= $subtask_paginator->order(t('Start'), 'start') ?></th>
+ <th class="column-20"><?= $subtask_paginator->order(t('End'), 'end') ?></th>
+ <th class="column-10"><?= $subtask_paginator->order(t('Time spent'), 'time_spent') ?></th>
</tr>
<?php foreach ($subtask_paginator->getCollection() as $record): ?>
<tr>
@@ -17,6 +18,7 @@
<td><?= t($record['subtask_title']) ?></td>
<td><?= dt('%B %e, %Y at %k:%M %p', $record['start']) ?></td>
<td><?= dt('%B %e, %Y at %k:%M %p', $record['end']) ?></td>
+ <td><?= n($record['time_spent']).' '.t('hours') ?></td>
</tr>
<?php endforeach ?>
</table>
diff --git a/app/Template/tasklink/create.php b/app/Template/tasklink/create.php
index fb438cd8..acf9d6d1 100644
--- a/app/Template/tasklink/create.php
+++ b/app/Template/tasklink/create.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new link') ?></h2>
</div>
-<form action="<?= $this->u('tasklink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->u('tasklink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => isset($ajax))) ?>" method="post" autocomplete="off">
<?= $this->formCsrf() ?>
<?= $this->formHidden('task_id', $values) ?>
@@ -22,6 +22,10 @@
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
<?= t('or') ?>
- <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?php if (isset($ajax)): ?>
+ <?= $this->a(t('cancel'), 'board', 'show', array('project_id' => $task['project_id']), false, 'close-popover') ?>
+ <?php else: ?>
+ <?= $this->a(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?php endif ?>
</div>
</form> \ No newline at end of file
diff --git a/app/Template/tasklink/show.php b/app/Template/tasklink/show.php
index a36f89dd..75e3c376 100644
--- a/app/Template/tasklink/show.php
+++ b/app/Template/tasklink/show.php
@@ -41,4 +41,24 @@
</tr>
<?php endforeach ?>
</table>
-<?php endif ?> \ No newline at end of file
+
+<?php if (! isset($not_editable) && isset($link_label_list)): ?>
+ <form action="<?= $this->u('tasklink', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+
+ <?= $this->formCsrf() ?>
+ <?= $this->formHidden('task_id', array('task_id' => $task['id'])) ?>
+ <?= $this->formHidden('opposite_task_id', array()) ?>
+
+ <?= $this->formSelect('link_id', $link_label_list, array(), array()) ?>
+
+ <?= $this->formText(
+ 'title',
+ array(),
+ array(),
+ array('required', 'data-dst-field="opposite_task_id"', 'data-search-url="'.$this->u('app', 'autocomplete', array('exclude_task_id' => $task['id'])).'"'),
+ 'task-autocomplete') ?>
+
+ <input type="submit" value="<?= t('Add') ?>" class="btn btn-blue"/>
+ </form>
+<?php endif ?>
+<?php endif ?>
diff --git a/app/Template/timetable/index.php b/app/Template/timetable/index.php
new file mode 100644
index 00000000..27cbe39c
--- /dev/null
+++ b/app/Template/timetable/index.php
@@ -0,0 +1,44 @@
+<div class="page-header">
+ <h2><?= t('Timetable') ?></h2>
+ <ul>
+ <li><?= $this->a(t('Day timetable'), 'timetableday', 'index', array('user_id' => $user['id'])) ?></li>
+ <li><?= $this->a(t('Week timetable'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?></li>
+ <li><?= $this->a(t('Time off timetable'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?></li>
+ <li><?= $this->a(t('Overtime timetable'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?></li>
+ </ul>
+</div>
+
+<form method="get" action="?" autocomplete="off" class="form-inline">
+
+ <?= $this->formHidden('controller', $values) ?>
+ <?= $this->formHidden('action', $values) ?>
+ <?= $this->formHidden('user_id', $values) ?>
+
+ <?= $this->formLabel(t('From'), 'from') ?>
+ <?= $this->formText('from', $values, array(), array(), 'form-date') ?>
+
+ <?= $this->formLabel(t('To'), 'to') ?>
+ <?= $this->formText('to', $values, array(), array(), 'form-date') ?>
+
+ <input type="submit" value="<?= t('Execute') ?>" class="btn btn-blue"/>
+</form>
+
+<?php if (! empty($timetable)): ?>
+<hr/>
+<h3><?= t('Work timetable') ?></h3>
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= t('Day') ?></th>
+ <th><?= t('Start') ?></th>
+ <th><?= t('End') ?></th>
+ </tr>
+ <?php foreach ($timetable as $slot): ?>
+ <tr>
+ <td><?= dt('%B %e, %Y', $slot[0]->getTimestamp()) ?></td>
+ <td><?= dt('%k:%M %p', $slot[0]->getTimestamp()) ?></td>
+ <td><?= dt('%k:%M %p', $slot[1]->getTimestamp()) ?></td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<?php endif ?> \ No newline at end of file
diff --git a/app/Template/timetable_day/index.php b/app/Template/timetable_day/index.php
new file mode 100644
index 00000000..50aca602
--- /dev/null
+++ b/app/Template/timetable_day/index.php
@@ -0,0 +1,45 @@
+<div class="page-header">
+ <h2><?= t('Day timetable') ?></h2>
+</div>
+
+<?php if (! empty($timetable)): ?>
+
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= t('Start time') ?></th>
+ <th><?= t('End time') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($timetable as $slot): ?>
+ <tr>
+ <td><?= $slot['start'] ?></td>
+ <td><?= $slot['end'] ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'timetableday', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<h3><?= t('Add new time slot') ?></h3>
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('timetableday', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->formHidden('user_id', $values) ?>
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formLabel(t('Start time'), 'start') ?>
+ <?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('End time'), 'end') ?>
+ <?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form>
+
+<p class="alert alert-info">
+ <?= t('This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.') ?>
+</p> \ No newline at end of file
diff --git a/app/Template/timetable_day/remove.php b/app/Template/timetable_day/remove.php
new file mode 100644
index 00000000..b3ee8775
--- /dev/null
+++ b/app/Template/timetable_day/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove time slot') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'timetableday', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'timetableday', 'index', array('user_id' => $user['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/timetable_extra/index.php b/app/Template/timetable_extra/index.php
new file mode 100644
index 00000000..a0a55bec
--- /dev/null
+++ b/app/Template/timetable_extra/index.php
@@ -0,0 +1,56 @@
+<div class="page-header">
+ <h2><?= t('Overtime timetable') ?></h2>
+</div>
+
+<?php if (! $paginator->isEmpty()): ?>
+
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= $paginator->order(t('Day'), 'Day') ?></th>
+ <th><?= $paginator->order(t('All day'), 'all_day') ?></th>
+ <th><?= $paginator->order(t('Start time'), 'start') ?></th>
+ <th><?= $paginator->order(t('End time'), 'end') ?></th>
+ <th class="column-40"><?= t('Comment') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($paginator->getCollection() as $slot): ?>
+ <tr>
+ <td><?= $slot['date'] ?></td>
+ <td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
+ <td><?= $slot['start'] ?></td>
+ <td><?= $slot['end'] ?></td>
+ <td><?= $this->e($slot['comment']) ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'timetableextra', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<?= $paginator ?>
+
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('timetableextra', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->formHidden('user_id', $values) ?>
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formLabel(t('Day'), 'date') ?>
+ <?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
+
+ <?= $this->formCheckbox('all_day', t('All day'), 1) ?>
+
+ <?= $this->formLabel(t('Start time'), 'start') ?>
+ <?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('End time'), 'end') ?>
+ <?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('Comment'), 'comment') ?>
+ <?= $this->formText('comment', $values, $errors) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form> \ No newline at end of file
diff --git a/app/Template/timetable_extra/remove.php b/app/Template/timetable_extra/remove.php
new file mode 100644
index 00000000..d8dc5b3b
--- /dev/null
+++ b/app/Template/timetable_extra/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove time slot') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'timetableextra', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/timetable_off/index.php b/app/Template/timetable_off/index.php
new file mode 100644
index 00000000..f35d331e
--- /dev/null
+++ b/app/Template/timetable_off/index.php
@@ -0,0 +1,56 @@
+<div class="page-header">
+ <h2><?= t('Time off timetable') ?></h2>
+</div>
+
+<?php if (! $paginator->isEmpty()): ?>
+
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= $paginator->order(t('Day'), 'Day') ?></th>
+ <th><?= $paginator->order(t('All day'), 'all_day') ?></th>
+ <th><?= $paginator->order(t('Start time'), 'start') ?></th>
+ <th><?= $paginator->order(t('End time'), 'end') ?></th>
+ <th class="column-40"><?= t('Comment') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($paginator->getCollection() as $slot): ?>
+ <tr>
+ <td><?= $slot['date'] ?></td>
+ <td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
+ <td><?= $slot['start'] ?></td>
+ <td><?= $slot['end'] ?></td>
+ <td><?= $this->e($slot['comment']) ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'timetableoff', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<?= $paginator ?>
+
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('timetableoff', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->formHidden('user_id', $values) ?>
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formLabel(t('Day'), 'date') ?>
+ <?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
+
+ <?= $this->formCheckbox('all_day', t('All day'), 1) ?>
+
+ <?= $this->formLabel(t('Start time'), 'start') ?>
+ <?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('End time'), 'end') ?>
+ <?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('Comment'), 'comment') ?>
+ <?= $this->formText('comment', $values, $errors) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form> \ No newline at end of file
diff --git a/app/Template/timetable_off/remove.php b/app/Template/timetable_off/remove.php
new file mode 100644
index 00000000..64863781
--- /dev/null
+++ b/app/Template/timetable_off/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove time slot') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'timetableoff', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/timetable_week/index.php b/app/Template/timetable_week/index.php
new file mode 100644
index 00000000..8fb51909
--- /dev/null
+++ b/app/Template/timetable_week/index.php
@@ -0,0 +1,46 @@
+<div class="page-header">
+ <h2><?= t('Week timetable') ?></h2>
+</div>
+
+<?php if (! empty($timetable)): ?>
+
+<table class="table-fixed table-stripped">
+ <tr>
+ <th><?= t('Day') ?></th>
+ <th><?= t('Start time') ?></th>
+ <th><?= t('End time') ?></th>
+ <th><?= t('Action') ?></th>
+ </tr>
+ <?php foreach ($timetable as $slot): ?>
+ <tr>
+ <td><?= $this->getWeekDay($slot['day']) ?></td>
+ <td><?= $slot['start'] ?></td>
+ <td><?= $slot['end'] ?></td>
+ <td>
+ <?= $this->a(t('Remove'), 'timetableweek', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+</table>
+
+<h3><?= t('Add new time slot') ?></h3>
+<?php endif ?>
+
+<form method="post" action="<?= $this->u('timetableweek', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->formHidden('user_id', $values) ?>
+ <?= $this->formCsrf() ?>
+
+ <?= $this->formLabel(t('Day'), 'day') ?>
+ <?= $this->formSelect('day', $this->getWeekDays(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('Start time'), 'start') ?>
+ <?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
+
+ <?= $this->formLabel(t('End time'), 'end') ?>
+ <?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ </div>
+</form> \ No newline at end of file
diff --git a/app/Template/timetable_week/remove.php b/app/Template/timetable_week/remove.php
new file mode 100644
index 00000000..f8eb2bbe
--- /dev/null
+++ b/app/Template/timetable_week/remove.php
@@ -0,0 +1,13 @@
+<div class="page-header">
+ <h2><?= t('Remove time slot') ?></h2>
+</div>
+
+<div class="confirm">
+ <p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
+
+ <div class="form-actions">
+ <?= $this->a(t('Yes'), 'timetableweek', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
+ <?= t('or') ?>
+ <?= $this->a(t('cancel'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php
index e41851a9..1af10c1d 100644
--- a/app/Template/user/sidebar.php
+++ b/app/Template/user/sidebar.php
@@ -32,7 +32,7 @@
<?= $this->a(t('Time tracking'), 'user', 'timesheet', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
-
+
<?php if ($this->userSession->isAdmin()): ?>
<li>
<?= $this->a(t('User dashboard'), 'app', 'dashboard', array('user_id' => $user['id'])) ?>
@@ -40,6 +40,12 @@
<li>
<?= $this->a(t('User calendar'), 'user', 'calendar', array('user_id' => $user['id'])) ?>
</li>
+ <li>
+ <?= $this->a(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
+ </li>
+ <li>
+ <?= $this->a(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?>
+ </li>
<?php endif ?>
<?php if ($this->userSession->isAdmin() && ! $this->userSession->isCurrentUser($user['id'])): ?>
diff --git a/app/Template/user/timesheet.php b/app/Template/user/timesheet.php
index 4f052006..3ae84df0 100644
--- a/app/Template/user/timesheet.php
+++ b/app/Template/user/timesheet.php
@@ -8,10 +8,11 @@
<?php else: ?>
<table class="table-fixed">
<tr>
- <th class="column-20"><?= $subtask_paginator->order(t('Task'), 'task_title') ?></th>
- <th class="column-20"><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th>
- <th><?= $subtask_paginator->order(t('Start'), 'start') ?></th>
- <th><?= $subtask_paginator->order(t('End'), 'end') ?></th>
+ <th class="column-25"><?= $subtask_paginator->order(t('Task'), 'task_title') ?></th>
+ <th class="column-25"><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th>
+ <th class="column-20"><?= $subtask_paginator->order(t('Start'), 'start') ?></th>
+ <th class="column-20"><?= $subtask_paginator->order(t('End'), 'end') ?></th>
+ <th class="column-10"><?= $subtask_paginator->order(t('Time spent'), 'time_spent') ?></th>
</tr>
<?php foreach ($subtask_paginator->getCollection() as $record): ?>
<tr>
@@ -19,6 +20,7 @@
<td><?= $this->a($this->e($record['subtask_title']), 'task', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td>
<td><?= dt('%B %e, %Y at %k:%M %p', $record['start']) ?></td>
<td><?= dt('%B %e, %Y at %k:%M %p', $record['end']) ?></td>
+ <td><?= n($record['time_spent']).' '.t('hours') ?></td>
</tr>
<?php endforeach ?>
</table>
diff --git a/app/constants.php b/app/constants.php
index 39ab5470..82d26f2c 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -21,6 +21,7 @@ defined('DB_USERNAME') or define('DB_USERNAME', 'root');
defined('DB_PASSWORD') or define('DB_PASSWORD', '');
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
defined('DB_NAME') or define('DB_NAME', 'kanboard');
+defined('DB_PORT') or define('DB_PORT', null);
// LDAP configuration
defined('LDAP_AUTH') or define('LDAP_AUTH', false);
@@ -67,6 +68,9 @@ defined('MAIL_SENDMAIL_COMMAND') or define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/s
// Enable or disable "Strict-Transport-Security" HTTP header
defined('ENABLE_HSTS') or define('ENABLE_HSTS', true);
+// Enable or disable "X-Frame-Options: DENY" HTTP header
+defined('ENABLE_XFRAME') or define('ENABLE_XFRAME', true);
+
// Default files directory
defined('FILES_DIR') or define('FILES_DIR', 'data/files/');