summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Api/Me.php2
-rw-r--r--app/Api/Project.php4
-rw-r--r--app/Api/Subtask.php4
-rw-r--r--app/Api/User.php4
-rw-r--r--app/Controller/PasswordReset.php2
-rw-r--r--app/Controller/Project.php4
-rw-r--r--app/Controller/Subtask.php4
-rw-r--r--app/Controller/Swimlane.php6
-rw-r--r--app/Controller/Tasklink.php4
-rw-r--r--app/Controller/User.php8
-rw-r--r--app/Core/Base.php8
-rw-r--r--app/Core/Session/SessionStorage.php2
-rw-r--r--app/Locale/my_MY/translations.php1100
-rw-r--r--app/Locale/pt_PT/translations.php68
-rw-r--r--app/Model/Config.php1
-rw-r--r--app/Model/Project.php69
-rw-r--r--app/Model/Subtask.php90
-rw-r--r--app/Model/Swimlane.php84
-rw-r--r--app/Model/TaskLink.php57
-rw-r--r--app/Model/User.php131
-rw-r--r--app/ServiceProvider/ClassProvider.php7
-rw-r--r--app/Template/subtask/show.php6
-rw-r--r--app/Validator/Base.php18
-rw-r--r--app/Validator/PasswordResetValidator.php8
-rw-r--r--app/Validator/ProjectValidator.php83
-rw-r--r--app/Validator/SubtaskValidator.php101
-rw-r--r--app/Validator/SwimlaneValidator.php96
-rw-r--r--app/Validator/TaskLinkValidator.php71
-rw-r--r--app/Validator/TaskValidator.php (renamed from app/Model/TaskValidator.php)6
-rw-r--r--app/Validator/UserValidator.php128
30 files changed, 1677 insertions, 499 deletions
diff --git a/app/Api/Me.php b/app/Api/Me.php
index 37851731..df8ec070 100644
--- a/app/Api/Me.php
+++ b/app/Api/Me.php
@@ -44,7 +44,7 @@ class Me extends Base
'is_private' => 1,
);
- list($valid, ) = $this->project->validateCreation($values);
+ list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->project->create($values, $this->userSession->getId(), true) : false;
}
diff --git a/app/Api/Project.php b/app/Api/Project.php
index f934432d..8e311f7f 100644
--- a/app/Api/Project.php
+++ b/app/Api/Project.php
@@ -69,7 +69,7 @@ class Project extends Base
'description' => $description
);
- list($valid, ) = $this->project->validateCreation($values);
+ list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->project->create($values) : false;
}
@@ -81,7 +81,7 @@ class Project extends Base
'description' => $description
);
- list($valid, ) = $this->project->validateModification($values);
+ list($valid, ) = $this->projectValidator->validateModification($values);
return $valid && $this->project->update($values);
}
}
diff --git a/app/Api/Subtask.php b/app/Api/Subtask.php
index 7baee3d3..782fdb02 100644
--- a/app/Api/Subtask.php
+++ b/app/Api/Subtask.php
@@ -36,7 +36,7 @@ class Subtask extends \Kanboard\Core\Base
'status' => $status,
);
- list($valid, ) = $this->subtask->validateCreation($values);
+ list($valid, ) = $this->subtaskValidator->validateCreation($values);
return $valid ? $this->subtask->create($values) : false;
}
@@ -58,7 +58,7 @@ class Subtask extends \Kanboard\Core\Base
}
}
- list($valid, ) = $this->subtask->validateApiModification($values);
+ list($valid, ) = $this->subtaskValidator->validateApiModification($values);
return $valid && $this->subtask->update($values);
}
}
diff --git a/app/Api/User.php b/app/Api/User.php
index 06e305f2..63c222fe 100644
--- a/app/Api/User.php
+++ b/app/Api/User.php
@@ -42,7 +42,7 @@ class User extends \Kanboard\Core\Base
'role' => $role,
);
- list($valid, ) = $this->user->validateCreation($values);
+ list($valid, ) = $this->userValidator->validateCreation($values);
return $valid ? $this->user->create($values) : false;
}
@@ -94,7 +94,7 @@ class User extends \Kanboard\Core\Base
}
}
- list($valid, ) = $this->user->validateApiModification($values);
+ list($valid, ) = $this->userValidator->validateApiModification($values);
return $valid && $this->user->update($values);
}
}
diff --git a/app/Controller/PasswordReset.php b/app/Controller/PasswordReset.php
index ebc1f77a..23567c9c 100644
--- a/app/Controller/PasswordReset.php
+++ b/app/Controller/PasswordReset.php
@@ -67,7 +67,7 @@ class PasswordReset extends Base
/**
* Set the new password
*/
- public function update(array $values = array(), array $errors = array())
+ public function update()
{
$this->checkActivation();
diff --git a/app/Controller/Project.php b/app/Controller/Project.php
index 5e75db4e..27c827d1 100644
--- a/app/Controller/Project.php
+++ b/app/Controller/Project.php
@@ -169,7 +169,7 @@ class Project extends Base
}
}
- list($valid, $errors) = $this->project->validateModification($values);
+ list($valid, $errors) = $this->projectValidator->validateModification($values);
if ($valid) {
if ($this->project->update($values)) {
@@ -329,7 +329,7 @@ class Project extends Base
public function save()
{
$values = $this->request->getValues();
- list($valid, $errors) = $this->project->validateCreation($values);
+ list($valid, $errors) = $this->projectValidator->validateCreation($values);
if ($valid) {
$project_id = $this->project->create($values, $this->userSession->getId(), true);
diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php
index c93b637d..caaaa85e 100644
--- a/app/Controller/Subtask.php
+++ b/app/Controller/Subtask.php
@@ -63,7 +63,7 @@ class Subtask extends Base
$task = $this->getTask();
$values = $this->request->getValues();
- list($valid, $errors) = $this->subtask->validateCreation($values);
+ list($valid, $errors) = $this->subtaskValidator->validateCreation($values);
if ($valid) {
if ($this->subtask->create($values)) {
@@ -113,7 +113,7 @@ class Subtask extends Base
$this->getSubtask();
$values = $this->request->getValues();
- list($valid, $errors) = $this->subtask->validateModification($values);
+ list($valid, $errors) = $this->subtaskValidator->validateModification($values);
if ($valid) {
if ($this->subtask->update($values)) {
diff --git a/app/Controller/Swimlane.php b/app/Controller/Swimlane.php
index 5229621c..66410888 100644
--- a/app/Controller/Swimlane.php
+++ b/app/Controller/Swimlane.php
@@ -60,7 +60,7 @@ class Swimlane extends Base
{
$project = $this->getProject();
$values = $this->request->getValues();
- list($valid, $errors) = $this->swimlane->validateCreation($values);
+ list($valid, $errors) = $this->swimlaneValidator->validateCreation($values);
if ($valid) {
if ($this->swimlane->create($values)) {
@@ -84,7 +84,7 @@ class Swimlane extends Base
$project = $this->getProject();
$values = $this->request->getValues() + array('show_default_swimlane' => 0);
- list($valid, ) = $this->swimlane->validateDefaultModification($values);
+ list($valid, ) = $this->swimlaneValidator->validateDefaultModification($values);
if ($valid) {
if ($this->swimlane->updateDefault($values)) {
@@ -126,7 +126,7 @@ class Swimlane extends Base
$project = $this->getProject();
$values = $this->request->getValues();
- list($valid, $errors) = $this->swimlane->validateModification($values);
+ list($valid, $errors) = $this->swimlaneValidator->validateModification($values);
if ($valid) {
if ($this->swimlane->update($values)) {
diff --git a/app/Controller/Tasklink.php b/app/Controller/Tasklink.php
index 068bf16d..a81d3ee5 100644
--- a/app/Controller/Tasklink.php
+++ b/app/Controller/Tasklink.php
@@ -69,7 +69,7 @@ class Tasklink extends Base
$values = $this->request->getValues();
$ajax = $this->request->isAjax() || $this->request->getIntegerParam('ajax');
- list($valid, $errors) = $this->taskLink->validateCreation($values);
+ list($valid, $errors) = $this->taskLinkValidator->validateCreation($values);
if ($valid) {
if ($this->taskLink->create($values['task_id'], $values['opposite_task_id'], $values['link_id'])) {
@@ -125,7 +125,7 @@ class Tasklink extends Base
$task = $this->getTask();
$values = $this->request->getValues();
- list($valid, $errors) = $this->taskLink->validateModification($values);
+ list($valid, $errors) = $this->taskLinkValidator->validateModification($values);
if ($valid) {
if ($this->taskLink->update($values['id'], $values['task_id'], $values['opposite_task_id'], $values['link_id'])) {
diff --git a/app/Controller/User.php b/app/Controller/User.php
index 2a811219..97e01553 100644
--- a/app/Controller/User.php
+++ b/app/Controller/User.php
@@ -108,7 +108,7 @@ class User extends Base
public function save()
{
$values = $this->request->getValues();
- list($valid, $errors) = $this->user->validateCreation($values);
+ list($valid, $errors) = $this->userValidator->validateCreation($values);
if ($valid) {
$project_id = empty($values['project_id']) ? 0 : $values['project_id'];
@@ -329,7 +329,7 @@ class User extends Base
if ($this->request->isPost()) {
$values = $this->request->getValues();
- list($valid, $errors) = $this->user->validatePasswordModification($values);
+ list($valid, $errors) = $this->userValidator->validatePasswordModification($values);
if ($valid) {
if ($this->user->update($values)) {
@@ -371,7 +371,7 @@ class User extends Base
}
}
- list($valid, $errors) = $this->user->validateModification($values);
+ list($valid, $errors) = $this->userValidator->validateModification($values);
if ($valid) {
if ($this->user->update($values)) {
@@ -409,7 +409,7 @@ class User extends Base
if ($this->request->isPost()) {
$values = $this->request->getValues() + array('disable_login_form' => 0, 'is_ldap_user' => 0);
- list($valid, $errors) = $this->user->validateModification($values);
+ list($valid, $errors) = $this->userValidator->validateModification($values);
if ($valid) {
if ($this->user->update($values)) {
diff --git a/app/Core/Base.php b/app/Core/Base.php
index f32c1442..723831e3 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -79,6 +79,7 @@ use Pimple\Container;
* @property \Kanboard\Model\ProjectMetadata $projectMetadata
* @property \Kanboard\Model\ProjectPermission $projectPermission
* @property \Kanboard\Model\ProjectUserRole $projectUserRole
+ * @property \Kanboard\Model\projectUserRoleFilter $projectUserRoleFilter
* @property \Kanboard\Model\ProjectGroupRole $projectGroupRole
* @property \Kanboard\Model\ProjectNotification $projectNotification
* @property \Kanboard\Model\ProjectNotificationType $projectNotificationType
@@ -100,7 +101,6 @@ use Pimple\Container;
* @property \Kanboard\Model\TaskPermission $taskPermission
* @property \Kanboard\Model\TaskPosition $taskPosition
* @property \Kanboard\Model\TaskStatus $taskStatus
- * @property \Kanboard\Model\TaskValidator $taskValidator
* @property \Kanboard\Model\TaskMetadata $taskMetadata
* @property \Kanboard\Model\Transition $transition
* @property \Kanboard\Model\User $user
@@ -114,6 +114,12 @@ use Pimple\Container;
* @property \Kanboard\Model\UserMetadata $userMetadata
* @property \Kanboard\Model\Webhook $webhook
* @property \Kanboard\Validator\PasswordResetValidator $passwordResetValidator
+ * @property \Kanboard\Validator\ProjectValidator $projectValidator
+ * @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
+ * @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
+ * @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
+ * @property \Kanboard\Validator\TaskValidator $taskValidator
+ * @property \Kanboard\Validator\UserValidator $userValidator
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
diff --git a/app/Core/Session/SessionStorage.php b/app/Core/Session/SessionStorage.php
index f55a7ee3..5ee1d811 100644
--- a/app/Core/Session/SessionStorage.php
+++ b/app/Core/Session/SessionStorage.php
@@ -20,6 +20,8 @@ namespace Kanboard\Core\Session;
* @property bool $hasSubtaskInProgress
* @property bool $hasRememberMe
* @property bool $boardCollapsed
+ * @property bool $twoFactorBeforeCodeCalled
+ * @property string $twoFactorSecret
*/
class SessionStorage
{
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
new file mode 100644
index 00000000..9b0f6c3d
--- /dev/null
+++ b/app/Locale/my_MY/translations.php
@@ -0,0 +1,1100 @@
+<?php
+return array(
+ 'number.decimals_separator' => '.',
+ 'number.thousands_separator' => ',',
+ 'None' => 'Tiada',
+ 'edit' => 'sunting',
+ 'Edit' => 'Sunting',
+ 'remove' => 'hapus',
+ 'Remove' => 'Hapus',
+ 'Update' => 'Kemaskini',
+ 'Yes' => 'Ya',
+ 'No' => 'Tidak',
+ 'cancel' => 'batal',
+ 'or' => 'atau',
+ 'Yellow' => 'Kuning',
+ 'Blue' => 'Biru',
+ 'Green' => 'Hijau',
+ 'Purple' => 'Ungu',
+ 'Red' => 'Merah',
+ 'Orange' => 'Oren',
+ 'Grey' => 'Kelabu',
+ 'Brown' => 'Coklat',
+ 'Deep Orange' => 'Oren Gelap',
+ 'Dark Grey' => 'Kelabu Malap',
+ 'Pink' => 'Merah Jambu',
+ 'Teal' => 'Teal',
+ 'Cyan' => 'Sian',
+ 'Lime' => 'Lime',
+ 'Light Green' => 'Hijau Muda',
+ 'Amber' => 'Amber',
+ 'Save' => 'Simpan',
+ 'Login' => 'Masuk',
+ 'Official website:' => 'Laman rasmi :',
+ 'Unassigned' => 'Belum ditugaskan',
+ 'View this task' => 'Lihat tugas ini',
+ 'Remove user' => 'Hapus pengguna',
+ 'Do you really want to remove this user: "%s"?' => 'Anda yakin mahu menghapus pengguna ini : « %s » ?',
+ 'New user' => 'Pengguna baru',
+ 'All users' => 'Semua pengguna',
+ 'Username' => 'Nama pengguna',
+ 'Password' => 'Kata laluan',
+ 'Administrator' => 'Pentadbir',
+ 'Sign in' => 'Masuk',
+ 'Users' => 'Para Pengguna',
+ 'No user' => 'Tiada pengguna',
+ 'Forbidden' => 'Larangan',
+ 'Access Forbidden' => 'Akses Dilarang',
+ 'Edit user' => 'Ubah Pengguna',
+ 'Logout' => 'Keluar',
+ 'Bad username or password' => 'Nama pengguna atau kata laluan tidak sepadan',
+ 'Edit project' => 'Ubah projek',
+ 'Name' => 'Nama',
+ 'Projects' => 'Projek',
+ 'No project' => 'Tiada projek',
+ 'Project' => 'Projek',
+ 'Status' => 'Status',
+ 'Tasks' => 'Tugasan',
+ 'Board' => 'Papan',
+ 'Actions' => 'Tindakan',
+ 'Inactive' => 'Tidak Aktif',
+ 'Active' => 'Aktif',
+ 'Add this column' => 'Tambahkan kolom ini',
+ '%d tasks on the board' => '%d tugasan di papan',
+ '%d tasks in total' => 'Sejumlah %d tugasan',
+ 'Unable to update this board.' => 'Tidak berupaya mengemaskini papan ini',
+ 'Edit board' => 'ubah papan',
+ 'Disable' => 'Nyah-Upaya',
+ 'Enable' => 'Aktifkan',
+ 'New project' => 'Projek Baru',
+ 'Do you really want to remove this project: "%s"?' => 'Anda yakin mahu menghapus projek ini : « %s » ?',
+ 'Remove project' => 'Hapus projek',
+ 'Edit the board for "%s"' => 'Ubah papan untuk « %s »',
+ 'All projects' => 'Semua projek',
+ 'Change columns' => 'Ubah kolom',
+ 'Add a new column' => 'Tambah kolom baru',
+ 'Title' => 'Judul',
+ 'Nobody assigned' => 'Tidak ada yang ditugaskan',
+ 'Assigned to %s' => 'Ditugaskan ke %s',
+ 'Remove a column' => 'Hapus kolom',
+ 'Remove a column from a board' => 'Hapus kolom dari papan',
+ 'Unable to remove this column.' => 'Tidak dapat menghapus kolom ini.',
+ 'Do you really want to remove this column: "%s"?' => 'Apakah anda yakin akan menghapus kolom ini : « %s » ?',
+ 'This action will REMOVE ALL TASKS associated to this column!' => 'tindakan ini akan MENGHAPUS SEMUA TUGAS yang terkait dengan kolom ini!',
+ 'Settings' => 'Penetapan',
+ 'Application settings' => 'Penetapan aplikasi',
+ 'Language' => 'Bahasa',
+ 'Webhook token:' => 'Token webhook :',
+ 'API token:' => 'Token API :',
+ 'Database size:' => 'Saiz pengkalan data:',
+ 'Download the database' => 'Muat turun pengkalan data',
+ 'Optimize the database' => 'Optimakan pengkalan data',
+ '(VACUUM command)' => '(perintah VACUUM)',
+ '(Gzip compressed Sqlite file)' => '(File Sqlite yang termampat Gzip)',
+ 'Close a task' => 'Tutup tugas',
+ 'Edit a task' => 'Sunting tugas',
+ 'Column' => 'Kolom',
+ 'Color' => 'Warna',
+ 'Assignee' => 'Orang yang ditugaskan',
+ 'Create another task' => 'Buat tugas lain',
+ 'New task' => 'Tugasan baru',
+ 'Open a task' => 'Buka tugas',
+ 'Do you really want to open this task: "%s"?' => 'Anda yakin untuk buka tugas ini : « %s » ?',
+ 'Back to the board' => 'Kembali ke papan',
+ 'Created on %B %e, %Y at %k:%M %p' => 'Dicipta pada tanggal %d/%m/%Y à %H:%M',
+ 'There is nobody assigned' => 'Tidak ada orang yand ditugaskan',
+ 'Column on the board:' => 'Kolom di dalam papan : ',
+ 'Status is open' => 'Status terbuka',
+ 'Status is closed' => 'Status ditutup',
+ 'Close this task' => 'Tutup tugas ini',
+ 'Open this task' => 'Buka tugas ini',
+ 'There is no description.' => 'Tidak ada keterangan.',
+ 'Add a new task' => 'Tambah tugas baru',
+ 'The username is required' => 'Nama pengguna adalah wajib',
+ 'The maximum length is %d characters' => 'Panjang maksimum adalah %d karakter',
+ 'The minimum length is %d characters' => 'Panjang minimum adalah %d karakter',
+ 'The password is required' => 'Kata laluan adalah wajib',
+ 'This value must be an integer' => 'Nilai ini harus integer',
+ 'The username must be unique' => 'Nama pengguna semestinya unik',
+ 'The user id is required' => 'Id Pengguna adalah wajib',
+ 'Passwords don\'t match' => 'Kata laluan tidak sepadan',
+ 'The confirmation is required' => 'Pengesahan diperlukan',
+ 'The project is required' => 'Projek diperlukan',
+ 'The id is required' => 'Id diperlukan',
+ 'The project id is required' => 'Id projek diperlukan',
+ 'The project name is required' => 'Nama projek diperlukan',
+ 'The title is required' => 'Judul diperlukan',
+ 'Settings saved successfully.' => 'Penetapan berjaya disimpan.',
+ 'Unable to save your settings.' => 'Tidak dapat menyimpan penetapan anda.',
+ 'Database optimization done.' => 'Optimasi pengkalan data selesai.',
+ 'Your project have been created successfully.' => 'Projek anda berhasil dibuat.',
+ 'Unable to create your project.' => 'Tidak dapat membuat projek anda.',
+ 'Project updated successfully.' => 'projek berhasil diperbaharui.',
+ 'Unable to update this project.' => 'Tidak dapat memperbaharui projek ini.',
+ 'Unable to remove this project.' => 'Tidak dapat menghapus projek ini.',
+ 'Project removed successfully.' => 'projek berhasil dihapus.',
+ 'Project activated successfully.' => 'projek berhasil diaktivasi.',
+ 'Unable to activate this project.' => 'Tidak dapat mengaktifkan projek ini.',
+ 'Project disabled successfully.' => 'projek berhasil dinonaktifkan.',
+ 'Unable to disable this project.' => 'Tidak dapat menonaktifkan projek ini.',
+ 'Unable to open this task.' => 'Tidak dapat membuka tugas ini.',
+ 'Task opened successfully.' => 'Tugas berhasil dibuka.',
+ 'Unable to close this task.' => 'Tidak dapat menutup tugas ini.',
+ 'Task closed successfully.' => 'Tugas berhasil ditutup.',
+ 'Unable to update your task.' => 'Tidak dapat memperbaharui tugas ini.',
+ 'Task updated successfully.' => 'Tugas berhasil diperbaharui.',
+ 'Unable to create your task.' => 'Tidak dapat membuat tugas anda.',
+ 'Task created successfully.' => 'Tugas berhasil dibuat.',
+ 'User created successfully.' => 'Pengguna berhasil dibuat.',
+ 'Unable to create your user.' => 'Tidak dapat membuat pengguna anda.',
+ 'User updated successfully.' => 'Pengguna berhasil diperbaharui.',
+ 'Unable to update your user.' => 'Tidak dapat memperbaharui pengguna anda.',
+ 'User removed successfully.' => 'pengguna berhasil dihapus.',
+ 'Unable to remove this user.' => 'Tidak dapat menghapus pengguna ini.',
+ 'Board updated successfully.' => 'Papan berhasil diperbaharui.',
+ 'Ready' => 'Siap',
+ 'Backlog' => 'Tertunda',
+ 'Work in progress' => 'Sedang dalam pengerjaan',
+ 'Done' => 'Selesai',
+ 'Application version:' => 'Versi aplikasi :',
+ 'Completed on %B %e, %Y at %k:%M %p' => 'Diselesaikan pada tanggal %d/%m/%Y à %H:%M',
+ '%B %e, %Y at %k:%M %p' => '%d/%m/%Y à %H:%M',
+ 'Date created' => 'Tanggal dibuat',
+ 'Date completed' => 'Tanggal diselesaikan',
+ 'Id' => 'Id.',
+ '%d closed tasks' => '%d tugas yang ditutup',
+ 'No task for this project' => 'Tidak ada tugas dalam projek ini',
+ 'Public link' => 'Pautan publik',
+ 'Change assignee' => 'Mengubah orang yand ditugaskan',
+ 'Change assignee for the task "%s"' => 'Mengubah orang yang ditugaskan untuk tugas « %s »',
+ 'Timezone' => 'Zona waktu',
+ 'Sorry, I didn\'t find this information in my database!' => 'Maaf, saya tidak menemukan informasi ini dalam basis data saya !',
+ 'Page not found' => 'Halaman tidak ditemukan',
+ 'Complexity' => 'Kompleksitas',
+ 'Task limit' => 'Batas tugas.',
+ 'Task count' => 'Jumlah tugas',
+ 'User' => 'Pengguna',
+ 'Comments' => 'Komentar',
+ 'Write your text in Markdown' => 'Menulis teks anda didalam Markdown',
+ 'Leave a comment' => 'Tinggalkan komentar',
+ 'Comment is required' => 'Komentar diperlukan',
+ 'Leave a description' => 'Tinggalkan deskripsi',
+ 'Comment added successfully.' => 'Komentar berhasil ditambahkan.',
+ 'Unable to create your comment.' => 'Tidak dapat menambahkan komentar anda.',
+ 'Edit this task' => 'Modifikasi tugas ini',
+ 'Due Date' => 'Batas Tanggal Terakhir',
+ 'Invalid date' => 'Tanggal tidak valid',
+ 'Must be done before %B %e, %Y' => 'Harus diselesaikan sebelum tanggal %d/%m/%Y',
+ '%B %e, %Y' => '%d %B %Y',
+ '%b %e, %Y' => '%d/%m/%Y',
+ 'Automatic actions' => 'Tindakan otomatis',
+ 'Your automatic action have been created successfully.' => 'Tindakan otomatis anda berhasil dibuat.',
+ 'Unable to create your automatic action.' => 'Tidak dapat membuat tindakan otomatis anda.',
+ 'Remove an action' => 'Hapus tindakan',
+ 'Unable to remove this action.' => 'Tidak dapat menghapus tindakan ini',
+ 'Action removed successfully.' => 'Tindakan berhasil dihapus.',
+ 'Automatic actions for the project "%s"' => 'Tindakan otomatis untuk projek ini « %s »',
+ 'Defined actions' => 'Tindakan didefinisikan',
+ 'Add an action' => 'Tambah tindakan',
+ 'Event name' => 'Nama acara',
+ 'Action name' => 'Nama tindakan',
+ 'Action parameters' => 'Parameter tindakan',
+ 'Action' => 'Tindakan',
+ 'Event' => 'Acara',
+ 'When the selected event occurs execute the corresponding action.' => 'Ketika acara yang dipilih terjadi, melakukan tindakan yang sesuai.',
+ 'Next step' => 'Langkah selanjutnya',
+ 'Define action parameters' => 'Definisi parameter tindakan',
+ 'Save this action' => 'Simpan tindakan ini',
+ 'Do you really want to remove this action: "%s"?' => 'Apakah anda yakin akan menghapus tindakan ini « %s » ?',
+ 'Remove an automatic action' => 'Hapus tindakan otomatis',
+ 'Assign the task to a specific user' => 'Menetapkan tugas untuk pengguna tertentu',
+ 'Assign the task to the person who does the action' => 'Memberikan tugas untuk orang yang melakukan tindakan',
+ 'Duplicate the task to another project' => 'Duplikasi tugas ke projek lain',
+ 'Move a task to another column' => 'Pindahkan tugas ke kolom lain',
+ 'Task modification' => 'Modifikasi tugas',
+ 'Task creation' => 'Membuat tugas',
+ 'Closing a task' => 'Menutup tugas',
+ 'Assign a color to a specific user' => 'Menetapkan warna untuk pengguna tertentu',
+ 'Column title' => 'Judul kolom',
+ 'Position' => 'Posisi',
+ 'Move Up' => 'Pindah ke atas',
+ 'Move Down' => 'Pindah ke bawah',
+ 'Duplicate to another project' => 'Duplikasi ke projek lain',
+ 'Duplicate' => 'Duplikasi',
+ 'link' => 'Pautan',
+ 'Comment updated successfully.' => 'Komentar berhasil diperbaharui.',
+ 'Unable to update your comment.' => 'Tidak dapat memperbaharui komentar anda.',
+ 'Remove a comment' => 'Hapus komentar',
+ 'Comment removed successfully.' => 'Komentar berhasil dihapus.',
+ 'Unable to remove this comment.' => 'Tidak dapat menghapus komentar ini.',
+ 'Do you really want to remove this comment?' => 'Apakah anda yakin akan menghapus komentar ini ?',
+ 'Only administrators or the creator of the comment can access to this page.' => 'Hanya administrator atau pembuat komentar yang dapat mengakses halaman ini.',
+ 'Current password for the user "%s"' => 'Kata laluan saat ini untuk pengguna « %s »',
+ 'The current password is required' => 'Kata laluan saat ini diperlukan',
+ 'Wrong password' => 'Kata laluan salah',
+ 'Unknown' => 'Tidak diketahui',
+ 'Last logins' => 'Masuk terakhir',
+ 'Login date' => 'Tanggal masuk',
+ 'Authentication method' => 'Metode otentifikasi',
+ 'IP address' => 'Alamat IP',
+ 'User agent' => 'Agen Pengguna',
+ 'Persistent connections' => 'Koneksi persisten',
+ 'No session.' => 'Tidak ada sesi.',
+ 'Expiration date' => 'Tanggal kadaluarsa',
+ 'Remember Me' => 'Ingat Saya',
+ 'Creation date' => 'Tanggal dibuat',
+ 'Everybody' => 'Semua orang',
+ 'Open' => 'Terbuka',
+ 'Closed' => 'Ditutup',
+ 'Search' => 'Cari',
+ 'Nothing found.' => 'Tidak ditemukan.',
+ 'Due date' => 'Batas tanggal terakhir',
+ 'Others formats accepted: %s and %s' => 'Format lain yang didukung : %s et %s',
+ 'Description' => 'Deskripsi',
+ '%d comments' => '%d komentar',
+ '%d comment' => '%d komentar',
+ 'Email address invalid' => 'Alamat email tidak valid',
+ 'Your external account is not linked anymore to your profile.' => 'Akaun eksternal anda tidak lagi terhubung ke profil anda.',
+ 'Unable to unlink your external account.' => 'Tidak dapat memutuskan Akaun eksternal anda.',
+ 'External authentication failed' => 'Otentifikasi eksternal gagal',
+ 'Your external account is linked to your profile successfully.' => 'Akaun eksternal anda berhasil dihubungkan ke profil anda.',
+ 'Email' => 'Email',
+ 'Link my Google Account' => 'Hubungkan Akaun Google saya',
+ 'Unlink my Google Account' => 'Putuskan Akaun Google saya',
+ 'Login with my Google Account' => 'Masuk menggunakan Akaun Google saya',
+ 'Project not found.' => 'projek tidak ditemukan.',
+ 'Task removed successfully.' => 'Tugas berhasil dihapus.',
+ 'Unable to remove this task.' => 'Tidak dapat menghapus tugas ini.',
+ 'Remove a task' => 'Hapus tugas',
+ 'Do you really want to remove this task: "%s"?' => 'Apakah anda yakin akan menghapus tugas ini « %s » ?',
+ 'Assign automatically a color based on a category' => 'Otomatis menetapkan warna berdasarkan kategori',
+ 'Assign automatically a category based on a color' => 'Otomatis menetapkan kategori berdasarkan warna',
+ 'Task creation or modification' => 'Tugas dibuat atau di mofifikasi',
+ 'Category' => 'Kategori',
+ 'Category:' => 'Kategori :',
+ 'Categories' => 'Kategori',
+ 'Category not found.' => 'Kategori tidak ditemukan',
+ 'Your category have been created successfully.' => 'Kategori anda berhasil dibuat.',
+ 'Unable to create your category.' => 'Tidak dapat membuat kategori anda.',
+ 'Your category have been updated successfully.' => 'Kategori anda berhasil diperbaharui.',
+ 'Unable to update your category.' => 'Tidak dapat memperbaharui kategori anda.',
+ 'Remove a category' => 'Hapus kategori',
+ 'Category removed successfully.' => 'Kategori berhasil dihapus.',
+ 'Unable to remove this category.' => 'Tidak dapat menghapus kategori ini.',
+ 'Category modification for the project "%s"' => 'Modifikasi kategori untuk projek « %s »',
+ 'Category Name' => 'Nama Kategori',
+ 'Add a new category' => 'Tambah kategori baru',
+ 'Do you really want to remove this category: "%s"?' => 'Apakah anda yakin akan menghapus kategori ini « %s » ?',
+ 'All categories' => 'Semua kategori',
+ 'No category' => 'Tidak ada kategori',
+ 'The name is required' => 'Nama diperlukan',
+ 'Remove a file' => 'Hapus berkas',
+ 'Unable to remove this file.' => 'Tidak dapat menghapus berkas ini.',
+ 'File removed successfully.' => 'Berkas berhasil dihapus.',
+ 'Attach a document' => 'Lampirkan dokumen',
+ 'Do you really want to remove this file: "%s"?' => 'Apakah anda yakin akan menghapus berkas ini « %s » ?',
+ 'Attachments' => 'Lampiran',
+ 'Edit the task' => 'Modifikasi tugas',
+ 'Edit the description' => 'Modifikasi deskripsi',
+ 'Add a comment' => 'Tambahkan komentar',
+ 'Edit a comment' => 'Modifikasi komentar',
+ 'Summary' => 'Ringkasan',
+ 'Time tracking' => 'Pelacakan waktu',
+ 'Estimate:' => 'Estimasi :',
+ 'Spent:' => 'Menghabiskan:',
+ 'Do you really want to remove this sub-task?' => 'Apakah anda yakin akan menghapus sub-tugas ini ?',
+ 'Remaining:' => 'Tersisa:',
+ 'hours' => 'jam',
+ 'spent' => 'menghabiskan',
+ 'estimated' => 'perkiraan',
+ 'Sub-Tasks' => 'Sub-tugas',
+ 'Add a sub-task' => 'Tambahkan sub-tugas',
+ 'Original estimate' => 'Perkiraan semula',
+ 'Create another sub-task' => 'Tambahkan sub-tugas lainnya',
+ 'Time spent' => 'Waktu yang dihabiskan',
+ 'Edit a sub-task' => 'Modifikasi sub-tugas',
+ 'Remove a sub-task' => 'Hapus sub-tugas',
+ 'The time must be a numeric value' => 'Waktu harus berisikan numerik',
+ 'Todo' => 'Yang harus dilakukan',
+ 'In progress' => 'Sedang proses',
+ 'Sub-task removed successfully.' => 'Sub-tugas berhasil dihapus.',
+ 'Unable to remove this sub-task.' => 'Tidak dapat menghapus sub-tugas.',
+ 'Sub-task updated successfully.' => 'Sub-tugas berhasil diperbaharui.',
+ 'Unable to update your sub-task.' => 'Tidak dapat memperbaharui sub-tugas anda.',
+ 'Unable to create your sub-task.' => 'Tidak dapat membuat sub-tugas anda.',
+ 'Sub-task added successfully.' => 'Sub-tugas berhasil dibuat.',
+ 'Maximum size: ' => 'Ukuran maksimum: ',
+ 'Unable to upload the file.' => 'Tidak dapat mengunggah berkas.',
+ 'Display another project' => 'Lihat projek lain',
+ 'Login with my Github Account' => 'Masuk menggunakan Akaun Github saya',
+ 'Link my Github Account' => 'Hubungkan Akaun Github saya ',
+ 'Unlink my Github Account' => 'Putuskan Akaun Github saya',
+ 'Created by %s' => 'Dibuat oleh %s',
+ 'Last modified on %B %e, %Y at %k:%M %p' => 'Modifikasi terakhir pada tanggal %d/%m/%Y à %H:%M',
+ 'Tasks Export' => 'Ekspor Tugas',
+ 'Tasks exportation for "%s"' => 'Tugas di ekspor untuk « %s »',
+ 'Start Date' => 'Tanggal Mulai',
+ 'End Date' => 'Tanggal Berakhir',
+ 'Execute' => 'Eksekusi',
+ 'Task Id' => 'Id Tugas',
+ 'Creator' => 'Pembuat',
+ 'Modification date' => 'Tanggal modifikasi',
+ 'Completion date' => 'Tanggal penyelesaian',
+ 'Clone' => 'Klon',
+ 'Project cloned successfully.' => 'Kloning projek berhasil.',
+ 'Unable to clone this project.' => 'Tidak dapat mengkloning projek.',
+ 'Enable email notifications' => 'Aktifkan pemberitahuan dari email',
+ 'Task position:' => 'Posisi tugas :',
+ 'The task #%d have been opened.' => 'Tugas #%d telah dibuka.',
+ 'The task #%d have been closed.' => 'Tugas #%d telah ditutup.',
+ 'Sub-task updated' => 'Sub-tugas diperbaharui',
+ 'Title:' => 'Judul :',
+ 'Status:' => 'Status :',
+ 'Assignee:' => 'Ditugaskan ke :',
+ 'Time tracking:' => 'Pelacakan waktu :',
+ 'New sub-task' => 'Sub-tugas baru',
+ 'New attachment added "%s"' => 'Lampiran baru ditambahkan « %s »',
+ 'Comment updated' => 'Komentar diperbaharui',
+ 'New comment posted by %s' => 'Komentar baru ditambahkan oleh « %s »',
+ 'New attachment' => 'Lampirkan baru',
+ 'New comment' => 'Komentar baru',
+ 'New subtask' => 'Sub-tugas baru',
+ 'Subtask updated' => 'Sub-tugas diperbaharui',
+ 'Task updated' => 'Tugas diperbaharui',
+ 'Task closed' => 'Tugas ditutup',
+ 'Task opened' => 'Tugas dibuka',
+ 'I want to receive notifications only for those projects:' => 'Saya ingin menerima pemberitahuan hanya untuk projek-projek yang dipilih :',
+ 'view the task on Kanboard' => 'lihat tugas di Kanboard',
+ 'Public access' => 'Akses awam',
+ 'User management' => 'Manajemen pengguna',
+ 'Active tasks' => 'Tugas aktif',
+ 'Disable public access' => 'Nyahaktifkan akses awam',
+ 'Enable public access' => 'Aktifkan akses awam',
+ 'Public access disabled' => 'Akses awam dinyahaktif',
+ 'Do you really want to disable this project: "%s"?' => 'Anda yakin menyah-aktifkan projek ini : « %s » ?',
+ 'Do you really want to enable this project: "%s"?' => 'Anda yakin untuk mengaktifkan projek ini : « %s » ?',
+ 'Project activation' => 'Aktifkan projek',
+ 'Move the task to another project' => 'Pindahkan tugas ke projek lain',
+ 'Move to another project' => 'Pindahkan ke projek lain',
+ 'Do you really want to duplicate this task?' => 'Anda yakin mengembarkan tugas ini ?',
+ 'Duplicate a task' => 'Kembarkan tugas',
+ 'External accounts' => 'Akaun luaran',
+ 'Account type' => 'Jenis Akaun',
+ 'Local' => 'Lokal',
+ 'Remote' => 'Jauh',
+ 'Enabled' => 'Aktif',
+ 'Disabled' => 'Tidak aktif',
+ 'Username:' => 'Nama pengguna :',
+ 'Name:' => 'Nama:',
+ 'Email:' => 'Emel:',
+ 'Notifications:' => 'Makluman:',
+ 'Notifications' => 'Makluman',
+ 'Account type:' => 'Jenis Akaun :',
+ 'Edit profile' => 'Sunting profil',
+ 'Change password' => 'Rubah kata sandri',
+ 'Password modification' => 'Modifikasi kata laluan',
+ 'External authentications' => 'Otentifikasi eksternal',
+ 'Google Account' => 'Akaun Google',
+ 'Github Account' => 'Akaun Github',
+ 'Never connected.' => 'Tidak pernah terhubung.',
+ 'No account linked.' => 'Tidak ada Akaun terhubung.',
+ 'Account linked.' => 'Akaun terhubung.',
+ 'No external authentication enabled.' => 'Tidak ada otentifikasi eksternal yang aktif.',
+ 'Password modified successfully.' => 'Kata laluan telah berjaya ditukar.',
+ 'Unable to change the password.' => 'Tidak dapat merubah kata laluanr.',
+ 'Change category for the task "%s"' => 'Rubah kategori untuk tugas « %s »',
+ 'Change category' => 'Tukar kategori',
+ '%s updated the task %s' => '%s memperbaharui tugas %s',
+ '%s opened the task %s' => '%s membuka tugas %s',
+ '%s moved the task %s to the position #%d in the column "%s"' => '%s memindahkan tugas %s ke posisi n°%d dalam kolom « %s »',
+ '%s moved the task %s to the column "%s"' => '%s memindahkan tugas %s ke kolom « %s »',
+ '%s created the task %s' => '%s membuat tugas %s',
+ '%s closed the task %s' => '%s menutup tugas %s',
+ '%s created a subtask for the task %s' => '%s membuat subtugas untuk tugas %s',
+ '%s updated a subtask for the task %s' => '%s memperbaharui subtugas untuk tugas %s',
+ 'Assigned to %s with an estimate of %s/%sh' => 'Ditugaskan untuk %s dengan perkiraan %s/%sh',
+ 'Not assigned, estimate of %sh' => 'Tiada yang ditugaskan, perkiraan %sh',
+ '%s updated a comment on the task %s' => '%s memperbaharui komentar pada tugas %s',
+ '%s commented the task %s' => '%s memberikan komentar pada tugas %s',
+ '%s\'s activity' => 'Aktifitas dari %s',
+ 'RSS feed' => 'RSS feed',
+ '%s updated a comment on the task #%d' => '%s memperbaharui komentar pada tugas n°%d',
+ '%s commented on the task #%d' => '%s memberikan komentar pada tugas n°%d',
+ '%s updated a subtask for the task #%d' => '%s memperbaharui subtugas untuk tugas n°%d',
+ '%s created a subtask for the task #%d' => '%s membuat subtugas untuk tugas n°%d',
+ '%s updated the task #%d' => '%s memperbaharui tugas n°%d',
+ '%s created the task #%d' => '%s membuat tugas n°%d',
+ '%s closed the task #%d' => '%s menutup tugas n°%d',
+ '%s open the task #%d' => '%s membuka tugas n°%d',
+ '%s moved the task #%d to the column "%s"' => '%s memindahkan tugas n°%d ke kolom « %s »',
+ '%s moved the task #%d to the position %d in the column "%s"' => '%s memindahkan tugas n°%d ke posisi n°%d dalam kolom « %s »',
+ 'Activity' => 'Aktifitas',
+ 'Default values are "%s"' => 'Standar nilai adalah« %s »',
+ 'Default columns for new projects (Comma-separated)' => 'Kolom default untuk projek baru (dipisahkan dengan koma)',
+ 'Task assignee change' => 'Mengubah orang ditugaskan untuk tugas',
+ '%s change the assignee of the task #%d to %s' => '%s rubah orang yang ditugaskan dari tugas n%d ke %s',
+ '%s changed the assignee of the task %s to %s' => '%s mengubah orang yang ditugaskan dari tugas %s ke %s',
+ 'New password for the user "%s"' => 'Kata laluan baru untuk pengguna « %s »',
+ 'Choose an event' => 'Pilih sebuah acara',
+ 'Create a task from an external provider' => 'Buat tugas dari pemasok eksternal',
+ 'Change the assignee based on an external username' => 'Rubah penugasan berdasarkan nama pengguna eksternal',
+ 'Change the category based on an external label' => 'Rubah kategori berdasarkan label eksternal',
+ 'Reference' => 'Referensi',
+ 'Reference: %s' => 'Referensi : %s',
+ 'Label' => 'Label',
+ 'Database' => 'Pengkalan data',
+ 'About' => 'Tentang',
+ 'Database driver:' => 'Driver pengkalan data:',
+ 'Board settings' => 'Pengaturan papan',
+ 'URL and token' => 'URL dan token',
+ 'Webhook settings' => 'Penetapan webhook',
+ 'URL for task creation:' => 'URL untuk cipta tugas:',
+ 'Reset token' => 'Menetap semula token',
+ 'API endpoint:' => 'API endpoint :',
+ 'Refresh interval for private board' => 'Interval pembaruan untuk papan pribadi',
+ 'Refresh interval for public board' => 'Interval pembaruan untuk papan publik',
+ 'Task highlight period' => 'Periode puncak tugas',
+ 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode (dalam detik) untuk mempertimbangkan tugas yang baru dimodifikasi (0 untuk menonaktifkan, standar 2 hari)',
+ 'Frequency in second (60 seconds by default)' => 'Frequensi dalam detik (standar 60 saat)',
+ 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekuensi dalam detik (0 untuk menonaktifkan fitur ini, standar 10 detik)',
+ 'Application URL' => 'URL Aplikasi',
+ 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Contoh: http://example.kanboard.net/ (digunakan untuk pemberitahuan email)',
+ 'Token regenerated.' => 'Token diregenerasi.',
+ 'Date format' => 'Format tarikh',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'Format ISO selalunya diterima, contoh: « %s » et « %s »',
+ 'New private project' => 'Projek peribadi baharu',
+ 'This project is private' => 'projek ini adalah peribadi',
+ 'Type here to create a new sub-task' => 'Ketik disini untuk membuat sub-tugas baru',
+ 'Add' => 'Tambah',
+ 'Estimated time: %s hours' => 'Anggaran waktu: %s jam',
+ 'Time spent: %s hours' => 'Waktu dihabiskan : %s jam',
+ 'Started on %B %e, %Y' => 'Dimulai pada %d/%m/%Y',
+ 'Start date' => 'Tarikh mula',
+ 'Time estimated' => 'Anggaran masa',
+ 'There is nothing assigned to you.' => 'Tidak ada yang diberikan kepada anda.',
+ 'My tasks' => 'Tugas saya',
+ 'Activity stream' => 'Arus aktifitas',
+ 'Dashboard' => 'Dasbor',
+ 'Confirmation' => 'Konfirmasi',
+ 'Allow everybody to access to this project' => 'Memungkinkan semua orang untuk mengakses projek ini',
+ 'Everybody have access to this project.' => 'Semua orang mendapat akses untuk projek ini.',
+ 'Webhooks' => 'Webhooks',
+ 'API' => 'API',
+ 'Create a comment from an external provider' => 'Buat komentar dari pemasok eksternal',
+ 'Project management' => 'Manajemen projek',
+ 'My projects' => 'projek saya',
+ 'Columns' => 'Kolom',
+ 'Task' => 'Tugas',
+ 'Your are not member of any project.' => 'Anda bukan anggota dari setiap projek.',
+ 'Percentage' => 'Persentasi',
+ 'Number of tasks' => 'Jumlah dari tugas',
+ 'Task distribution' => 'Pembagian tugas',
+ 'Reportings' => 'Pelaporan',
+ 'Task repartition for "%s"' => 'Pembagian tugas untuk « %s »',
+ 'Analytics' => 'Analitis',
+ 'Subtask' => 'Subtugas',
+ 'My subtasks' => 'Subtugas saya',
+ 'User repartition' => 'Partisi ulang pengguna',
+ 'User repartition for "%s"' => 'Partisi ulang pengguna untuk « %s »',
+ 'Clone this project' => 'Gandakan projek ini',
+ 'Column removed successfully.' => 'Kolom berhasil dihapus.',
+ 'Not enough data to show the graph.' => 'Tidak cukup data untuk menampilkan grafik.',
+ 'Previous' => 'Sebelumnya',
+ 'The id must be an integer' => 'Id harus integer',
+ 'The project id must be an integer' => 'Id projek harus integer',
+ 'The status must be an integer' => 'Status harus integer',
+ 'The subtask id is required' => 'Id subtugas diperlukan',
+ 'The subtask id must be an integer' => 'Id subtugas harus integer',
+ 'The task id is required' => 'Id tugas diperlukan',
+ 'The task id must be an integer' => 'Id tugas harus integer',
+ 'The user id must be an integer' => 'Id user harus integer',
+ 'This value is required' => 'Nilai ini diperlukan',
+ 'This value must be numeric' => 'Nilai ini harus angka',
+ 'Unable to create this task.' => 'Tidak dapat membuat tugas ini',
+ 'Cumulative flow diagram' => 'Diagram alir kumulatif',
+ 'Cumulative flow diagram for "%s"' => 'Diagram alir kumulatif untuk « %s »',
+ 'Daily project summary' => 'Ringkasan projek harian',
+ 'Daily project summary export' => 'Ekspot ringkasan projek harian',
+ 'Daily project summary export for "%s"' => 'Ekspor ringkasan projek harian untuk « %s »',
+ 'Exports' => 'Ekspor',
+ 'This export contains the number of tasks per column grouped per day.' => 'Ekspor ini berisi jumlah dari tugas per kolom dikelompokan perhari.',
+ 'Nothing to preview...' => 'Tiada yang dapat diintai...',
+ 'Preview' => 'Intai',
+ 'Write' => 'Tulis',
+ 'Active swimlanes' => 'Swimlanes aktif',
+ 'Add a new swimlane' => 'Tambah swimlane baharu',
+ 'Change default swimlane' => 'Tukar piawai swimlane',
+ 'Default swimlane' => 'Piawai swimlane',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Anda yakin untuk menghapus swimlane ini : « %s » ?',
+ 'Inactive swimlanes' => 'Swimlanes tidak aktif',
+ 'Remove a swimlane' => 'Padam swimlane',
+ 'Rename' => 'Namakan semula',
+ 'Show default swimlane' => 'Tampilkan piawai swimlane',
+ 'Swimlane modification for the project "%s"' => 'Modifikasi swimlane untuk projek « %s »',
+ 'Swimlane not found.' => 'Swimlane tidak ditemui.',
+ 'Swimlane removed successfully.' => 'Swimlane telah dipadamkan.',
+ 'Swimlanes' => 'Swimlanes',
+ 'Swimlane updated successfully.' => 'Swimlane telah dikemaskini.',
+ 'The default swimlane have been updated successfully.' => 'Standar swimlane berhasil diperbaharui.',
+ 'Unable to create your swimlane.' => 'Tidak dapat membuat swimlane anda.',
+ 'Unable to remove this swimlane.' => 'Tidak dapat menghapus swimlane ini.',
+ 'Unable to update this swimlane.' => 'Tidak dapat memperbaharui swimlane ini.',
+ 'Your swimlane have been created successfully.' => 'Swimlane anda berhasil dibuat.',
+ 'Example: "Bug, Feature Request, Improvement"' => 'Contoh: « Insiden, Permintaan Ciri, Pembaikan »',
+ 'Default categories for new projects (Comma-separated)' => 'Piawaian kategori untuk projek baru (asingkan guna koma)',
+ 'Integrations' => 'Integrasi',
+ 'Integration with third-party services' => 'Integrasi dengan khidmat pihak ketiga',
+ 'Subtask Id' => 'Id Subtugas',
+ 'Subtasks' => 'Subtugas',
+ 'Subtasks Export' => 'Ekspot Subtugas',
+ 'Subtasks exportation for "%s"' => 'Ekspor subtugas untuk « %s »',
+ 'Task Title' => 'Judul Tugas',
+ 'Untitled' => 'Tanpa nama',
+ 'Application default' => 'Aplikasi Piawaian',
+ 'Language:' => 'Bahasa:',
+ 'Timezone:' => 'Zon masa:',
+ 'All columns' => 'Semua kolom',
+ 'Calendar' => 'Kalender',
+ 'Next' => 'Selanjutnya',
+ '#%d' => 'n°%d',
+ 'All swimlanes' => 'Semua swimlane',
+ 'All colors' => 'Semua warna',
+ 'Moved to column %s' => 'Pindah ke kolom %s',
+ 'Change description' => 'Ubah keterangan',
+ 'User dashboard' => 'Papan Kenyataan pengguna',
+ 'Allow only one subtask in progress at the same time for a user' => 'Izinkan hanya satu subtugas dalam proses secara bersamaan untuk satu pengguna',
+ 'Edit column "%s"' => 'Modifikasi kolom « %s »',
+ 'Select the new status of the subtask: "%s"' => 'Pilih status baru untuk subtugas : « %s »',
+ 'Subtask timesheet' => 'Subtugas absen',
+ 'There is nothing to show.' => 'Tidak ada yang dapat diperlihatkan.',
+ 'Time Tracking' => 'Pelacakan waktu',
+ 'You already have one subtask in progress' => 'Anda sudah ada satu subtugas dalam proses',
+ 'Which parts of the project do you want to duplicate?' => 'Bagian dalam projek mana yang ingin anda duplikasi?',
+ 'Disallow login form' => 'Larang formulir masuk',
+ 'Start' => 'Mula',
+ 'End' => 'Selesai',
+ 'Task age in days' => 'Usia tugas dalam bentuk harian',
+ 'Days in this column' => 'Hari dalam kolom ini',
+ '%dd' => '%dj',
+ 'Add a link' => 'Menambahkan pautan',
+ 'Add a new link' => 'Tambah Pautan baru',
+ 'Do you really want to remove this link: "%s"?' => 'Anda yakin akan menghapus Pautan ini : « %s » ?',
+ 'Do you really want to remove this link with task #%d?' => 'Anda yakin akan menghapus Pautan ini dengan tugas n°%d ?',
+ 'Field required' => 'Medan diperlukan',
+ 'Link added successfully.' => 'Pautan berhasil ditambahkan.',
+ 'Link updated successfully.' => 'Pautan berhasil diperbaharui.',
+ 'Link removed successfully.' => 'Pautan berhasil dihapus.',
+ 'Link labels' => 'Label Pautan',
+ 'Link modification' => 'Modifikasi Pautan',
+ 'Links' => 'Pautan',
+ 'Link settings' => 'Pengaturan Pautan',
+ 'Opposite label' => 'Label berlawanan',
+ 'Remove a link' => 'Hapus Pautan',
+ 'Task\'s links' => 'Pautan tugas',
+ 'The labels must be different' => 'Label harus berbeda',
+ 'There is no link.' => 'Tidak ada Pautan.',
+ 'This label must be unique' => 'Label ini harus unik',
+ 'Unable to create your link.' => 'Tidak dapat membuat Pautan anda.',
+ 'Unable to update your link.' => 'Tidak dapat memperbaharui Pautan anda.',
+ 'Unable to remove this link.' => 'Tidak dapat menghapus Pautan ini.',
+ 'relates to' => 'berhubungan dengan',
+ 'blocks' => 'blok',
+ 'is blocked by' => 'diblokir oleh',
+ 'duplicates' => 'duplikat',
+ 'is duplicated by' => 'diduplikasi oleh',
+ 'is a child of' => 'anak dari',
+ 'is a parent of' => 'orant tua dari',
+ 'targets milestone' => 'milestone target',
+ 'is a milestone of' => 'adalah milestone dari',
+ 'fixes' => 'perbaikan',
+ 'is fixed by' => 'diperbaiki oleh',
+ 'This task' => 'Tugas ini',
+ '<1h' => '<1h',
+ '%dh' => '%dh',
+ '%b %e' => '%e %b',
+ 'Expand tasks' => 'Perluas tugas',
+ 'Collapse tasks' => 'Lipat tugas',
+ 'Expand/collapse tasks' => 'Perluas/lipat tugas',
+ 'Close dialog box' => 'Tutup kotak dialog',
+ 'Submit a form' => 'Submit formulir',
+ 'Board view' => 'Table halaman',
+ 'Keyboard shortcuts' => 'pintas keyboard',
+ 'Open board switcher' => 'Buka table switcher',
+ 'Application' => 'Aplikasi',
+ 'since %B %e, %Y at %k:%M %p' => 'sejak %d/%m/%Y à %H:%M',
+ 'Compact view' => 'Tampilan kompak',
+ 'Horizontal scrolling' => 'Horisontal bergulir',
+ 'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas',
+ 'No results match:' => 'Tidak ada hasil :',
+ 'Currency' => 'Mata uang',
+ 'Files' => 'Arsip',
+ 'Images' => 'Gambar',
+ 'Private project' => 'projek pribadi',
+ 'AUD - Australian Dollar' => 'AUD - Dollar Australia',
+ 'CAD - Canadian Dollar' => 'CAD - Dollar Kanada',
+ 'CHF - Swiss Francs' => 'CHF - Swiss Prancis',
+ 'Custom Stylesheet' => 'Kustomisasi Stylesheet',
+ 'download' => 'unduh',
+ 'EUR - Euro' => 'EUR - Euro',
+ 'GBP - British Pound' => 'GBP - Poundsterling inggris',
+ 'INR - Indian Rupee' => 'INR - Rupe India',
+ 'JPY - Japanese Yen' => 'JPY - Yen Jepang',
+ 'NZD - New Zealand Dollar' => 'NZD - Dollar Selandia baru',
+ 'RSD - Serbian dinar' => 'RSD - Dinar Serbia',
+ 'USD - US Dollar' => 'USD - Dollar Amerika',
+ 'Destination column' => 'Kolom tujuan',
+ 'Move the task to another column when assigned to a user' => 'Pindahkan tugas ke kolom lain ketika ditugaskan ke pengguna',
+ 'Move the task to another column when assignee is cleared' => 'Pindahkan tugas ke kolom lain ketika orang yang ditugaskan dibersihkan',
+ 'Source column' => 'Sumber kolom',
+ 'Transitions' => 'Transisi',
+ 'Executer' => 'Eksekusi',
+ 'Time spent in the column' => 'Waktu yang dihabiskan dalam kolom',
+ 'Task transitions' => 'Transisi tugas',
+ 'Task transitions export' => 'Ekspor transisi tugas',
+ 'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Laporan ini berisi semua kolom yang pindah untuk setiap tugas dengan tanggal, pengguna dan waktu yang dihabiskan untuk setiap transisi.',
+ 'Currency rates' => 'Nilai tukar mata uang',
+ 'Rate' => 'Tarif',
+ 'Change reference currency' => 'Mengubah referensi mata uang',
+ 'Add a new currency rate' => 'Tambahkan nilai tukar mata uang baru',
+ 'Reference currency' => 'Referensi mata uang',
+ 'The currency rate have been added successfully.' => 'Nilai tukar mata uang berhasil ditambahkan.',
+ 'Unable to add this currency rate.' => 'Tidak dapat menambahkan nilai tukar mata uang',
+ 'Webhook URL' => 'URL webhook',
+ '%s remove the assignee of the task %s' => '%s menghapus penugasan dari tugas %s',
+ 'Enable Gravatar images' => 'Mengaktifkan gambar Gravatar',
+ 'Information' => 'Informasi',
+ 'Check two factor authentication code' => 'Cek dua faktor kode otentifikasi',
+ 'The two factor authentication code is not valid.' => 'Kode dua faktor kode otentifikasi tidak valid.',
+ 'The two factor authentication code is valid.' => 'Kode dua faktor kode otentifikasi valid.',
+ 'Code' => 'Kode',
+ 'Two factor authentication' => 'Dua faktor otentifikasi',
+ 'This QR code contains the key URI: ' => 'kode QR ini mengandung kunci URI : ',
+ 'Check my code' => 'Memeriksa kode saya',
+ 'Secret key: ' => 'Kunci rahasia : ',
+ 'Test your device' => 'Menguji perangkat anda',
+ 'Assign a color when the task is moved to a specific column' => 'Menetapkan warna ketika tugas tersebut dipindahkan ke kolom tertentu',
+ '%s via Kanboard' => '%s via Kanboard',
+ 'uploaded by: %s' => 'diunggah oleh %s',
+ 'uploaded on: %s' => 'diunggah pada %s',
+ 'size: %s' => 'ukuran : %s',
+ 'Burndown chart for "%s"' => 'Grafik Burndown untku « %s »',
+ 'Burndown chart' => 'Grafik Burndown',
+ 'This chart show the task complexity over the time (Work Remaining).' => 'Grafik ini menunjukkan kompleksitas tugas dari waktu ke waktu (Sisa Pekerjaan).',
+ 'Screenshot taken %s' => 'Screenshot diambil %s',
+ 'Add a screenshot' => 'Tambah screenshot',
+ 'Take a screenshot and press CTRL+V or ?+V to paste here.' => 'Mengambil screenshot dan tekan CTRL + V atau ? + V untuk paste di sini.',
+ 'Screenshot uploaded successfully.' => 'Screenshot berhasil diunggah.',
+ 'SEK - Swedish Krona' => 'SEK - Krona Swedia',
+ 'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identifier projek adalah kode alfanumerik opsional digunakan untuk mengidentifikasi projek Anda.',
+ 'Identifier' => 'Identifier',
+ 'Disable two factor authentication' => 'Matikan dua faktor otentifikasi',
+ 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Apakah anda yakin akan mematikan dua faktor otentifikasi untuk pengguna ini : « %s » ?',
+ 'Edit link' => 'Modifikasi Pautan',
+ 'Start to type task title...' => 'Mulai mengetik judul tugas...',
+ 'A task cannot be linked to itself' => 'Sebuah tugas tidak dapat dikaitkan dengan dirinya sendiri',
+ 'The exact same link already exists' => 'Pautan yang sama persis sudah ada',
+ 'Recurrent task is scheduled to be generated' => 'Tugas berulang dijadwalkan akan dihasilkan',
+ 'Recurring information' => 'Informasi berulang',
+ 'Score' => 'Skor',
+ 'The identifier must be unique' => 'Identifier harus unik',
+ 'This linked task id doesn\'t exists' => 'Id tugas terkait tidak ada',
+ 'This value must be alphanumeric' => 'Nilai harus alfanumerik',
+ 'Edit recurrence' => 'Modifikasi pengulangan',
+ 'Generate recurrent task' => 'Menghasilkan tugas berulang',
+ 'Trigger to generate recurrent task' => 'Memicu untuk menghasilkan tugas berulang',
+ 'Factor to calculate new due date' => 'Faktor untuk menghitung tanggal jatuh tempo baru',
+ 'Timeframe to calculate new due date' => 'Jangka waktu untuk menghitung tanggal jatuh tempo baru',
+ 'Base date to calculate new due date' => 'Tanggal dasar untuk menghitung tanggal jatuh tempo baru',
+ 'Action date' => 'Tanggal aksi',
+ 'Base date to calculate new due date: ' => 'Tanggal dasar untuk menghitung tanggal jatuh tempo baru: ',
+ 'This task has created this child task: ' => 'Tugas ini telah menciptakan tugas anak ini: ',
+ 'Day(s)' => 'Hari',
+ 'Existing due date' => 'Batas waktu yang ada',
+ 'Factor to calculate new due date: ' => 'Faktor untuk menghitung tanggal jatuh tempo baru: ',
+ 'Month(s)' => 'Bulan',
+ 'Recurrence' => 'Pengulangan',
+ 'This task has been created by: ' => 'Tugas ini telah dibuat oleh:',
+ 'Recurrent task has been generated:' => 'Tugas berulang telah dihasilkan:',
+ 'Timeframe to calculate new due date: ' => 'Jangka waktu untuk menghitung tanggal jatuh tempo baru: ',
+ 'Trigger to generate recurrent task: ' => 'Pemicu untuk menghasilkan tugas berulang: ',
+ 'When task is closed' => 'Ketika tugas ditutup',
+ 'When task is moved from first column' => 'Ketika tugas dipindahkan dari kolom pertama',
+ 'When task is moved to last column' => 'Ketika tugas dipindahkan ke kolom terakhir',
+ 'Year(s)' => 'Tahun',
+ 'Calendar settings' => 'Pengaturan kalender',
+ 'Project calendar view' => 'Tampilan kalender projek',
+ 'Project settings' => 'Pengaturan projek',
+ 'Show subtasks based on the time tracking' => 'Tampilkan subtugas berdasarkan pelacakan waktu',
+ 'Show tasks based on the creation date' => 'Tampilkan tugas berdasarkan tanggal pembuatan',
+ 'Show tasks based on the start date' => 'Tampilkan tugas berdasarkan tanggal mulai',
+ 'Subtasks time tracking' => 'Pelacakan waktu subtgas',
+ 'User calendar view' => 'Pengguna tampilan kalender',
+ 'Automatically update the start date' => 'Otomatikkan pengemaskinian tanggal',
+ 'iCal feed' => 'iCal feed',
+ 'Preferences' => 'Keutamaan',
+ 'Security' => 'Keamanan',
+ 'Two factor authentication disabled' => 'Otentifikasi dua faktor dimatikan',
+ 'Two factor authentication enabled' => 'Otentifikasi dua faktor dihidupkan',
+ 'Unable to update this user.' => 'Tidak dapat memperbarui pengguna ini.',
+ 'There is no user management for private projects.' => 'Tidak ada manajemen pengguna untuk projek-projek pribadi.',
+ 'User that will receive the email' => 'Pengguna yang akan menerima email',
+ 'Email subject' => 'Subjek Emel',
+ 'Date' => 'Tanggal',
+ 'Add a comment log when moving the task between columns' => 'Menambahkan log komentar ketika memindahkan tugas antara kolom',
+ 'Move the task to another column when the category is changed' => 'Pindahkan tugas ke kolom lain ketika kategori berubah',
+ 'Send a task by email to someone' => 'Kirim tugas melalui email ke seseorang',
+ 'Reopen a task' => 'Membuka kembali tugas',
+ 'Column change' => 'Kolom berubah',
+ 'Position change' => 'Posisi berubah',
+ 'Swimlane change' => 'Swimlane berubah',
+ 'Assignee change' => 'Penerima berubah',
+ '[%s] Overdue tasks' => '[%s] Tugas terlambat',
+ 'Notification' => 'Pemberitahuan',
+ '%s moved the task #%d to the first swimlane' => '%s memindahkan tugas n°%d ke swimlane pertama',
+ '%s moved the task #%d to the swimlane "%s"' => '%s memindahkan tugas n°%d ke swimlane « %s »',
+ 'Swimlane' => 'Swimlane',
+ 'Gravatar' => 'Gravatar',
+ '%s moved the task %s to the first swimlane' => '%s memindahkan tugas %s ke swimlane pertama',
+ '%s moved the task %s to the swimlane "%s"' => '%s memindahkan tugas %s ke swimlane « %s »',
+ 'This report contains all subtasks information for the given date range.' => 'Laporan ini berisi semua informasi subtugas untuk rentang tanggal tertentu.',
+ 'This report contains all tasks information for the given date range.' => 'Laporan ini berisi semua informasi tugas untuk rentang tanggal tertentu.',
+ 'Project activities for %s' => 'Aktifitas projek untuk « %s »',
+ 'view the board on Kanboard' => 'lihat papan di Kanboard',
+ 'The task have been moved to the first swimlane' => 'Tugas telah dipindahkan ke swimlane pertama',
+ 'The task have been moved to another swimlane:' => 'Tugas telah dipindahkan ke swimlane lain:',
+ 'Overdue tasks for the project "%s"' => 'Tugas terlambat untuk projek « %s »',
+ 'New title: %s' => 'Judul baru : %s',
+ 'The task is not assigned anymore' => 'Tugas tidak ditugaskan lagi',
+ 'New assignee: %s' => 'Penerima baru : %s',
+ 'There is no category now' => 'Tidak ada kategori untuk sekarang',
+ 'New category: %s' => 'Kategori baru : %s',
+ 'New color: %s' => 'Warna baru : %s',
+ 'New complexity: %d' => 'Kompleksitas baru : %d',
+ 'The due date have been removed' => 'Tanggal jatuh tempo telah dihapus',
+ 'There is no description anymore' => 'Tidak ada deskripsi lagi',
+ 'Recurrence settings have been modified' => 'Pengaturan pengulangan telah dimodifikasi',
+ 'Time spent changed: %sh' => 'Waktu yang dihabiskan berubah : %sh',
+ 'Time estimated changed: %sh' => 'Perkiraan waktu berubah : %sh',
+ 'The field "%s" have been updated' => 'Field « %s » telah diperbaharui',
+ 'The description have been modified' => 'Deskripsi telah dimodifikasi',
+ 'Do you really want to close the task "%s" as well as all subtasks?' => 'Apakah anda yakin akan menutup tugas « %s » beserta semua sub-tugasnya ?',
+ 'Swimlane: %s' => 'Swimlane : %s',
+ 'I want to receive notifications for:' => 'Saya ingin menerima pemberitahuan untuk :',
+ 'All tasks' => 'Semua tugas',
+ 'Only for tasks assigned to me' => 'Hanya untuk tugas yang ditugaskan ke saya',
+ 'Only for tasks created by me' => 'Hanya untuk tugas yang dibuat oleh saya',
+ 'Only for tasks created by me and assigned to me' => 'Hanya untuk tugas yang dibuat oleh saya dan ditugaskan ke saya',
+ '%A' => '%A',
+ '%b %e, %Y, %k:%M %p' => '%d/%m/%Y %H:%M',
+ 'New due date: %B %e, %Y' => 'Tanggal jatuh tempo baru : %d/%m/%Y',
+ 'Start date changed: %B %e, %Y' => 'Tanggal mulai berubah : %d/%m/%Y',
+ '%k:%M %p' => '%H:%M',
+ '%%Y-%%m-%%d' => '%%d/%%m/%%Y',
+ 'Total for all columns' => 'Total untuk semua kolom',
+ 'You need at least 2 days of data to show the chart.' => 'Anda memerlukan setidaknya 2 hari dari data yang menunjukkan grafik.',
+ '<15m' => '<15m',
+ '<30m' => '<30m',
+ 'Stop timer' => 'Hentikan timer',
+ 'Start timer' => 'Mulai timer',
+ 'Add project member' => 'Tambahkan anggota projek',
+ 'Enable notifications' => 'Aktifkan pemberitahuan',
+ 'My activity stream' => 'Aliran kegiatan saya',
+ 'My calendar' => 'Kalender saya',
+ 'Search tasks' => 'Cari tugas',
+ 'Back to the calendar' => 'Kembali ke kalender',
+ 'Filters' => 'Filter',
+ 'Reset filters' => 'Reset ulang filter',
+ 'My tasks due tomorrow' => 'Tugas saya yang berakhir besok',
+ 'Tasks due today' => 'Tugas yang berakhir hari ini',
+ 'Tasks due tomorrow' => 'Tugas yang berakhir besok',
+ 'Tasks due yesterday' => 'Tugas yang berakhir kemarin',
+ 'Closed tasks' => 'Tugas yang ditutup',
+ 'Open tasks' => 'Buka Tugas',
+ 'Not assigned' => 'Tidak ditugaskan',
+ 'View advanced search syntax' => 'Lihat sintaks pencarian lanjutan',
+ 'Overview' => 'Ikhtisar',
+ '%b %e %Y' => '%b %e %Y',
+ 'Board/Calendar/List view' => 'Tampilan Papan/Kalender/Daftar',
+ 'Switch to the board view' => 'Beralih ke tampilan papan',
+ 'Switch to the calendar view' => 'Beralih ke tampilan kalender',
+ 'Switch to the list view' => 'Beralih ke tampilan daftar',
+ 'Go to the search/filter box' => 'Pergi ke kotak pencarian/filter',
+ 'There is no activity yet.' => 'Tidak ada aktifitas saat ini.',
+ 'No tasks found.' => 'Tidak ada tugas yang ditemukan.',
+ 'Keyboard shortcut: "%s"' => 'Keyboard shortcut : « %s »',
+ 'List' => 'Daftar',
+ 'Filter' => 'Filter',
+ 'Advanced search' => 'Pencarian lanjutan',
+ 'Example of query: ' => 'Contoh dari query : ',
+ 'Search by project: ' => 'Pencarian berdasarkan projek : ',
+ 'Search by column: ' => 'Pencarian berdasarkan kolom : ',
+ 'Search by assignee: ' => 'Pencarian berdasarkan penerima : ',
+ 'Search by color: ' => 'Pencarian berdasarkan warna : ',
+ 'Search by category: ' => 'Pencarian berdasarkan kategori : ',
+ 'Search by description: ' => 'Pencarian berdasarkan deskripsi : ',
+ 'Search by due date: ' => 'Pencarian berdasarkan tanggal jatuh tempo : ',
+ 'Lead and Cycle time for "%s"' => 'Memimpin dan Siklus waktu untuk « %s »',
+ 'Average time spent into each column for "%s"' => 'Rata-rata waktu yang dihabiskan dalam setiap kolom untuk « %s »',
+ 'Average time spent into each column' => 'Rata-rata waktu yang dihabiskan dalam setiap kolom',
+ 'Average time spent' => 'Rata-rata waktu yang dihabiskan',
+ 'This chart show the average time spent into each column for the last %d tasks.' => 'Grafik ini menunjukkan rata-rata waktu yang dihabiskan dalam setiap kolom untuk %d tugas.',
+ 'Average Lead and Cycle time' => 'Rata-rata Memimpin dan Siklus waktu',
+ 'Average lead time: ' => 'Rata-rata waktu pimpinan : ',
+ 'Average cycle time: ' => 'Rata-rata siklus waktu : ',
+ 'Cycle Time' => 'Siklus Waktu',
+ 'Lead Time' => 'Lead Time',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Grafik ini menunjukkan memimpin rata-rata dan waktu siklus untuk %d tugas terakhir dari waktu ke waktu.',
+ 'Average time into each column' => 'Rata-rata waktu ke setiap kolom',
+ 'Lead and cycle time' => 'Lead dan siklus waktu',
+ 'Google Authentication' => 'Google Otentifikasi',
+ 'Help on Google authentication' => 'Bantuan pada otentifikasi Google',
+ 'Github Authentication' => 'Otentifikasi Github',
+ 'Help on Github authentication' => 'Bantuan pada otentifikasi Github',
+ 'Lead time: ' => 'Lead time : ',
+ 'Cycle time: ' => 'Siklus waktu : ',
+ 'Time spent into each column' => 'Waktu yang dihabiskan di setiap kolom',
+ 'The lead time is the duration between the task creation and the completion.' => 'Lead time adalah durasi antara pembuatan tugas dan penyelesaian.',
+ 'The cycle time is the duration between the start date and the completion.' => 'Siklus waktu adalah durasi antara tanggal mulai dan tanggal penyelesaian.',
+ 'If the task is not closed the current time is used instead of the completion date.' => 'Jika tugas tidak ditutup waktu saat ini yang digunakan sebagai pengganti tanggal penyelesaian.',
+ 'Set automatically the start date' => 'Secara otomatis mengatur tanggal mulai',
+ 'Edit Authentication' => 'Modifikasi Otentifikasi',
+ 'Google Id' => 'Id Google',
+ 'Github Id' => 'Id Github',
+ 'Remote user' => 'Pengguna jauh',
+ 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Pengguna jauh tidak menyimpan kata laluan mereka dalam basis data Kanboard, contoh: Akaun LDAP, Google dan Github.',
+ 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Jika anda mencentang kotak "Larang formulir login", kredensial masuk ke formulis login akan diabaikan.',
+ 'New remote user' => 'Pengguna baru jauh',
+ 'New local user' => 'Pengguna baru lokal',
+ 'Default task color' => 'Standar warna tugas',
+ 'Hide sidebar' => 'Sembunyikan sidebar',
+ 'Expand sidebar' => 'Perluas sidebar',
+ 'This feature does not work with all browsers.' => 'Ciri ini tidak dapat digunakan pada semua browsers',
+ 'There is no destination project available.' => 'Tiada destinasi projek yang tersedia.',
+ 'Trigger automatically subtask time tracking' => 'Picu pengesanan subtugas secara otomatik',
+ 'Include closed tasks in the cumulative flow diagram' => 'Termasuk tugas yang ditutup pada diagram aliran kumulatif',
+ 'Current swimlane: %s' => 'Swimlane saat ini : %s',
+ 'Current column: %s' => 'Kolom saat ini : %s',
+ 'Current category: %s' => 'Kategori saat ini : %s',
+ 'no category' => 'tiada kategori',
+ 'Current assignee: %s' => 'Saat ini ditugaskan pada: %s',
+ 'not assigned' => 'Belum ditugaskan',
+ 'Author:' => 'Penulis:',
+ 'contributors' => 'Penggiat',
+ 'License:' => 'Lesen:',
+ 'License' => 'Lesen',
+ 'Enter the text below' => 'Masukkan teks di bawah',
+ 'Gantt chart for %s' => 'Carta Gantt untuk %s',
+ 'Sort by position' => 'Urutkan berdasarkan posisi',
+ 'Sort by date' => 'Urutkan berdasarkan tanggal',
+ 'Add task' => 'Tambah tugas',
+ 'Start date:' => 'Tanggal mulai:',
+ 'Due date:' => 'Batas waktu:',
+ 'There is no start date or due date for this task.' => 'Tiada tanggal mulai dan batas waktu untuk tugas ini.',
+ 'Moving or resizing a task will change the start and due date of the task.' => 'Memindahkan atau mengubah ukuran tugas anda akan mengubah tanggal mulai dan batas waktu dari tugas ini.',
+ 'There is no task in your project.' => 'Tiada tugas didalam projek anda.',
+ 'Gantt chart' => 'Carta Gantt',
+ 'People who are project managers' => 'Orang-orang yang menjadi pengurus projek',
+ 'People who are project members' => 'Orang-orang yang menjadi anggota projek',
+ 'NOK - Norwegian Krone' => 'NOK - Krone Norwegia',
+ 'Show this column' => 'Perlihatkan kolom ini',
+ 'Hide this column' => 'Sembunyikan kolom ini',
+ 'open file' => 'buka fail',
+ 'End date' => 'Waktu berakhir',
+ 'Users overview' => 'Ikhtisar pengguna',
+ 'Managers' => 'Pengurus',
+ 'Members' => 'Anggota',
+ 'Shared project' => 'projek bersama',
+ 'Project managers' => 'Pengurus projek',
+ 'Gantt chart for all projects' => 'Carta Gantt untuk kesemua projek',
+ 'Projects list' => 'Senarai projek',
+ 'Gantt chart for this project' => 'Carta Gantt untuk projek ini',
+ 'Project board' => 'Papan projek',
+ 'End date:' => 'Waktu berakhir :',
+ 'There is no start date or end date for this project.' => 'Tidak ada waktu mula atau waktu berakhir pada projek ini',
+ 'Projects Gantt chart' => 'projekkan carta Gantt',
+ 'Start date: %s' => 'Waktu mulai: %s',
+ 'End date: %s' => 'Waktu berakhir: %s',
+ 'Link type' => 'Jenis pautan',
+ 'Change task color when using a specific task link' => 'Rubah warna tugas ketika menggunakan Pautan tugas yang spesifik',
+ 'Task link creation or modification' => 'Pautan tugas pada penciptaan atau penyuntingan',
+ 'Login with my Gitlab Account' => 'Masuk menggunakan Akaun Gitlab saya',
+ 'Milestone' => 'Batu Tanda',
+ 'Gitlab Authentication' => 'Otentifikasi Gitlab',
+ 'Help on Gitlab authentication' => 'Bantuan pada otentifikasi Gitlab',
+ 'Gitlab Id' => 'Id Gitlab',
+ 'Gitlab Account' => 'Akaun Gitlab',
+ 'Link my Gitlab Account' => 'Hubungkan akaun Gitlab saya',
+ 'Unlink my Gitlab Account' => 'Putuskan akaun Gitlab saya',
+ 'Documentation: %s' => 'Dokumentasi : %s',
+ 'Switch to the Gantt chart view' => 'Beralih ke tampilan Carta Gantt',
+ 'Reset the search/filter box' => 'Tetap semula pencarian/saringan',
+ 'Documentation' => 'Dokumentasi',
+ 'Table of contents' => 'Isi kandungan',
+ 'Gantt' => 'Gantt',
+ // 'Author' => '',
+ // 'Version' => '',
+ // 'Plugins' => '',
+ // 'There is no plugin loaded.' => '',
+ // 'Set maximum column height' => '',
+ // 'Remove maximum column height' => '',
+ // 'My notifications' => '',
+ // 'Custom filters' => '',
+ // 'Your custom filter have been created successfully.' => '',
+ // 'Unable to create your custom filter.' => '',
+ // 'Custom filter removed successfully.' => '',
+ // 'Unable to remove this custom filter.' => '',
+ // 'Edit custom filter' => '',
+ // 'Your custom filter have been updated successfully.' => '',
+ // 'Unable to update custom filter.' => '',
+ // 'Web' => '',
+ // 'New attachment on task #%d: %s' => '',
+ // 'New comment on task #%d' => '',
+ // 'Comment updated on task #%d' => '',
+ // 'New subtask on task #%d' => '',
+ // 'Subtask updated on task #%d' => '',
+ // 'New task #%d: %s' => '',
+ // 'Task updated #%d' => '',
+ // 'Task #%d closed' => '',
+ // 'Task #%d opened' => '',
+ // 'Column changed for task #%d' => '',
+ // 'New position for task #%d' => '',
+ // 'Swimlane changed for task #%d' => '',
+ // 'Assignee changed on task #%d' => '',
+ // '%d overdue tasks' => '',
+ // 'Task #%d is overdue' => '',
+ // 'No new notifications.' => '',
+ // 'Mark all as read' => '',
+ // 'Mark as read' => '',
+ // 'Total number of tasks in this column across all swimlanes' => '',
+ // 'Collapse swimlane' => '',
+ // 'Expand swimlane' => '',
+ // 'Add a new filter' => '',
+ // 'Share with all project members' => '',
+ // 'Shared' => '',
+ // 'Owner' => '',
+ // 'Unread notifications' => '',
+ // 'My filters' => '',
+ // 'Notification methods:' => '',
+ // 'Import tasks from CSV file' => '',
+ // 'Unable to read your file' => '',
+ // '%d task(s) have been imported successfully.' => '',
+ // 'Nothing have been imported!' => '',
+ // 'Import users from CSV file' => '',
+ // '%d user(s) have been imported successfully.' => '',
+ // 'Comma' => '',
+ // 'Semi-colon' => '',
+ // 'Tab' => '',
+ // 'Vertical bar' => '',
+ // 'Double Quote' => '',
+ // 'Single Quote' => '',
+ // '%s attached a file to the task #%d' => '',
+ // 'There is no column or swimlane activated in your project!' => '',
+ // 'Append filter (instead of replacement)' => '',
+ // 'Append/Replace' => '',
+ // 'Append' => '',
+ // 'Replace' => '',
+ // 'There is no notification method registered.' => '',
+ // 'Import' => '',
+ // 'change sorting' => '',
+ // 'Tasks Importation' => '',
+ // 'Delimiter' => '',
+ // 'Enclosure' => '',
+ // 'CSV File' => '',
+ // 'Instructions' => '',
+ // 'Your file must use the predefined CSV format' => '',
+ // 'Your file must be encoded in UTF-8' => '',
+ // 'The first row must be the header' => '',
+ // 'Duplicates are not verified for you' => '',
+ // 'The due date must use the ISO format: YYYY-MM-DD' => '',
+ // 'Download CSV template' => '',
+ // 'No external integration registered.' => '',
+ // 'Duplicates are not imported' => '',
+ // 'Usernames must be lowercase and unique' => '',
+ // 'Passwords will be encrypted if present' => '',
+ // '%s attached a new file to the task %s' => '',
+ // 'Assign automatically a category based on a link' => '',
+ // 'BAM - Konvertible Mark' => '',
+ // 'Assignee Username' => '',
+ // 'Assignee Name' => '',
+ // 'Groups' => '',
+ // 'Members of %s' => '',
+ // 'New group' => '',
+ // 'Group created successfully.' => '',
+ // 'Unable to create your group.' => '',
+ // 'Edit group' => '',
+ // 'Group updated successfully.' => '',
+ // 'Unable to update your group.' => '',
+ // 'Add group member to "%s"' => '',
+ // 'Group member added successfully.' => '',
+ // 'Unable to add group member.' => '',
+ // 'Remove user from group "%s"' => '',
+ // 'User removed successfully from this group.' => '',
+ // 'Unable to remove this user from the group.' => '',
+ // 'Remove group' => '',
+ // 'Group removed successfully.' => '',
+ // 'Unable to remove this group.' => '',
+ // 'Project Permissions' => '',
+ // 'Manager' => '',
+ // 'Project Manager' => '',
+ // 'Project Member' => '',
+ // 'Project Viewer' => '',
+ // 'Your account is locked for %d minutes' => '',
+ // 'Invalid captcha' => '',
+ // 'The name must be unique' => '',
+ // 'View all groups' => '',
+ // 'View group members' => '',
+ // 'There is no user available.' => '',
+ // 'Do you really want to remove the user "%s" from the group "%s"?' => '',
+ // 'There is no group.' => '',
+ // 'External Id' => '',
+ // 'Add group member' => '',
+ // 'Do you really want to remove this group: "%s"?' => '',
+ // 'There is no user in this group.' => '',
+ // 'Remove this user' => '',
+ // 'Permissions' => '',
+ // 'Allowed Users' => '',
+ // 'No user have been allowed specifically.' => '',
+ // 'Role' => '',
+ // 'Enter user name...' => '',
+ // 'Allowed Groups' => '',
+ // 'No group have been allowed specifically.' => '',
+ // 'Group' => '',
+ // 'Group Name' => '',
+ // 'Enter group name...' => '',
+ 'Role:' => 'Peranan',
+ 'Project members' => 'Anggota projek',
+ // 'Compare hours for "%s"' => '',
+ // '%s mentioned you in the task #%d' => '',
+ // '%s mentioned you in a comment on the task #%d' => '',
+ // 'You were mentioned in the task #%d' => '',
+ // 'You were mentioned in a comment on the task #%d' => '',
+ // 'Mentioned' => '',
+ // 'Compare Estimated Time vs Actual Time' => '',
+ // 'Estimated hours: ' => '',
+ // 'Actual hours: ' => '',
+ // 'Hours Spent' => '',
+ // 'Hours Estimated' => '',
+ // 'Estimated Time' => '',
+ // 'Actual Time' => '',
+ // 'Estimated vs actual time' => '',
+ // 'RUB - Russian Ruble' => '',
+ // 'Assign the task to the person who does the action when the column is changed' => '',
+ // 'Close a task in a specific column' => '',
+ // 'Time-based One-time Password Algorithm' => '',
+ // 'Two-Factor Provider: ' => '',
+ // 'Disable two-factor authentication' => '',
+ // 'Enable two-factor authentication' => '',
+ // 'There is no integration registered at the moment.' => '',
+ // 'Password Reset for Kanboard' => '',
+ // 'Forgot password?' => '',
+ // 'Enable "Forget Password"' => '',
+ // 'Password Reset' => '',
+ // 'New password' => '',
+ // 'Change Password' => '',
+ // 'To reset your password click on this link:' => '',
+ // 'Last Password Reset' => '',
+ //'The password has never been reinitialized.' => 'Kata laluan tidak pernah ',
+ 'Creation' => 'Ciptaan',
+ 'Expiration' => 'Jangka hayat',
+ 'Password reset history' => 'Sirah tetap semula kata laluan',
+);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index b1652dd9..6b387bf2 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -1064,38 +1064,38 @@ return array(
'Enter group name...' => 'Escreva o nome do Grupo',
'Role:' => 'Função:',
'Project members' => 'Membros do projecto',
- // 'Compare hours for "%s"' => '',
- // '%s mentioned you in the task #%d' => '',
- // '%s mentioned you in a comment on the task #%d' => '',
- // 'You were mentioned in the task #%d' => '',
- // 'You were mentioned in a comment on the task #%d' => '',
- // 'Mentioned' => '',
- // 'Compare Estimated Time vs Actual Time' => '',
- // 'Estimated hours: ' => '',
- // 'Actual hours: ' => '',
- // 'Hours Spent' => '',
- // 'Hours Estimated' => '',
- // 'Estimated Time' => '',
- // 'Actual Time' => '',
- // 'Estimated vs actual time' => '',
- // 'RUB - Russian Ruble' => '',
- // 'Assign the task to the person who does the action when the column is changed' => '',
- // 'Close a task in a specific column' => '',
- // 'Time-based One-time Password Algorithm' => '',
- // 'Two-Factor Provider: ' => '',
- // 'Disable two-factor authentication' => '',
- // 'Enable two-factor authentication' => '',
- // 'There is no integration registered at the moment.' => '',
- // 'Password Reset for Kanboard' => '',
- // 'Forgot password?' => '',
- // 'Enable "Forget Password"' => '',
- // 'Password Reset' => '',
- // 'New password' => '',
- // 'Change Password' => '',
- // 'To reset your password click on this link:' => '',
- // 'Last Password Reset' => '',
- // 'The password has never been reinitialized.' => '',
- // 'Creation' => '',
- // 'Expiration' => '',
- // 'Password reset history' => '',
+ 'Compare hours for "%s"' => 'Comparar horas para "%s"',
+ '%s mentioned you in the task #%d' => '%s mencionou-te na tarefa #%d',
+ '%s mentioned you in a comment on the task #%d' => '%s mencionou-te num comentário na tarefa #%d',
+ 'You were mentioned in the task #%d' => 'Foi mencionado na tarefa #%d',
+ 'You were mentioned in a comment on the task #%d' => 'Foi mencionado num comentário na tarefa #%d',
+ 'Mentioned' => 'Mencionado',
+ 'Compare Estimated Time vs Actual Time' => 'Comparar Tempo Estimado vs Tempo Real',
+ 'Estimated hours: ' => 'Horas estimadas: ',
+ 'Actual hours: ' => 'Horas reais: ',
+ 'Hours Spent' => 'Horas Gastas',
+ 'Hours Estimated' => 'Horas Estimadas',
+ 'Estimated Time' => 'Tempo Estimado',
+ 'Actual Time' => 'Tempo Real',
+ 'Estimated vs actual time' => 'Tempo estimado vs real',
+ 'RUB - Russian Ruble' => 'RUB - Rublo Russo',
+ 'Assign the task to the person who does the action when the column is changed' => 'Assignar a tarefa à pessoa que realiza a acção quando a coluna é alterada',
+ 'Close a task in a specific column' => 'Fechar tarefa numa coluna especifica',
+ 'Time-based One-time Password Algorithm' => 'Algoritmo de password para uso único baseado em tempo',
+ 'Two-Factor Provider: ' => 'Provedor de Dois Passos: ',
+ 'Disable two-factor authentication' => 'Desactivar autenticação de dois passos',
+ 'Enable two-factor authentication' => 'Activar autenticação de dois passos',
+ 'There is no integration registered at the moment.' => 'Não existe nenhuma integração registrada até ao momento.',
+ 'Password Reset for Kanboard' => 'Redefinir Password para Kanboard',
+ 'Forgot password?' => 'Esqueceu a password?',
+ 'Enable "Forget Password"' => 'Activar "Esqueceu a password"',
+ 'Password Reset' => 'Redefinir a Password',
+ 'New password' => 'Nova Password',
+ 'Change Password' => 'Alterar Password',
+ 'To reset your password click on this link:' => 'Para redefinir a sua password click nesta ligação:',
+ 'Last Password Reset' => 'Última Redefinição da Password',
+ 'The password has never been reinitialized.' => 'A password nunca foi redefinida.',
+ 'Creation' => 'Criação',
+ 'Expiration' => 'Expiração',
+ 'Password reset history' => 'Histórico da redefinição da password',
);
diff --git a/app/Model/Config.php b/app/Model/Config.php
index 0e9311f1..839a2fd4 100644
--- a/app/Model/Config.php
+++ b/app/Model/Config.php
@@ -80,6 +80,7 @@ class Config extends Setting
'fr_FR' => 'Français',
'it_IT' => 'Italiano',
'hu_HU' => 'Magyar',
+ 'my_MY' => 'Melayu',
'nl_NL' => 'Nederlands',
'nb_NO' => 'Norsk',
'pl_PL' => 'Polski',
diff --git a/app/Model/Project.php b/app/Model/Project.php
index 8a949ba6..63077348 100644
--- a/app/Model/Project.php
+++ b/app/Model/Project.php
@@ -2,8 +2,6 @@
namespace Kanboard\Model;
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
@@ -510,71 +508,4 @@ class Project extends Base
->eq('id', $project_id)
->save(array('is_public' => 0, 'token' => ''));
}
-
- /**
- * Common validation rules
- *
- * @access private
- * @return array
- */
- private function commonValidationRules()
- {
- return array(
- new Validators\Integer('id', t('This value must be an integer')),
- new Validators\Integer('is_active', t('This value must be an integer')),
- new Validators\Required('name', t('The project name is required')),
- new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
- new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50),
- new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
- new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10),
- new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) ,
- new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), self::TABLE),
- );
- }
-
- /**
- * Validate project 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)
- {
- if (! empty($values['identifier'])) {
- $values['identifier'] = strtoupper($values['identifier']);
- }
-
- $v = new Validator($values, $this->commonValidationRules());
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate project modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateModification(array $values)
- {
- if (! empty($values['identifier'])) {
- $values['identifier'] = strtoupper($values['identifier']);
- }
-
- $rules = array(
- new Validators\Required('id', t('This value is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
}
diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php
index 664e41e1..0e039bb3 100644
--- a/app/Model/Subtask.php
+++ b/app/Model/Subtask.php
@@ -4,11 +4,9 @@ namespace Kanboard\Model;
use PicoDb\Database;
use Kanboard\Event\SubtaskEvent;
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
/**
- * Subtask model
+ * Subtask Model
*
* @package model
* @author Frederic Guillot
@@ -451,90 +449,4 @@ class Subtask extends Base
}
});
}
-
- /**
- * 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)
- {
- $rules = array(
- new Validators\Required('task_id', t('The task id is required')),
- new Validators\Required('title', t('The title is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The subtask id is required')),
- new Validators\Required('task_id', t('The task id is required')),
- new Validators\Required('title', t('The title is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate API modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateApiModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The subtask id is required')),
- new Validators\Required('task_id', t('The task id is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Common validation rules
- *
- * @access private
- * @return array
- */
- private function commonValidationRules()
- {
- 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', 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')),
- new Validators\Numeric('time_spent', t('The time must be a numeric value')),
- );
- }
}
diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php
index df44985a..e5124e8e 100644
--- a/app/Model/Swimlane.php
+++ b/app/Model/Swimlane.php
@@ -2,9 +2,6 @@
namespace Kanboard\Model;
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-
/**
* Swimlanes
*
@@ -470,85 +467,4 @@ class Swimlane extends Base
return true;
}
-
- /**
- * 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)
- {
- $rules = array(
- new Validators\Required('project_id', t('The project id is required')),
- new Validators\Required('name', t('The name is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The id is required')),
- new Validators\Required('name', t('The name is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate default swimlane modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateDefaultModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The id is required')),
- new Validators\Required('default_swimlane', t('The name is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Common validation rules
- *
- * @access private
- * @return array
- */
- private function commonValidationRules()
- {
- return array(
- new Validators\Integer('id', t('The id must be an integer')),
- new Validators\Integer('project_id', t('The project id must be an integer')),
- new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50)
- );
- }
}
diff --git a/app/Model/TaskLink.php b/app/Model/TaskLink.php
index 1ac59203..87aae55e 100644
--- a/app/Model/TaskLink.php
+++ b/app/Model/TaskLink.php
@@ -2,8 +2,6 @@
namespace Kanboard\Model;
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
use Kanboard\Event\TaskLinkEvent;
/**
@@ -261,59 +259,4 @@ class TaskLink extends Base
return true;
}
-
- /**
- * Common validation rules
- *
- * @access private
- * @return array
- */
- private function commonValidationRules()
- {
- return array(
- new Validators\Required('task_id', t('Field required')),
- new Validators\Required('opposite_task_id', t('Field required')),
- new Validators\Required('link_id', t('Field required')),
- new Validators\NotEquals('opposite_task_id', 'task_id', t('A task cannot be linked to itself')),
- new Validators\Exists('opposite_task_id', t('This linked task id doesn\'t exists'), $this->db->getConnection(), Task::TABLE, 'id')
- );
- }
-
- /**
- * 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, $this->commonValidationRules());
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('Field required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
}
diff --git a/app/Model/User.php b/app/Model/User.php
index 50e9b310..ac0e7491 100644
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -3,9 +3,6 @@
namespace Kanboard\Model;
use PicoDb\Database;
-use SimpleValidator\Validator;
-use SimpleValidator\Validators;
-use Kanboard\Core\Session\SessionManager;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
@@ -369,132 +366,4 @@ class User extends Base
->eq('id', $user_id)
->save(array('token' => ''));
}
-
- /**
- * Common validation rules
- *
- * @access private
- * @return array
- */
- private function commonValidationRules()
- {
- return array(
- new Validators\MaxLength('role', t('The maximum length is %d characters', 25), 25),
- new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
- new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'),
- new Validators\Email('email', t('Email address invalid')),
- new Validators\Integer('is_ldap_user', t('This value must be an integer')),
- );
- }
-
- /**
- * Common password validation rules
- *
- * @access private
- * @return array
- */
- private function commonPasswordValidationRules()
- {
- return array(
- new Validators\Required('password', t('The password is required')),
- new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6),
- new Validators\Required('confirmation', t('The confirmation is required')),
- new Validators\Equals('password', 'confirmation', t('Passwords don\'t match')),
- );
- }
-
- /**
- * Validate user 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)
- {
- $rules = array(
- new Validators\Required('username', t('The username is required')),
- );
-
- if (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) {
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
- } else {
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules(), $this->commonPasswordValidationRules()));
- }
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate user modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The user id is required')),
- new Validators\Required('username', t('The username is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate user API modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validateApiModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The user id is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
-
- return array(
- $v->execute(),
- $v->getErrors()
- );
- }
-
- /**
- * Validate password modification
- *
- * @access public
- * @param array $values Form values
- * @return array $valid, $errors [0] = Success or not, [1] = List of errors
- */
- public function validatePasswordModification(array $values)
- {
- $rules = array(
- new Validators\Required('id', t('The user id is required')),
- new Validators\Required('current_password', t('The current password is required')),
- );
-
- $v = new Validator($values, array_merge($rules, $this->commonPasswordValidationRules()));
-
- if ($v->execute()) {
- if ($this->authenticationManager->passwordAuthentication($this->userSession->getUsername(), $values['current_password'], false)) {
- return array(true, array());
- } else {
- return array(false, array('current_password' => array(t('Wrong password'))));
- }
- }
-
- return array(false, $v->getErrors());
- }
}
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index e206ef68..bb9e757e 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -63,7 +63,6 @@ class ClassProvider implements ServiceProviderInterface
'TaskPermission',
'TaskPosition',
'TaskStatus',
- 'TaskValidator',
'TaskImport',
'TaskMetadata',
'Transition',
@@ -87,6 +86,12 @@ class ClassProvider implements ServiceProviderInterface
),
'Validator' => array(
'PasswordResetValidator',
+ 'ProjectValidator',
+ 'SubtaskValidator',
+ 'SwimlaneValidator',
+ 'TaskValidator',
+ 'TaskLinkValidator',
+ 'UserValidator',
),
'Core' => array(
'DateParser',
diff --git a/app/Template/subtask/show.php b/app/Template/subtask/show.php
index 283057f4..6945840f 100644
--- a/app/Template/subtask/show.php
+++ b/app/Template/subtask/show.php
@@ -13,7 +13,7 @@
<th><?= t('Assignee') ?></th>
<th><?= t('Time tracking') ?></th>
<?php if ($editable): ?>
- <th><?= t('Actions') ?></th>
+ <th class="column-5"></th>
<?php endif ?>
</tr>
<?php foreach ($subtasks as $subtask): ?>
@@ -61,6 +61,8 @@
</td>
<?php if ($editable): ?>
<td>
+ <div class="dropdown">
+ <a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<?php if ($subtask['position'] != $first_position): ?>
<li>
@@ -79,6 +81,7 @@
<?= $this->url->link(t('Remove'), 'subtask', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>
</li>
</ul>
+ </div>
</td>
<?php endif ?>
</tr>
@@ -87,7 +90,6 @@
<?php endif ?>
<?php if ($editable && $this->user->hasProjectAccess('subtask', 'save', $task['project_id'])): ?>
-
<?php if (empty($subtasks)): ?>
<div class="page-header">
<h2><?= t('Sub-Tasks') ?></h2>
diff --git a/app/Validator/Base.php b/app/Validator/Base.php
index 6c56e2fd..ba32a503 100644
--- a/app/Validator/Base.php
+++ b/app/Validator/Base.php
@@ -2,6 +2,8 @@
namespace Kanboard\Validator;
+use SimpleValidator\Validators;
+
/**
* Base Validator
*
@@ -33,4 +35,20 @@ class Base extends \Kanboard\Core\Base
return array($result, $errors);
}
+
+ /**
+ * Common password validation rules
+ *
+ * @access protected
+ * @return array
+ */
+ protected function commonPasswordValidationRules()
+ {
+ return array(
+ new Validators\Required('password', t('The password is required')),
+ new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6),
+ new Validators\Required('confirmation', t('The confirmation is required')),
+ new Validators\Equals('password', 'confirmation', t('Passwords don\'t match')),
+ );
+ }
}
diff --git a/app/Validator/PasswordResetValidator.php b/app/Validator/PasswordResetValidator.php
index 6f21cbca..baf2d8d7 100644
--- a/app/Validator/PasswordResetValidator.php
+++ b/app/Validator/PasswordResetValidator.php
@@ -35,12 +35,7 @@ class PasswordResetValidator extends Base
*/
public function validateModification(array $values)
{
- $v = new Validator($values, array(
- new Validators\Required('password', t('The password is required')),
- new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6),
- new Validators\Required('confirmation', t('The confirmation is required')),
- new Validators\Equals('password', 'confirmation', t('Passwords don\'t match')),
- ));
+ $v = new Validator($values, $this->commonPasswordValidationRules());
return array(
$v->execute(),
@@ -78,7 +73,6 @@ class PasswordResetValidator extends Base
*/
protected function validateCaptcha(array $values)
{
- $result = true;
$errors = array();
if (! isset($this->sessionStorage->captcha)) {
diff --git a/app/Validator/ProjectValidator.php b/app/Validator/ProjectValidator.php
new file mode 100644
index 00000000..53cb7a37
--- /dev/null
+++ b/app/Validator/ProjectValidator.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+use Kanboard\Model\Project;
+
+/**
+ * Project Validator
+ *
+ * @package validator
+ * @author Frederic Guillot
+ */
+class ProjectValidator extends Base
+{
+ /**
+ * Common validation rules
+ *
+ * @access private
+ * @return array
+ */
+ private function commonValidationRules()
+ {
+ return array(
+ new Validators\Integer('id', t('This value must be an integer')),
+ new Validators\Integer('is_active', t('This value must be an integer')),
+ new Validators\Required('name', t('The project name is required')),
+ new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
+ new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50),
+ new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
+ new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10),
+ new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) ,
+ new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), Project::TABLE),
+ );
+ }
+
+ /**
+ * Validate project 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)
+ {
+ if (! empty($values['identifier'])) {
+ $values['identifier'] = strtoupper($values['identifier']);
+ }
+
+ $v = new Validator($values, $this->commonValidationRules());
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate project modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateModification(array $values)
+ {
+ if (! empty($values['identifier'])) {
+ $values['identifier'] = strtoupper($values['identifier']);
+ }
+
+ $rules = array(
+ new Validators\Required('id', t('This value is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Validator/SubtaskValidator.php b/app/Validator/SubtaskValidator.php
new file mode 100644
index 00000000..1989b7f4
--- /dev/null
+++ b/app/Validator/SubtaskValidator.php
@@ -0,0 +1,101 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Subtask Validator
+ *
+ * @package validator
+ * @author Frederic Guillot
+ */
+class SubtaskValidator extends Base
+{
+ /**
+ * 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)
+ {
+ $rules = array(
+ new Validators\Required('task_id', t('The task id is required')),
+ new Validators\Required('title', t('The title is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The subtask id is required')),
+ new Validators\Required('task_id', t('The task id is required')),
+ new Validators\Required('title', t('The title is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate API modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateApiModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The subtask id is required')),
+ new Validators\Required('task_id', t('The task id is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Common validation rules
+ *
+ * @access private
+ * @return array
+ */
+ private function commonValidationRules()
+ {
+ 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', 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')),
+ new Validators\Numeric('time_spent', t('The time must be a numeric value')),
+ );
+ }
+}
diff --git a/app/Validator/SwimlaneValidator.php b/app/Validator/SwimlaneValidator.php
new file mode 100644
index 00000000..4cc780f9
--- /dev/null
+++ b/app/Validator/SwimlaneValidator.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+
+/**
+ * Swimlane Validator
+ *
+ * @package validator
+ * @author Frederic Guillot
+ */
+class SwimlaneValidator extends Base
+{
+ /**
+ * 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)
+ {
+ $rules = array(
+ new Validators\Required('project_id', t('The project id is required')),
+ new Validators\Required('name', t('The name is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The id is required')),
+ new Validators\Required('name', t('The name is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate default swimlane modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateDefaultModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The id is required')),
+ new Validators\Required('default_swimlane', t('The name is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Common validation rules
+ *
+ * @access private
+ * @return array
+ */
+ private function commonValidationRules()
+ {
+ return array(
+ new Validators\Integer('id', t('The id must be an integer')),
+ new Validators\Integer('project_id', t('The project id must be an integer')),
+ new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50)
+ );
+ }
+}
diff --git a/app/Validator/TaskLinkValidator.php b/app/Validator/TaskLinkValidator.php
new file mode 100644
index 00000000..c88c2b16
--- /dev/null
+++ b/app/Validator/TaskLinkValidator.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+use Kanboard\Model\Task;
+
+/**
+ * Task Link Validator
+ *
+ * @package validator
+ * @author Frederic Guillot
+ */
+class TaskLinkValidator extends Base
+{
+ /**
+ * Common validation rules
+ *
+ * @access private
+ * @return array
+ */
+ private function commonValidationRules()
+ {
+ return array(
+ new Validators\Required('task_id', t('Field required')),
+ new Validators\Required('opposite_task_id', t('Field required')),
+ new Validators\Required('link_id', t('Field required')),
+ new Validators\NotEquals('opposite_task_id', 'task_id', t('A task cannot be linked to itself')),
+ new Validators\Exists('opposite_task_id', t('This linked task id doesn\'t exists'), $this->db->getConnection(), Task::TABLE, 'id')
+ );
+ }
+
+ /**
+ * 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, $this->commonValidationRules());
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('Field required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/app/Model/TaskValidator.php b/app/Validator/TaskValidator.php
index 683cb0b1..c18a9761 100644
--- a/app/Model/TaskValidator.php
+++ b/app/Validator/TaskValidator.php
@@ -1,14 +1,14 @@
<?php
-namespace Kanboard\Model;
+namespace Kanboard\Validator;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
- * Task validator model
+ * Task Validator
*
- * @package model
+ * @package validator
* @author Frederic Guillot
*/
class TaskValidator extends Base
diff --git a/app/Validator/UserValidator.php b/app/Validator/UserValidator.php
new file mode 100644
index 00000000..d85d335f
--- /dev/null
+++ b/app/Validator/UserValidator.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Kanboard\Validator;
+
+use SimpleValidator\Validator;
+use SimpleValidator\Validators;
+use Kanboard\Model\User;
+
+/**
+ * User Validator
+ *
+ * @package validator
+ * @author Frederic Guillot
+ */
+class UserValidator extends Base
+{
+ /**
+ * Common validation rules
+ *
+ * @access private
+ * @return array
+ */
+ private function commonValidationRules()
+ {
+ return array(
+ new Validators\MaxLength('role', t('The maximum length is %d characters', 25), 25),
+ new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
+ new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), User::TABLE, 'id'),
+ new Validators\Email('email', t('Email address invalid')),
+ new Validators\Integer('is_ldap_user', t('This value must be an integer')),
+ );
+ }
+
+ /**
+ * Validate user 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)
+ {
+ $rules = array(
+ new Validators\Required('username', t('The username is required')),
+ );
+
+ if (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) {
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+ } else {
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules(), $this->commonPasswordValidationRules()));
+ }
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate user modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The user id is required')),
+ new Validators\Required('username', t('The username is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate user API modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateApiModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The user id is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+
+ /**
+ * Validate password modification
+ *
+ * @access public
+ * @param array $values Form values
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validatePasswordModification(array $values)
+ {
+ $rules = array(
+ new Validators\Required('id', t('The user id is required')),
+ new Validators\Required('current_password', t('The current password is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonPasswordValidationRules()));
+
+ if ($v->execute()) {
+ if ($this->authenticationManager->passwordAuthentication($this->userSession->getUsername(), $values['current_password'], false)) {
+ return array(true, array());
+ } else {
+ return array(false, array('current_password' => array(t('Wrong password'))));
+ }
+ }
+
+ return array(false, $v->getErrors());
+ }
+}