diff options
Diffstat (limited to 'app')
91 files changed, 3027 insertions, 2425 deletions
diff --git a/app/Api/Swimlane.php b/app/Api/Swimlane.php index fb40841f..13838d77 100644 --- a/app/Api/Swimlane.php +++ b/app/Api/Swimlane.php @@ -40,14 +40,18 @@ class Swimlane extends \Core\Base return $this->swimlane->getDefault($project_id); } - public function addSwimlane($project_id, $name) + public function addSwimlane($project_id, $name, $description = '') { - return $this->swimlane->create($project_id, $name); + return $this->swimlane->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description)); } - public function updateSwimlane($swimlane_id, $name) + public function updateSwimlane($swimlane_id, $name, $description = null) { - return $this->swimlane->rename($swimlane_id, $name); + $values = array('id' => $swimlane_id, 'name' => $name); + if (!is_null($description)) { + $values['description'] = $description; + } + return $this->swimlane->update($values); } public function removeSwimlane($project_id, $swimlane_id) diff --git a/app/Auth/Ldap.php b/app/Auth/Ldap.php index c1459b4e..0ccd09a4 100644 --- a/app/Auth/Ldap.php +++ b/app/Auth/Ldap.php @@ -20,6 +20,178 @@ class Ldap extends Base const AUTH_NAME = 'LDAP'; /** + * Get LDAP server name + * + * @access public + * @return string + */ + public function getLdapServer() + { + return LDAP_SERVER; + } + + /** + * Get LDAP server port + * + * @access public + * @return integer + */ + public function getLdapPort() + { + return LDAP_PORT; + } + + /** + * Get LDAP username (proxy auth) + * + * @access public + * @return string + */ + public function getLdapUsername() + { + return LDAP_USERNAME; + } + + /** + * Get LDAP password (proxy auth) + * + * @access public + * @return string + */ + public function getLdapPassword() + { + return LDAP_PASSWORD; + } + + /** + * Get LDAP Base DN + * + * @access public + * @return string + */ + public function getLdapBaseDn() + { + return LDAP_ACCOUNT_BASE; + } + + /** + * Get LDAP account id attribute + * + * @access public + * @return string + */ + public function getLdapAccountId() + { + return LDAP_ACCOUNT_ID; + } + + /** + * Get LDAP account email attribute + * + * @access public + * @return string + */ + public function getLdapAccountEmail() + { + return LDAP_ACCOUNT_EMAIL; + } + + /** + * Get LDAP account name attribute + * + * @access public + * @return string + */ + public function getLdapAccountName() + { + return LDAP_ACCOUNT_FULLNAME; + } + + /** + * Get LDAP account memberof attribute + * + * @access public + * @return string + */ + public function getLdapAccountMemberOf() + { + return LDAP_ACCOUNT_MEMBEROF; + } + + /** + * Get LDAP admin group DN + * + * @access public + * @return string + */ + public function getLdapGroupAdmin() + { + return LDAP_GROUP_ADMIN_DN; + } + + /** + * Get LDAP project admin group DN + * + * @access public + * @return string + */ + public function getLdapGroupProjectAdmin() + { + return LDAP_GROUP_PROJECT_ADMIN_DN; + } + + /** + * Get LDAP username pattern + * + * @access public + * @return string + */ + public function getLdapUserPattern($username) + { + return sprintf(LDAP_USER_PATTERN, $username); + } + + /** + * Return true if the LDAP username is case sensitive + * + * @access public + * @return boolean + */ + public function isLdapAccountCaseSensitive() + { + return LDAP_USERNAME_CASE_SENSITIVE; + } + + /** + * Return true if the automatic account creation is enabled + * + * @access public + * @return boolean + */ + public function isLdapAccountCreationEnabled() + { + return LDAP_ACCOUNT_CREATION; + } + + /** + * Ge the list of attributes to fetch when reading the LDAP user entry + * + * Must returns array with index that start at 0 otherwise ldap_search returns a warning "Array initialization wrong" + * + * @access public + * @return array + */ + public function getProfileAttributes() + { + return array_values(array_filter(array( + $this->getLdapAccountId(), + $this->getLdapAccountName(), + $this->getLdapAccountEmail(), + $this->getLdapAccountMemberOf() + ))); + } + + /** * Authenticate the user * * @access public @@ -29,7 +201,7 @@ class Ldap extends Base */ public function authenticate($username, $password) { - $username = LDAP_USERNAME_CASE_SENSITIVE ? $username : strtolower($username); + $username = $this->isLdapAccountCaseSensitive() ? $username : strtolower($username); $result = $this->findUser($username, $password); if (is_array($result)) { @@ -46,7 +218,7 @@ class Ldap extends Base else { // We create automatically a new user - if (LDAP_ACCOUNT_CREATION && $this->createUser($username, $result['name'], $result['email'])) { + if ($this->isLdapAccountCreationEnabled() && $this->user->create($result) !== false) { $user = $this->user->getByUsername($username); } else { @@ -65,28 +237,6 @@ class Ldap extends Base } /** - * Create a new local user after the LDAP authentication - * - * @access public - * @param string $username Username - * @param string $name Name of the user - * @param string $email Email address - * @return bool - */ - public function createUser($username, $name, $email) - { - $values = array( - 'username' => $username, - 'name' => $name, - 'email' => $email, - 'is_admin' => 0, - 'is_ldap_user' => 1, - ); - - return $this->user->create($values); - } - - /** * Find the user from the LDAP server * * @access public @@ -98,8 +248,8 @@ class Ldap extends Base { $ldap = $this->connect(); - if (is_resource($ldap) && $this->bind($ldap, $username, $password)) { - return $this->search($ldap, $username, $password); + if ($ldap !== false && $this->bind($ldap, $username, $password)) { + return $this->getProfile($ldap, $username, $password); } return false; @@ -108,13 +258,14 @@ class Ldap extends Base /** * LDAP connection * - * @access private - * @return resource $ldap LDAP connection + * @access public + * @return resource|boolean */ - private function connect() + public function connect() { if (! function_exists('ldap_connect')) { - die('The PHP LDAP extension is required'); + $this->logger->error('The PHP LDAP extension is required'); + return false; } // Skip SSL certificate verification @@ -122,10 +273,11 @@ class Ldap extends Base putenv('LDAPTLS_REQCERT=never'); } - $ldap = ldap_connect(LDAP_SERVER, LDAP_PORT); + $ldap = ldap_connect($this->getLdapServer(), $this->getLdapPort()); - if (! is_resource($ldap)) { - die('Unable to connect to the LDAP server: "'.LDAP_SERVER.'"'); + if ($ldap === false) { + $this->logger->error('Unable to connect to the LDAP server'); + return false; } ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); @@ -134,30 +286,32 @@ class Ldap extends Base ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, 1); if (LDAP_START_TLS && ! @ldap_start_tls($ldap)) { - die('Unable to use ldap_start_tls()'); + $this->logger->error('Unable to use ldap_start_tls()'); + return false; } return $ldap; } /** - * LDAP bind + * LDAP authentication * - * @access private - * @param resource $ldap LDAP connection - * @param string $username Username - * @param string $password Password + * @access public + * @param resource $ldap + * @param string $username + * @param string $password + * @param string $ldap_type * @return boolean */ - private function bind($ldap, $username, $password) + public function bind($ldap, $username, $password, $ldap_type = LDAP_BIND_TYPE) { - if (LDAP_BIND_TYPE === 'user') { - $ldap_username = sprintf(LDAP_USERNAME, $username); + if ($ldap_type === 'user') { + $ldap_username = $this->getLdapUserPattern($username); $ldap_password = $password; } - else if (LDAP_BIND_TYPE === 'proxy') { - $ldap_username = LDAP_USERNAME; - $ldap_password = LDAP_PASSWORD; + else if ($ldap_type === 'proxy') { + $ldap_username = $this->getLdapUsername(); + $ldap_password = $this->getLdapPassword(); } else { $ldap_username = null; @@ -172,118 +326,182 @@ class Ldap extends Base } /** - * LDAP user lookup + * Get LDAP user profile * - * @access private - * @param resource $ldap LDAP connection - * @param string $username Username - * @param string $password Password + * @access public + * @param resource $ldap + * @param string $username + * @param string $password * @return boolean|array */ - private function search($ldap, $username, $password) + public function getProfile($ldap, $username, $password) { - $sr = @ldap_search($ldap, LDAP_ACCOUNT_BASE, sprintf(LDAP_USER_PATTERN, $username), array(LDAP_ACCOUNT_FULLNAME, LDAP_ACCOUNT_EMAIL)); - - if ($sr === false) { + $entries = $this->executeQuery($ldap, $this->getLdapUserPattern($username)); + if ($entries === false) { return false; } - $info = ldap_get_entries($ldap, $sr); + if (@ldap_bind($ldap, $entries[0]['dn'], $password)) { + return $this->prepareProfile($ldap, $entries, $username); + } - // User not found - if (count($info) == 0 || $info['count'] == 0) { - return false; + return false; + } + + /** + * Build user profile from LDAP information + * + * @access public + * @param resource $ldap + * @param array $entries + * @param string $username + * @return boolean|array + */ + public function prepareProfile($ldap, array $entries, $username) + { + if ($this->getLdapAccountId() !== '') { + $username = $this->getEntry($entries, $this->getLdapAccountId(), $username); } - // We got our user - if (@ldap_bind($ldap, $info[0]['dn'], $password)) { + return array( + 'username' => $username, + 'name' => $this->getEntry($entries, $this->getLdapAccountName()), + 'email' => $this->getEntry($entries, $this->getLdapAccountEmail()), + 'is_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupAdmin()), + 'is_project_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupProjectAdmin()), + 'is_ldap_user' => 1, + ); + } - return array( - 'username' => $username, - 'name' => $this->getFromInfo($info, LDAP_ACCOUNT_FULLNAME), - 'email' => $this->getFromInfo($info, LDAP_ACCOUNT_EMAIL), - ); + /** + * Check group membership + * + * @access public + * @param array $group_entries + * @param string $group_dn + * @return boolean + */ + public function isMemberOf(array $group_entries, $group_dn) + { + if (! isset($group_entries['count']) || empty($group_dn)) { + return false; + } + + for ($i = 0; $i < $group_entries['count']; $i++) { + if ($group_entries[$i] === $group_dn) { + return true; + } } return false; } /** - * Retrieve info on LDAP user + * Retrieve info on LDAP user by username or email * - * @param string $username Username - * @param string $email Email address + * @access public + * @param string $username + * @param string $email + * @return boolean|array */ public function lookup($username = null, $email = null) { - $query = $this->getQuery($username, $email); - if ($query === false) { + $query = $this->getLookupQuery($username, $email); + if ($query === '') { return false; } - // Connect and attempt anonymous bind + // Connect and attempt anonymous or proxy binding $ldap = $this->connect(); - if (! is_resource($ldap) || ! $this->bind($ldap, null, null)) { + if ($ldap === false || ! $this->bind($ldap, null, null)) { return false; } // Try to find user - $sr = @ldap_search($ldap, LDAP_ACCOUNT_BASE, $query, array(LDAP_ACCOUNT_FULLNAME, LDAP_ACCOUNT_EMAIL, LDAP_ACCOUNT_ID)); - if ($sr === false) { + $entries = $this->executeQuery($ldap, $query); + if ($entries === false) { + return false; + } + + // User id not retrieved: LDAP_ACCOUNT_ID not properly configured + if (empty($username) && ! isset($entries[0][$this->getLdapAccountId()][0])) { return false; } - $info = ldap_get_entries($ldap, $sr); + return $this->prepareProfile($ldap, $entries, $username); + } - // User not found - if (count($info) == 0 || $info['count'] == 0) { + /** + * Execute LDAP query + * + * @access private + * @param resource $ldap + * @param string $query + * @return boolean|array + */ + private function executeQuery($ldap, $query) + { + $sr = ldap_search($ldap, $this->getLdapBaseDn(), $query, $this->getProfileAttributes()); + if ($sr === false) { return false; } - // User id not retrieved: LDAP_ACCOUNT_ID not properly configured - if (empty($username) && ! isset($info[0][LDAP_ACCOUNT_ID][0])) { + $entries = ldap_get_entries($ldap, $sr); + if ($entries === false || count($entries) === 0 || $entries['count'] == 0) { return false; } - return array( - 'username' => $this->getFromInfo($info, LDAP_ACCOUNT_ID, $username), - 'name' => $this->getFromInfo($info, LDAP_ACCOUNT_FULLNAME), - 'email' => $this->getFromInfo($info, LDAP_ACCOUNT_EMAIL, $email), - ); + return $entries; } /** * Get the LDAP query to find a user * - * @param string $username Username - * @param string $email Email address + * @access private + * @param string $username + * @param string $email + * @return string */ - private function getQuery($username, $email) + private function getLookupQuery($username, $email) { - if ($username && $email) { - return '(&('.sprintf(LDAP_USER_PATTERN, $username).')('.LDAP_ACCOUNT_EMAIL.'='.$email.'))'; + if (! empty($username) && ! empty($email)) { + return '(&('.$this->getLdapUserPattern($username).')('.$this->getLdapAccountEmail().'='.$email.'))'; } - else if ($username) { - return sprintf(LDAP_USER_PATTERN, $username); + else if (! empty($username)) { + return $this->getLdapUserPattern($username); } - else if ($email) { - return '('.LDAP_ACCOUNT_EMAIL.'='.$email.')'; - } - else { - return false; + else if (! empty($email)) { + return '('.$this->getLdapAccountEmail().'='.$email.')'; } + + return ''; } /** - * Return a value from the LDAP info + * Return one entry from a list of entries * - * @param array $info LDAP info - * @param string $key Key - * @param string $default Default value if key not set in entry + * @access private + * @param array $entries LDAP entries + * @param string $key Key + * @param string $default Default value if key not set in entry * @return string */ - private function getFromInfo($info, $key, $default = '') + private function getEntry(array $entries, $key, $default = '') + { + return isset($entries[0][$key][0]) ? $entries[0][$key][0] : $default; + } + + /** + * Return subset of entries + * + * @access private + * @param array $entries + * @param string $key + * @param array $default + * @return array + */ + private function getEntries(array $entries, $key, $default = array()) { - return isset($info[0][$key][0]) ? $info[0][$key][0] : $default; + return isset($entries[0][$key]) ? $entries[0][$key] : $default; } } diff --git a/app/Auth/ReverseProxy.php b/app/Auth/ReverseProxy.php index c8fd5eec..7818254c 100644 --- a/app/Auth/ReverseProxy.php +++ b/app/Auth/ReverseProxy.php @@ -28,7 +28,6 @@ class ReverseProxy extends Base public function authenticate() { if (isset($_SERVER[REVERSE_PROXY_USER_HEADER])) { - $login = $_SERVER[REVERSE_PROXY_USER_HEADER]; $user = $this->user->getByUsername($login); diff --git a/app/Controller/Board.php b/app/Controller/Board.php index 179c6b3c..a552b9cf 100644 --- a/app/Controller/Board.php +++ b/app/Controller/Board.php @@ -321,6 +321,18 @@ class Board extends Base } /** + * Display swimlane description in tooltip + * + * @access public + */ + public function swimlane() + { + $this->getProject(); + $swimlane = $this->swimlane->getById($this->request->getIntegerParam('swimlane_id')); + $this->response->html($this->template->render('board/tooltip_description', array('task' => $swimlane))); + } + + /** * Enable collapsed mode * * @access public diff --git a/app/Controller/Budget.php b/app/Controller/Budget.php deleted file mode 100644 index a2f7e0db..00000000 --- a/app/Controller/Budget.php +++ /dev/null @@ -1,135 +0,0 @@ -<?php - -namespace Controller; - -/** - * Budget - * - * @package controller - * @author Frederic Guillot - */ -class Budget extends Base -{ - /** - * Budget index page - * - * @access public - */ - public function index() - { - $project = $this->getProject(); - - $this->response->html($this->projectLayout('budget/index', array( - 'daily_budget' => $this->budget->getDailyBudgetBreakdown($project['id']), - 'project' => $project, - 'title' => t('Budget') - ), 'budget/sidebar')); - } - - /** - * Cost breakdown by users/subtasks/tasks - * - * @access public - */ - public function breakdown() - { - $project = $this->getProject(); - - $paginator = $this->paginator - ->setUrl('budget', 'breakdown', array('project_id' => $project['id'])) - ->setMax(30) - ->setOrder('start') - ->setDirection('DESC') - ->setQuery($this->budget->getSubtaskBreakdown($project['id'])) - ->calculate(); - - $this->response->html($this->projectLayout('budget/breakdown', array( - 'paginator' => $paginator, - 'project' => $project, - 'title' => t('Budget') - ), 'budget/sidebar')); - } - - /** - * Create budget lines - * - * @access public - */ - public function create(array $values = array(), array $errors = array()) - { - $project = $this->getProject(); - - if (empty($values)) { - $values['date'] = date('Y-m-d'); - } - - $this->response->html($this->projectLayout('budget/create', array( - 'lines' => $this->budget->getAll($project['id']), - 'values' => $values + array('project_id' => $project['id']), - 'errors' => $errors, - 'project' => $project, - 'title' => t('Budget lines') - ), 'budget/sidebar')); - } - - /** - * Validate and save a new budget - * - * @access public - */ - public function save() - { - $project = $this->getProject(); - - $values = $this->request->getValues(); - list($valid, $errors) = $this->budget->validateCreation($values); - - if ($valid) { - - if ($this->budget->create($values['project_id'], $values['amount'], $values['comment'], $values['date'])) { - $this->session->flash(t('The budget line have been created successfully.')); - $this->response->redirect($this->helper->url->to('budget', 'create', array('project_id' => $project['id']))); - } - else { - $this->session->flashError(t('Unable to create the budget line.')); - } - } - - $this->create($values, $errors); - } - - /** - * Confirmation dialog before removing a budget - * - * @access public - */ - public function confirm() - { - $project = $this->getProject(); - - $this->response->html($this->projectLayout('budget/remove', array( - 'project' => $project, - 'budget_id' => $this->request->getIntegerParam('budget_id'), - 'title' => t('Remove a budget line'), - ), 'budget/sidebar')); - } - - /** - * Remove a budget - * - * @access public - */ - public function remove() - { - $this->checkCSRFParam(); - $project = $this->getProject(); - - if ($this->budget->remove($this->request->getIntegerParam('budget_id'))) { - $this->session->flash(t('Budget line removed successfully.')); - } else { - $this->session->flashError(t('Unable to remove this budget line.')); - } - - $this->response->redirect($this->helper->url->to('budget', 'create', array('project_id' => $project['id']))); - } -} diff --git a/app/Controller/Doc.php b/app/Controller/Doc.php index 19644b84..f9f0a675 100644 --- a/app/Controller/Doc.php +++ b/app/Controller/Doc.php @@ -16,7 +16,7 @@ class Doc extends Base { $url = $this->helper->url; $data = file_get_contents($filename); - list($title,, $content) = explode("\n", $data, 3); + list($title,) = explode("\n", $data, 2); $replaceUrl = function (array $matches) use ($url) { return '('.$url->to('doc', 'show', array('file' => str_replace('.markdown', '', $matches[1]))).')'; @@ -32,16 +32,24 @@ class Doc extends Base public function show() { - $filename = $this->request->getStringParam('file', 'index'); + $page = $this->request->getStringParam('file', 'index'); - if (! preg_match('/^[a-z0-9\-]+/', $filename)) { - $filename = 'index'; + if (! preg_match('/^[a-z0-9\-]+/', $page)) { + $page = 'index'; } - $filename = __DIR__.'/../../doc/'.$filename.'.markdown'; + $filenames = array(__DIR__.'/../../doc/'.$page.'.markdown'); + $filename = __DIR__.'/../../doc/index.markdown'; - if (! file_exists($filename)) { - $filename = __DIR__.'/../../doc/index.markdown'; + if ($this->config->getCurrentLanguage() === 'fr_FR') { + array_unshift($filenames, __DIR__.'/../../doc/fr/'.$page.'.markdown'); + } + + foreach ($filenames as $file) { + if (file_exists($file)) { + $filename = $file; + break; + } } $this->response->html($this->template->layout('doc/show', $this->readFile($filename) + array( diff --git a/app/Controller/File.php b/app/Controller/File.php index f73a9de9..7b7c75ee 100644 --- a/app/Controller/File.php +++ b/app/Controller/File.php @@ -60,7 +60,7 @@ class File extends Base { $task = $this->getTask(); - if (! $this->file->upload($task['project_id'], $task['id'], 'files')) { + if (! $this->file->uploadFiles($task['project_id'], $task['id'], 'files')) { $this->session->flashError(t('Unable to upload the file.')); } @@ -76,14 +76,13 @@ class File extends Base { $task = $this->getTask(); $file = $this->file->getById($this->request->getIntegerParam('file_id')); - $filename = FILES_DIR.$file['path']; - if ($file['task_id'] == $task['id'] && file_exists($filename)) { - $this->response->forceDownload($file['name']); - $this->response->binary(file_get_contents($filename)); + if ($file['task_id'] != $task['id']) { + $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); + $this->response->forceDownload($file['name']); + $this->objectStorage->passthru($file['path']); } /** @@ -113,16 +112,13 @@ class File extends Base { $task = $this->getTask(); $file = $this->file->getById($this->request->getIntegerParam('file_id')); - $filename = FILES_DIR.$file['path']; - - if ($file['task_id'] == $task['id'] && file_exists($filename)) { - $metadata = getimagesize($filename); - if (isset($metadata['mime'])) { - $this->response->contentType($metadata['mime']); - readfile($filename); - } + if ($file['task_id'] != $task['id']) { + $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } + + $this->response->contentType($this->file->getImageMimeType($file['name'])); + $this->objectStorage->passthru($file['path']); } /** @@ -134,17 +130,13 @@ class File extends Base { $task = $this->getTask(); $file = $this->file->getById($this->request->getIntegerParam('file_id')); - $filename = FILES_DIR.$file['path']; - - if ($file['task_id'] == $task['id'] && file_exists($filename)) { - $this->response->contentType('image/jpeg'); - $this->file->generateThumbnail( - $filename, - $this->request->getIntegerParam('width'), - $this->request->getIntegerParam('height') - ); + if ($file['task_id'] != $task['id']) { + $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); } + + $this->response->contentType('image/jpeg'); + $this->objectStorage->passthru($this->file->getThumbnailPath($file['path'])); } /** diff --git a/app/Controller/Hourlyrate.php b/app/Controller/Hourlyrate.php deleted file mode 100644 index 19650ede..00000000 --- a/app/Controller/Hourlyrate.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php - -namespace Controller; - -/** - * Hourly Rate controller - * - * @package controller - * @author Frederic Guillot - */ -class Hourlyrate extends User -{ - /** - * Display rate and form - * - * @access public - */ - public function index(array $values = array(), array $errors = array()) - { - $user = $this->getUser(); - - $this->response->html($this->layout('hourlyrate/index', array( - 'rates' => $this->hourlyRate->getAllByUser($user['id']), - 'currencies_list' => $this->config->getCurrencies(), - 'values' => $values + array('user_id' => $user['id']), - 'errors' => $errors, - 'user' => $user, - ))); - } - - /** - * Validate and save a new rate - * - * @access public - */ - public function save() - { - $values = $this->request->getValues(); - list($valid, $errors) = $this->hourlyRate->validateCreation($values); - - if ($valid) { - - if ($this->hourlyRate->create($values['user_id'], $values['rate'], $values['currency'], $values['date_effective'])) { - $this->session->flash(t('Hourly rate created successfully.')); - $this->response->redirect($this->helper->url->to('hourlyrate', 'index', array('user_id' => $values['user_id']))); - } - else { - $this->session->flashError(t('Unable to save the hourly rate.')); - } - } - - $this->index($values, $errors); - } - - /** - * Confirmation dialag box to remove a row - * - * @access public - */ - public function confirm() - { - $user = $this->getUser(); - - $this->response->html($this->layout('hourlyrate/remove', array( - 'rate_id' => $this->request->getIntegerParam('rate_id'), - 'user' => $user, - ))); - } - - /** - * Remove a row - * - * @access public - */ - public function remove() - { - $this->checkCSRFParam(); - $user = $this->getUser(); - - if ($this->hourlyRate->remove($this->request->getIntegerParam('rate_id'))) { - $this->session->flash(t('Rate removed successfully.')); - } - else { - $this->session->flash(t('Unable to remove this rate.')); - } - - $this->response->redirect($this->helper->url->to('hourlyrate', 'index', array('user_id' => $user['id']))); - } -} diff --git a/app/Controller/Swimlane.php b/app/Controller/Swimlane.php index 054fa4ba..f92e9fe3 100644 --- a/app/Controller/Swimlane.php +++ b/app/Controller/Swimlane.php @@ -59,13 +59,12 @@ class Swimlane extends Base public function save() { $project = $this->getProject(); - $values = $this->request->getValues(); list($valid, $errors) = $this->swimlane->validateCreation($values); if ($valid) { - if ($this->swimlane->create($project['id'], $values['name'])) { + if ($this->swimlane->create($values)) { $this->session->flash(t('Your swimlane have been created successfully.')); $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); } @@ -134,8 +133,7 @@ class Swimlane extends Base list($valid, $errors) = $this->swimlane->validateModification($values); if ($valid) { - - if ($this->swimlane->rename($values['id'], $values['name'])) { + if ($this->swimlane->update($values)) { $this->session->flash(t('Swimlane updated successfully.')); $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id']))); } diff --git a/app/Controller/Taskcreation.php b/app/Controller/Taskcreation.php index ff25c5da..b9e9a33c 100644 --- a/app/Controller/Taskcreation.php +++ b/app/Controller/Taskcreation.php @@ -59,25 +59,29 @@ class Taskcreation extends Base list($valid, $errors) = $this->taskValidator->validateCreation($values); - if ($valid) { + if ($valid && $this->taskCreation->create($values)) { + $this->session->flash(t('Task created successfully.')); + $this->afterSave($project, $values); + } + else { + $this->session->flashError(t('Unable to create your task.')); + } - if ($this->taskCreation->create($values)) { - $this->session->flash(t('Task created successfully.')); + $this->create($values, $errors); + } - if (isset($values['another_task']) && $values['another_task'] == 1) { - unset($values['title']); - unset($values['description']); - $this->response->redirect($this->helper->url->to('taskcreation', 'create', $values)); - } - else { - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id']))); - } - } - else { - $this->session->flashError(t('Unable to create your task.')); + private function afterSave(array $project, array &$values) + { + if (isset($values['another_task']) && $values['another_task'] == 1) { + unset($values['title']); + unset($values['description']); + + if (! $this->request->isAjax()) { + $this->response->redirect($this->helper->url->to('taskcreation', 'create', $values)); } } - - $this->create($values, $errors); + else { + $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id']))); + } } } diff --git a/app/Controller/Taskmodification.php b/app/Controller/Taskmodification.php index 56d2b9f9..638af594 100644 --- a/app/Controller/Taskmodification.php +++ b/app/Controller/Taskmodification.php @@ -126,11 +126,13 @@ class Taskmodification extends Base ); if ($ajax) { - $this->response->html($this->template->render('task_modification/edit_task', $params)); + $html = $this->template->render('task_modification/edit_task', $params); } else { - $this->response->html($this->taskLayout('task_modification/edit_task', $params)); + $html = $this->taskLayout('task_modification/edit_task', $params); } + + $this->response->html($html); } /** @@ -145,24 +147,20 @@ class Taskmodification extends Base list($valid, $errors) = $this->taskValidator->validateModification($values); - if ($valid) { - - if ($this->taskModification->update($values)) { - $this->session->flash(t('Task updated successfully.')); + if ($valid && $this->taskModification->update($values)) { + $this->session->flash(t('Task updated successfully.')); - if ($this->request->getIntegerParam('ajax')) { - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id']))); - } - else { - $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']))); - } + if ($this->request->isAjax()) { + $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id']))); } else { - $this->session->flashError(t('Unable to update your task.')); + $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']))); } } - - $this->edit($values, $errors); + else { + $this->session->flashError(t('Unable to update your task.')); + $this->edit($values, $errors); + } } /** diff --git a/app/Core/Base.php b/app/Core/Base.php index 3db0cf74..5ed8f40a 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -35,7 +35,6 @@ use Pimple\Container; * @property \Model\Action $action * @property \Model\Authentication $authentication * @property \Model\Board $board - * @property \Model\Budget $budget * @property \Model\Category $category * @property \Model\Color $color * @property \Model\Comment $comment @@ -43,7 +42,6 @@ use Pimple\Container; * @property \Model\Currency $currency * @property \Model\DateParser $dateParser * @property \Model\File $file - * @property \Model\HourlyRate $hourlyRate * @property \Model\LastLogin $lastLogin * @property \Model\Link $link * @property \Model\Notification $notification diff --git a/app/Core/ObjectStorage/FileStorage.php b/app/Core/ObjectStorage/FileStorage.php new file mode 100644 index 00000000..66c62334 --- /dev/null +++ b/app/Core/ObjectStorage/FileStorage.php @@ -0,0 +1,150 @@ +<?php + +namespace Core\ObjectStorage; + +/** + * Local File Storage + * + * @package ObjectStorage + * @author Frederic Guillot + */ +class FileStorage implements ObjectStorageInterface +{ + /** + * Base path + * + * @access private + * @var string + */ + private $path = ''; + + /** + * Constructor + * + * @access public + * @param string $path + */ + public function __construct($path) + { + $this->path = $path; + } + + /** + * Fetch object contents + * + * @access public + * @param string $key + * @return string + */ + public function get($key) + { + $filename = $this->path.DIRECTORY_SEPARATOR.$key; + + if (! file_exists($filename)) { + throw new ObjectStorageException('File not found: '.$filename); + } + + return file_get_contents($filename); + } + + /** + * Save object + * + * @access public + * @param string $key + * @param string $blob + * @return string + */ + public function put($key, &$blob) + { + $this->createFolder($key); + + if (file_put_contents($this->path.DIRECTORY_SEPARATOR.$key, $blob) === false) { + throw new ObjectStorageException('Unable to write the file: '.$this->path.DIRECTORY_SEPARATOR.$key); + } + } + + /** + * Output directly object content + * + * @access public + * @param string $key + */ + public function passthru($key) + { + $filename = $this->path.DIRECTORY_SEPARATOR.$key; + + if (! file_exists($filename)) { + throw new ObjectStorageException('File not found: '.$filename); + } + + return readfile($filename); + } + + /** + * Move local file to object storage + * + * @access public + * @param string $filename + * @param string $key + * @return boolean + */ + public function moveFile($src_filename, $key) + { + $this->createFolder($key); + $dst_filename = $this->path.DIRECTORY_SEPARATOR.$key; + + if (! rename($src_filename, $dst_filename)) { + throw new ObjectStorageException('Unable to move the file: '.$src_filename.' to '.$dst_filename); + } + + return true; + } + + /** + * Move uploaded file to object storage + * + * @access public + * @param string $filename + * @param string $key + * @return boolean + */ + public function moveUploadedFile($filename, $key) + { + $this->createFolder($key); + return move_uploaded_file($filename, $this->path.DIRECTORY_SEPARATOR.$key); + } + + /** + * Remove object + * + * @access public + * @param string $key + * @return boolean + */ + public function remove($key) + { + $filename = $this->path.DIRECTORY_SEPARATOR.$key; + + if (file_exists($filename)) { + return unlink($filename); + } + + return false; + } + + /** + * Create object folder + * + * @access private + * @param string $key + */ + private function createFolder($key) + { + $folder = $this->path.DIRECTORY_SEPARATOR.dirname($key); + + if (! is_dir($folder) && ! mkdir($folder, 0755, true)) { + throw new ObjectStorageException('Unable to create folder: '.$folder); + } + } +} diff --git a/app/Core/ObjectStorage/ObjectStorageException.php b/app/Core/ObjectStorage/ObjectStorageException.php new file mode 100644 index 00000000..e89aeb25 --- /dev/null +++ b/app/Core/ObjectStorage/ObjectStorageException.php @@ -0,0 +1,9 @@ +<?php + +namespace Core\ObjectStorage; + +use Exception; + +class ObjectStorageException extends Exception +{ +} diff --git a/app/Core/ObjectStorage/ObjectStorageInterface.php b/app/Core/ObjectStorage/ObjectStorageInterface.php new file mode 100644 index 00000000..5440cf2b --- /dev/null +++ b/app/Core/ObjectStorage/ObjectStorageInterface.php @@ -0,0 +1,68 @@ +<?php + +namespace Core\ObjectStorage; + +/** + * Object Storage Interface + * + * @package ObjectStorage + * @author Frederic Guillot + */ +interface ObjectStorageInterface +{ + /** + * Fetch object contents + * + * @access public + * @param string $key + * @return string + */ + public function get($key); + + /** + * Save object + * + * @access public + * @param string $key + * @param string $blob + * @return string + */ + public function put($key, &$blob); + + /** + * Output directly object content + * + * @access public + * @param string $key + */ + public function passthru($key); + + /** + * Move local file to object storage + * + * @access public + * @param string $filename + * @param string $key + * @return boolean + */ + public function moveFile($filename, $key); + + /** + * Move uploaded file to object storage + * + * @access public + * @param string $filename + * @param string $key + * @return boolean + */ + public function moveUploadedFile($filename, $key); + + /** + * Remove object + * + * @access public + * @param string $key + * @return boolean + */ + public function remove($key); +} diff --git a/app/Core/PluginBase.php b/app/Core/PluginBase.php new file mode 100644 index 00000000..457afa03 --- /dev/null +++ b/app/Core/PluginBase.php @@ -0,0 +1,47 @@ +<?php + +namespace Core; + +/** + * Plugin Base class + * + * @package core + * @author Frederic Guillot + */ +abstract class PluginBase extends Base +{ + /** + * Method called for each request + * + * @abstract + * @access public + */ + abstract public function initialize(); + + /** + * Returns all classes that needs to be stored in the DI container + * + * @access public + * @return array + */ + public function getClasses() + { + return array(); + } + + /** + * Listen on internal events + * + * @access public + * @param string $event + * @param callable $callback + */ + public function on($event, $callback) + { + $container = $this->container; + + $this->container['dispatcher']->addListener($event, function() use ($container, $callback) { + call_user_func($callback, $container); + }); + } +} diff --git a/app/Core/PluginLoader.php b/app/Core/PluginLoader.php new file mode 100644 index 00000000..c7c254f7 --- /dev/null +++ b/app/Core/PluginLoader.php @@ -0,0 +1,137 @@ +<?php + +namespace Core; + +use DirectoryIterator; +use PDOException; + +/** + * Plugin Loader + * + * @package core + * @author Frederic Guillot + */ +class PluginLoader extends Base +{ + /** + * Schema version table for plugins + * + * @var string + */ + const TABLE_SCHEMA = 'plugin_schema_versions'; + + /** + * Scan plugin folder and load plugins + * + * @access public + */ + public function scan() + { + if (file_exists(__DIR__.'/../../plugins')) { + $dir = new DirectoryIterator(__DIR__.'/../../plugins'); + + foreach ($dir as $fileinfo) { + if (! $fileinfo->isDot() && $fileinfo->isDir()) { + $plugin = $fileinfo->getFilename(); + $this->loadSchema($plugin); + $this->load($plugin); + } + } + } + } + + /** + * Load plugin + * + * @access public + */ + public function load($plugin) + { + $class = '\Plugin\\'.$plugin.'\\Plugin'; + $instance = new $class($this->container); + + Tool::buildDic($this->container, $instance->getClasses()); + + $instance->initialize(); + } + + /** + * Load plugin schema + * + * @access public + * @param string $plugin + */ + public function loadSchema($plugin) + { + $filename = __DIR__.'/../../plugins/'.$plugin.'/Schema/'.ucfirst(DB_DRIVER).'.php'; + + if (file_exists($filename)) { + require($filename); + $this->migrateSchema($plugin); + } + } + + /** + * Execute plugin schema migrations + * + * @access public + * @param string $plugin + */ + public function migrateSchema($plugin) + { + $last_version = constant('\Plugin\\'.$plugin.'\Schema\VERSION'); + $current_version = $this->getSchemaVersion($plugin); + + try { + + $this->db->startTransaction(); + $this->db->getDriver()->disableForeignKeys(); + + for ($i = $current_version + 1; $i <= $last_version; $i++) { + $function_name = '\Plugin\\'.$plugin.'\Schema\version_'.$i; + + if (function_exists($function_name)) { + call_user_func($function_name, $this->db->getConnection()); + } + } + + $this->db->getDriver()->enableForeignKeys(); + $this->db->closeTransaction(); + $this->setSchemaVersion($plugin, $i - 1); + } + catch (PDOException $e) { + $this->db->cancelTransaction(); + $this->db->getDriver()->enableForeignKeys(); + die('Unable to migrate schema for the plugin: '.$plugin.' => '.$e->getMessage()); + } + } + + /** + * Get current plugin schema version + * + * @access public + * @param string $plugin + * @return integer + */ + public function getSchemaVersion($plugin) + { + return (int) $this->db->table(self::TABLE_SCHEMA)->eq('plugin', strtolower($plugin))->findOneColumn('version'); + } + + /** + * Save last plugin schema version + * + * @access public + * @param string $plugin + * @param integer $version + * @return boolean + */ + public function setSchemaVersion($plugin, $version) + { + $dictionary = array( + strtolower($plugin) => $version + ); + + return $this->db->getDriver()->upsert(self::TABLE_SCHEMA, 'plugin', 'version', $dictionary); + } +} diff --git a/app/Core/Response.php b/app/Core/Response.php index d42a8f1e..f8ca015c 100644 --- a/app/Core/Response.php +++ b/app/Core/Response.php @@ -66,7 +66,13 @@ class Response */ public function redirect($url) { - header('Location: '.$url); + if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') { + header('X-Ajax-Redirect: '.$url); + } + else { + header('Location: '.$url); + } + exit; } diff --git a/app/Core/Router.php b/app/Core/Router.php index 6e7576d6..36bbfd55 100644 --- a/app/Core/Router.php +++ b/app/Core/Router.php @@ -213,49 +213,17 @@ class Router extends Base if (! empty($_GET['controller']) && ! empty($_GET['action'])) { $controller = $this->sanitize($_GET['controller'], 'app'); $action = $this->sanitize($_GET['action'], 'index'); + $plugin = ! empty($_GET['plugin']) ? $this->sanitize($_GET['plugin'], '') : ''; } else { - list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string)); + list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string)); // TODO: add plugin for routes + $plugin = ''; } - return $this->load( - __DIR__.'/../Controller/'.ucfirst($controller).'.php', - $controller, - '\Controller\\'.ucfirst($controller), - $action - ); - } - - /** - * Load a controller and execute the action - * - * @access private - * @param string $filename - * @param string $controller - * @param string $class - * @param string $method - * @return bool - */ - private function load($filename, $controller, $class, $method) - { - if (file_exists($filename)) { - - require $filename; - - if (! method_exists($class, $method)) { - return false; - } - - $this->action = $method; - $this->controller = $controller; - - $instance = new $class($this->container); - $instance->beforeAction($controller, $method); - $instance->$method(); - - return true; - } + $class = empty($plugin) ? '\Controller\\'.ucfirst($controller) : '\Plugin\\'.ucfirst($plugin).'\Controller\\'.ucfirst($controller); - return false; + $instance = new $class($this->container); + $instance->beforeAction($controller, $action); + $instance->$action(); } } diff --git a/app/Core/Template.php b/app/Core/Template.php index ba869ee6..b75f7da1 100644 --- a/app/Core/Template.php +++ b/app/Core/Template.php @@ -13,11 +13,12 @@ use LogicException; class Template extends Helper { /** - * Template path + * List of template overrides * - * @var string + * @access private + * @var array */ - const PATH = 'app/Template/'; + private $overrides = array(); /** * Render a template @@ -33,16 +34,10 @@ class Template extends Helper */ public function render($__template_name, array $__template_args = array()) { - $__template_file = self::PATH.$__template_name.'.php'; - - if (! file_exists($__template_file)) { - throw new LogicException('Unable to load the template: "'.$__template_name.'"'); - } - extract($__template_args); ob_start(); - include $__template_file; + include $this->getTemplateFile($__template_name); return ob_get_clean(); } @@ -62,4 +57,41 @@ class Template extends Helper $template_args + array('content_for_layout' => $this->render($template_name, $template_args)) ); } + + /** + * Define a new template override + * + * @access public + * @param string $original_template + * @param string $new_template + */ + public function setTemplateOverride($original_template, $new_template) + { + $this->overrides[$original_template] = $new_template; + } + + /** + * Find template filename + * + * Core template name: 'task/show' + * Plugin template name: 'myplugin:task/show' + * + * @access public + * @param string $template_name + * @return string + */ + public function getTemplateFile($template_name) + { + $template_name = isset($this->overrides[$template_name]) ? $this->overrides[$template_name] : $template_name; + + if (strpos($template_name, ':') !== false) { + list($plugin, $template) = explode(':', $template_name); + $path = __DIR__.'/../../plugins/'.ucfirst($plugin).'/Template/'.$template.'.php'; + } + else { + $path = __DIR__.'/../Template/'.$template_name.'.php'; + } + + return $path; + } } diff --git a/app/Core/Tool.php b/app/Core/Tool.php index 84e42ba8..887c8fb3 100644 --- a/app/Core/Tool.php +++ b/app/Core/Tool.php @@ -2,6 +2,8 @@ namespace Core; +use Pimple\Container; + /** * Tool class * @@ -23,7 +25,6 @@ class Tool $fp = fopen($filename, 'w'); if (is_resource($fp)) { - foreach ($rows as $fields) { fputcsv($fp, $fields); } @@ -51,4 +52,102 @@ class Tool return $identifier; } + + /** + * Build dependency injection container from an array + * + * @static + * @access public + * @param Container $container + * @param array $namespaces + */ + public static function buildDIC(Container $container, array $namespaces) + { + foreach ($namespaces as $namespace => $classes) { + foreach ($classes as $name) { + $class = '\\'.$namespace.'\\'.$name; + $container[lcfirst($name)] = function ($c) use ($class) { + return new $class($c); + }; + } + } + } + + /** + * Generate a jpeg thumbnail from an image + * + * @static + * @access public + * @param string $src_file Source file image + * @param string $dst_file Destination file image + * @param integer $resize_width Desired image width + * @param integer $resize_height Desired image height + */ + public static function generateThumbnail($src_file, $dst_file, $resize_width = 250, $resize_height = 100) + { + $metadata = getimagesize($src_file); + $src_width = $metadata[0]; + $src_height = $metadata[1]; + $dst_y = 0; + $dst_x = 0; + + if (empty($metadata['mime'])) { + return; + } + + if ($resize_width == 0 && $resize_height == 0) { + $resize_width = 100; + $resize_height = 100; + } + + if ($resize_width > 0 && $resize_height == 0) { + $dst_width = $resize_width; + $dst_height = floor($src_height * ($resize_width / $src_width)); + $dst_image = imagecreatetruecolor($dst_width, $dst_height); + } + elseif ($resize_width == 0 && $resize_height > 0) { + $dst_width = floor($src_width * ($resize_height / $src_height)); + $dst_height = $resize_height; + $dst_image = imagecreatetruecolor($dst_width, $dst_height); + } + else { + + $src_ratio = $src_width / $src_height; + $resize_ratio = $resize_width / $resize_height; + + if ($src_ratio <= $resize_ratio) { + $dst_width = $resize_width; + $dst_height = floor($src_height * ($resize_width / $src_width)); + + $dst_y = ($dst_height - $resize_height) / 2 * (-1); + } + else { + $dst_width = floor($src_width * ($resize_height / $src_height)); + $dst_height = $resize_height; + + $dst_x = ($dst_width - $resize_width) / 2 * (-1); + } + + $dst_image = imagecreatetruecolor($resize_width, $resize_height); + } + + switch ($metadata['mime']) { + case 'image/jpeg': + case 'image/jpg': + $src_image = imagecreatefromjpeg($src_file); + break; + case 'image/png': + $src_image = imagecreatefrompng($src_file); + break; + case 'image/gif': + $src_image = imagecreatefromgif($src_file); + break; + default: + return; + } + + imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height); + imagejpeg($dst_image, $dst_file); + imagedestroy($dst_image); + } } diff --git a/app/Core/Translator.php b/app/Core/Translator.php index e3d19692..e9aa1f3f 100644 --- a/app/Core/Translator.php +++ b/app/Core/Translator.php @@ -15,7 +15,7 @@ class Translator * * @var string */ - const PATH = 'app/Locale/'; + const PATH = 'app/Locale'; /** * Locale @@ -196,18 +196,27 @@ class Translator * @static * @access public * @param string $language Locale code: fr_FR + * @param string $path Locale folder */ - public static function load($language) + public static function load($language, $path = self::PATH) { setlocale(LC_TIME, $language.'.UTF-8', $language); - $filename = self::PATH.$language.DIRECTORY_SEPARATOR.'translations.php'; + $filename = $path.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'translations.php'; if (file_exists($filename)) { - self::$locales = require $filename; - } - else { - self::$locales = array(); + self::$locales = array_merge(self::$locales, require($filename)); } } + + /** + * Clear locales stored in memory + * + * @static + * @access public + */ + public static function unload() + { + self::$locales = array(); + } } diff --git a/app/Helper/App.php b/app/Helper/App.php index e5ebefcb..5fb89afe 100644 --- a/app/Helper/App.php +++ b/app/Helper/App.php @@ -67,9 +67,11 @@ class App extends \Core\Base if (isset($this->session['flash_message'])) { $html = '<div class="alert alert-success alert-fade-out">'.$this->helper->e($this->session['flash_message']).'</div>'; unset($this->session['flash_message']); + unset($this->session['flash_error_message']); } else if (isset($this->session['flash_error_message'])) { $html = '<div class="alert alert-error">'.$this->helper->e($this->session['flash_error_message']).'</div>'; + unset($this->session['flash_message']); unset($this->session['flash_error_message']); } diff --git a/app/Helper/Hook.php b/app/Helper/Hook.php new file mode 100644 index 00000000..77756757 --- /dev/null +++ b/app/Helper/Hook.php @@ -0,0 +1,49 @@ +<?php + +namespace Helper; + +/** + * Template Hook helpers + * + * @package helper + * @author Frederic Guillot + */ +class Hook extends \Core\Base +{ + private $hooks = array(); + + /** + * Render all attached hooks + * + * @access public + * @param string $hook + * @param array $variables + * @return string + */ + public function render($hook, array $variables = array()) + { + $buffer = ''; + + foreach ($this->hooks as $name => $template) { + if ($hook === $name) { + $buffer .= $this->template->render($template, $variables); + } + } + + return $buffer; + } + + /** + * Attach a template to a hook + * + * @access public + * @param string $hook + * @param string $template + * @return \Helper\Hook + */ + public function attach($hook, $template) + { + $this->hooks[$hook] = $template; + return $this; + } +} diff --git a/app/Integration/Mailgun.php b/app/Integration/Mailgun.php index 1451b211..076c311a 100644 --- a/app/Integration/Mailgun.php +++ b/app/Integration/Mailgun.php @@ -2,7 +2,6 @@ namespace Integration; -use HTML_To_Markdown; use Core\Tool; /** @@ -76,8 +75,7 @@ class Mailgun extends \Core\Base // Get the Markdown contents if (! empty($payload['stripped-html'])) { - $markdown = new HTML_To_Markdown($payload['stripped-html'], array('strip_tags' => true)); - $description = $markdown->output(); + $description = $this->htmlConverter->convert($payload['stripped-html']); } else if (! empty($payload['stripped-text'])) { $description = $payload['stripped-text']; diff --git a/app/Integration/Postmark.php b/app/Integration/Postmark.php index dbb70aee..05bdf58b 100644 --- a/app/Integration/Postmark.php +++ b/app/Integration/Postmark.php @@ -2,8 +2,6 @@ namespace Integration; -use HTML_To_Markdown; - /** * Postmark integration * @@ -76,8 +74,7 @@ class Postmark extends \Core\Base // Get the Markdown contents if (! empty($payload['HtmlBody'])) { - $markdown = new HTML_To_Markdown($payload['HtmlBody'], array('strip_tags' => true)); - $description = $markdown->output(); + $description = $this->htmlConverter->convert($payload['HtmlBody']); } else if (! empty($payload['TextBody'])) { $description = $payload['TextBody']; diff --git a/app/Integration/Sendgrid.php b/app/Integration/Sendgrid.php index 902749f6..fd58342a 100644 --- a/app/Integration/Sendgrid.php +++ b/app/Integration/Sendgrid.php @@ -2,7 +2,6 @@ namespace Integration; -use HTML_To_Markdown; use Core\Tool; /** @@ -79,8 +78,7 @@ class Sendgrid extends \Core\Base // Get the Markdown contents if (! empty($payload['html'])) { - $markdown = new HTML_To_Markdown($payload['html'], array('strip_tags' => true)); - $description = $markdown->output(); + $description = $this->htmlConverter->convert($payload['html']); } else if (! empty($payload['text'])) { $description = $payload['text']; diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php index 557a62cc..8cea7367 100644 --- a/app/Locale/cs_CZ/translations.php +++ b/app/Locale/cs_CZ/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Vzdálený', 'Enabled' => 'Povoleno', 'Disabled' => 'Zakázáno', - 'Google account linked' => 'Google úÄet byl propojen', - 'Github account linked' => 'Mit Githubaccount verbunden', 'Username:' => 'Uživatelské jméno:', 'Name:' => 'Jméno:', 'Email:' => 'e-mail', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Horizontálnà rolovánÃ', 'Compact/wide view' => 'KompaktnÃ/plné zobrazenÃ', 'No results match:' => 'Žádná shoda:', - 'Remove hourly rate' => 'Stundensatz entfernen', - 'Do you really want to remove this hourly rate?' => 'Opravdu chcete odstranit tuto hodinovou sazbu?', - 'Hourly rates' => 'Hodinové sazby', - 'Hourly rate' => 'Hodinová sazba', 'Currency' => 'MÄ›na', - 'Effective date' => 'Datum úÄinnosti', - 'Add new rate' => 'PÅ™idat novou hodinovou sazbu', - 'Rate removed successfully.' => 'Sazba byla úspěšnÄ› odstranÄ›na', - 'Unable to remove this rate.' => 'Sazbu nelze odstranit.', - 'Unable to save the hourly rate.' => 'Hodinovou sazbu nelze uložit', - 'Hourly rate created successfully.' => 'Hodinová sazba byla úspěšnÄ› vytvoÅ™ena.', 'Start time' => 'PoÄáteÄnà datum', 'End time' => 'KoneÄné datum', 'Comment' => 'Komentář', @@ -703,34 +691,18 @@ return array( 'Files' => 'Soubory', 'Images' => 'Obrázky', 'Private project' => 'Soukromý projekt', - 'Amount' => 'Částka', // 'AUD - Australian Dollar' => '', - 'Budget' => 'RozpoÄet', - 'Budget line' => 'Položka rozpoÄtu', - 'Budget line removed successfully.' => 'Položka rozpoÄtu byla odstranÄ›na', - 'Budget lines' => 'Položky rozpoÄtu', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - 'Cost' => 'Cena', - 'Cost breakdown' => 'Rozpis nákladů', 'Custom Stylesheet' => 'Vlastnà šablony stylů', 'download' => 'Stáhnout', - 'Do you really want to remove this budget line?' => 'Opravdu chcete odstranit tuto rozpoÄtovou řádku?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Náklady', 'GBP - British Pound' => 'GBP - Britská Libra', 'INR - Indian Rupee' => 'INR - Indische Rupien', 'JPY - Japanese Yen' => 'JPY - Japanischer Yen', - 'New budget line' => 'Nová položka rozpoÄtu', 'NZD - New Zealand Dollar' => 'NZD - Neuseeland-Dollar', - 'Remove a budget line' => 'Budgetlinie entfernen', - 'Remove budget line' => 'Budgetlinie entfernen', 'RSD - Serbian dinar' => 'RSD - Serbische Dinar', - 'The budget line have been created successfully.' => 'Položka rozpoÄtu byla úspěšnÄ› vytvoÅ™ena.', - 'Unable to create the budget line.' => 'Nelze vytvoÅ™it rozpoÄtovou řádku.', - 'Unable to remove this budget line.' => 'Nelze vyjmout rozpoÄtovou řádku.', 'USD - US Dollar' => 'USD - US Dollar', - 'Remaining' => 'ZbývajÃcÃ', 'Destination column' => 'CÃlový sloupec', 'Move the task to another column when assigned to a user' => 'PÅ™esunout úkol do jiného sloupce, když je úkol pÅ™iÅ™azen uživateli.', 'Move the task to another column when assignee is cleared' => 'PÅ™esunout úkol do jiného sloupce, když je pověřenà uživatele vymazáno.', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Kurz', 'Change reference currency' => 'ZmÄ›nit referenÄnà mÄ›nu', 'Add a new currency rate' => 'PÅ™idat nový smÄ›nný kurz', - 'Currency rates are used to calculate project budget.' => 'MÄ›nové sazby se použÃvajà k výpoÄtu rozpoÄtu projektu.', 'Reference currency' => 'ReferenÄnà mÄ›na', 'The currency rate have been added successfully.' => 'SmÄ›nný kurz byl úspěšnÄ› pÅ™idán.', 'Unable to add this currency rate.' => 'Nelze pÅ™idat tento smÄ›nný kurz', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s hat die Aufgabe #%d in die erste Swimlane verschoben', '%s moved the task #%d to the swimlane "%s"' => '%s hat die Aufgabe #%d in die Swimlane "%s" verschoben', // 'Swimlane' => '', - 'Budget overview' => 'Budget Übersicht', - 'Type' => 'Typ', - 'There is not enough data to show something.' => 'Es gibt nicht genug Daten für die Anzeige', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index 6a41f065..027b22c5 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remote', 'Enabled' => 'Aktiv', 'Disabled' => 'Deaktiveret', - 'Google account linked' => 'Google-konto forbundet', - 'Github account linked' => 'Github-konto forbundet', 'Username:' => 'Brugernavn', 'Name:' => 'Navn:', 'Email:' => 'Email:', @@ -667,17 +665,7 @@ return array( // 'Horizontal scrolling' => '', // 'Compact/wide view' => '', // 'No results match:' => '', - // 'Remove hourly rate' => '', - // 'Do you really want to remove this hourly rate?' => '', - // 'Hourly rates' => '', - // 'Hourly rate' => '', // 'Currency' => '', - // 'Effective date' => '', - // 'Add new rate' => '', - // 'Rate removed successfully.' => '', - // 'Unable to remove this rate.' => '', - // 'Unable to save the hourly rate.' => '', - // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', // 'Comment' => '', @@ -703,34 +691,18 @@ return array( // 'Files' => '', // 'Images' => '', // 'Private project' => '', - // 'Amount' => '', // 'AUD - Australian Dollar' => '', - // 'Budget' => '', - // 'Budget line' => '', - // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', // 'Custom Stylesheet' => '', // 'download' => '', - // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', - // 'Expenses' => '', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - // 'New budget line' => '', // 'NZD - New Zealand Dollar' => '', - // 'Remove a budget line' => '', - // 'Remove budget line' => '', // 'RSD - Serbian dinar' => '', - // 'The budget line have been created successfully.' => '', - // 'Unable to create the budget line.' => '', - // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', - // 'Remaining' => '', // 'Destination column' => '', // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index 7b38e9fc..0b1df2e7 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remote', 'Enabled' => 'angeschaltet', 'Disabled' => 'abgeschaltet', - 'Google account linked' => 'Mit Google-Account verbunden', - 'Github account linked' => 'Mit Github-Account verbunden', 'Username:' => 'Benutzername', 'Name:' => 'Name', 'Email:' => 'E-Mail', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Horizontales Scrollen', 'Compact/wide view' => 'Kompakt/Breite-Ansicht', 'No results match:' => 'Keine Ergebnisse:', - 'Remove hourly rate' => 'Stundensatz entfernen', - 'Do you really want to remove this hourly rate?' => 'Diesen Stundensatz wirklich entfernen?', - 'Hourly rates' => 'Stundensätze', - 'Hourly rate' => 'Stundensatz', 'Currency' => 'Währung', - 'Effective date' => 'Inkraftsetzung', - 'Add new rate' => 'Neue Rate hinzufügen', - 'Rate removed successfully.' => 'Rate erfolgreich entfernt', - 'Unable to remove this rate.' => 'Nicht in der Lage, diese Rate zu entfernen.', - 'Unable to save the hourly rate.' => 'Nicht in der Lage, diese Rate zu speichern', - 'Hourly rate created successfully.' => 'Stundensatz erfolgreich angelegt.', 'Start time' => 'Startzeit', 'End time' => 'Endzeit', 'Comment' => 'Kommentar', @@ -703,34 +691,18 @@ return array( 'Files' => 'Dateien', 'Images' => 'Bilder', 'Private project' => 'privates Projekt', - 'Amount' => 'Betrag', 'AUD - Australian Dollar' => 'AUD - Australische Dollar', - 'Budget' => 'Budget', - 'Budget line' => 'Budgetlinie', - 'Budget line removed successfully.' => 'Budgetlinie erfolgreich entfernt', - 'Budget lines' => 'Budgetlinien', 'CAD - Canadian Dollar' => 'CAD - Kanadische Dollar', 'CHF - Swiss Francs' => 'CHF - Schweizer Franken', - 'Cost' => 'Kosten', - 'Cost breakdown' => 'Kostenaufschlüsselung', 'Custom Stylesheet' => 'benutzerdefiniertes Stylesheet', 'download' => 'Download', - 'Do you really want to remove this budget line?' => 'Soll diese Budgetlinie wirklich entfernt werden?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Kosten', 'GBP - British Pound' => 'GBP - Britische Pfund', 'INR - Indian Rupee' => 'INR - Indische Rupien', 'JPY - Japanese Yen' => 'JPY - Japanische Yen', - 'New budget line' => 'Neue Budgetlinie', 'NZD - New Zealand Dollar' => 'NZD - Neuseeland-Dollar', - 'Remove a budget line' => 'Budgetlinie entfernen', - 'Remove budget line' => 'Budgetlinie entfernen', 'RSD - Serbian dinar' => 'RSD - Serbische Dinar', - 'The budget line have been created successfully.' => 'Die Budgetlinie wurde erfolgreich angelegt.', - 'Unable to create the budget line.' => 'Budgetlinie konnte nicht erstellt werden.', - 'Unable to remove this budget line.' => 'Budgetlinie konnte nicht gelöscht werden.', 'USD - US Dollar' => 'USD - US-Dollar', - 'Remaining' => 'Verbleibend', 'Destination column' => 'Zielspalte', 'Move the task to another column when assigned to a user' => 'Aufgabe in eine andere Spalte verschieben, wenn ein User zugeordnet wurde.', 'Move the task to another column when assignee is cleared' => 'Aufgabe in eine andere Spalte verschieben, wenn die Zuordnung gelöscht wurde.', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Kurse', 'Change reference currency' => 'Referenzwährung ändern', 'Add a new currency rate' => 'Neuen Währungskurs hinzufügen', - 'Currency rates are used to calculate project budget.' => 'Währungskurse werden verwendet, um das Projektbudget zu berechnen.', 'Reference currency' => 'Referenzwährung', 'The currency rate have been added successfully.' => 'Der Währungskurs wurde erfolgreich hinzugefügt.', 'Unable to add this currency rate.' => 'Währungskurs konnte nicht hinzugefügt werden', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s hat die Aufgabe #%d in die erste Swimlane verschoben', '%s moved the task #%d to the swimlane "%s"' => '%s hat die Aufgabe #%d in die Swimlane "%s" verschoben', // 'Swimlane' => '', - 'Budget overview' => 'Budget-Übersicht', - 'Type' => 'Typ', - 'There is not enough data to show something.' => 'Es gibt nicht genügend Daten für diese Anzeige', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index ac7c0e4b..1e15d8c0 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remota', 'Enabled' => 'Activada', 'Disabled' => 'Desactivada', - 'Google account linked' => 'Vinculada con Cuenta de Google', - 'Github account linked' => 'Vinculada con Cuenta de Gitgub', 'Username:' => 'Nombre de Usuario:', 'Name:' => 'Nombre:', 'Email:' => 'Correo electrónico:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Desplazamiento horizontal', 'Compact/wide view' => 'Vista compacta/amplia', 'No results match:' => 'No hay resultados coincidentes:', - 'Remove hourly rate' => 'Quitar cobro horario', - 'Do you really want to remove this hourly rate?' => '¿Realmente quire quitar el cobro horario?', - 'Hourly rates' => 'Cobros horarios', - 'Hourly rate' => 'Cobro horario', 'Currency' => 'Moneda', - 'Effective date' => 'Fecha efectiva', - 'Add new rate' => 'Añadir nuevo cobro', - 'Rate removed successfully.' => 'Cobro quitado con éxito.', - 'Unable to remove this rate.' => 'No pude quitar este cobro.', - 'Unable to save the hourly rate.' => 'No pude grabar el cobro horario.', - 'Hourly rate created successfully.' => 'Cobro horario creado con éxito', 'Start time' => 'Tiempo de inicio', 'End time' => 'Tiempo de fin', 'Comment' => 'Comentario', @@ -703,34 +691,18 @@ return array( 'Files' => 'Ficheros', 'Images' => 'Imágenes', 'Private project' => 'Proyecto privado', - 'Amount' => 'Cantidad', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', - 'Budget' => 'Presupuesto', - 'Budget line' => 'LÃnea de presupuesto', - 'Budget line removed successfully.' => 'LÃnea de presupuesto quitada con éxito', - 'Budget lines' => 'LÃneas de presupuesto', 'CAD - Canadian Dollar' => 'CAD - Dólar canadiense', 'CHF - Swiss Francs' => 'CHF - Francos suizos', - 'Cost' => 'Costo', - 'Cost breakdown' => 'Desglose de costes', 'Custom Stylesheet' => 'Hoja de estilo Personalizada', 'download' => 'descargar', - 'Do you really want to remove this budget line?' => '¿Realmente quiere quitar esta lÃnea de presupuesto?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Gastos', 'GBP - British Pound' => 'GBP - Libra británica', 'INR - Indian Rupee' => 'INR - Rupias indúes', 'JPY - Japanese Yen' => 'JPY - Yen japonés', - 'New budget line' => 'Nueva lÃnea de presupuesto', 'NZD - New Zealand Dollar' => 'NZD - Dóloar neocelandés', - 'Remove a budget line' => 'Quitar una lÃnea de presupuesto', - 'Remove budget line' => 'Quitar lÃnea de presupuesto', 'RSD - Serbian dinar' => 'RSD - Dinar serbio', - 'The budget line have been created successfully.' => 'Se ha creado la lÃnea de presupuesto con éxito.', - 'Unable to create the budget line.' => 'No pude crear la lÃnea de presupuesto.', - 'Unable to remove this budget line.' => 'No pude quitar esta lÃnea de presupuesto.', 'USD - US Dollar' => 'USD - Dólar Estadounidense', - 'Remaining' => 'Restante', 'Destination column' => 'Columna destino', 'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse al usuario', 'Move the task to another column when assignee is cleared' => 'Mover la tarea a otra columna al quitar el concesionario', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Cambio', 'Change reference currency' => 'Cambiar moneda de referencia', 'Add a new currency rate' => 'Añadir nuevo cambio de moneda', - 'Currency rates are used to calculate project budget.' => 'Se usan los cambios de moneda para calcular el presupuesto del proyecto.', 'Reference currency' => 'Moneda de referencia', 'The currency rate have been added successfully.' => 'Se ha añadido el cambio de moneda con éxito', 'Unable to add this currency rate.' => 'No pude añadir este cambio de moneda.', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s movió la tarea #%d a la primera calle', '%s moved the task #%d to the swimlane "%s"' => '%s movió la tarea #%d a la calle "%s"', 'Swimlane' => 'Calle', - 'Budget overview' => 'Resumen del Presupuesto', - 'Type' => 'Tipo', - 'There is not enough data to show something.' => 'No hay datos suficientes como para mostrar algo.', 'Gravatar' => 'Gravatar', 'Hipchat' => 'Hipchat', 'Slack' => 'Desatendida', @@ -1040,31 +1008,31 @@ return array( 'Shared project' => 'Proyecto compartido', 'Project managers' => 'Administradores de proyecto', 'Project members' => 'Miembros de proyecto', - // 'Gantt chart for all projects' => '', - // 'Projects list' => '', - // 'Gantt chart for this project' => '', - // 'Project board' => '', - // 'End date:' => '', - // 'There is no start date or end date for this project.' => '', - // 'Projects Gantt chart' => '', - // 'Start date: %s' => '', - // 'End date: %s' => '', - // 'Link type' => '', - // 'Change task color when using a specific task link' => '', - // 'Task link creation or modification' => '', - // 'Login with my Gitlab Account' => '', - // 'Milestone' => '', - // 'Gitlab Authentication' => '', - // 'Help on Gitlab authentication' => '', - // 'Gitlab Id' => '', - // 'Gitlab Account' => '', - // 'Link my Gitlab Account' => '', - // 'Unlink my Gitlab Account' => '', - // 'Documentation: %s' => '', - // 'Switch to the Gantt chart view' => '', - // 'Reset the search/filter box' => '', - // 'Documentation' => '', - // 'Table of contents' => '', - // 'Gantt' => '', - // 'Help with project permissions' => '', + 'Gantt chart for all projects' => 'Diagrama de Gantt para todos los proyectos', + 'Projects list' => 'Lista de proyectos', + 'Gantt chart for this project' => 'Diagrama de Gantt para este proyecto', + 'Project board' => 'Tablero del proyecto', + 'End date:' => 'Fecha final', + 'There is no start date or end date for this project.' => 'No existe fecha de inicio o de fin para este proyecto.', + 'Projects Gantt chart' => 'Diagramas de Gantt de los proyectos', + 'Start date: %s' => 'Fecha inicial: %s', + 'End date: %s' => 'Fecha final: %s', + 'Link type' => 'Tipo de enlace', + 'Change task color when using a specific task link' => 'Cambiar colo de la tarea al usar un enlace especÃfico a tarea', + 'Task link creation or modification' => 'Creación o modificación de enlace a tarea', + 'Login with my Gitlab Account' => 'Ingresar usando mi Cuenta en Gitlab', + 'Milestone' => 'Hito', + 'Gitlab Authentication' => 'Autenticación Gitlab', + 'Help on Gitlab authentication' => 'Ayuda con autenticación Gitlab', + 'Gitlab Id' => 'Id de Gitlab', + 'Gitlab Account' => 'Cuenta de Gitlab', + 'Link my Gitlab Account' => 'Enlazar con mi Cuenta en Gitlab', + 'Unlink my Gitlab Account' => 'Desenlazar con mi Cuenta en Gitlab', + 'Documentation: %s' => 'Documentación: %s', + 'Switch to the Gantt chart view' => 'Conmutar a vista de diagrama de Gantt', + 'Reset the search/filter box' => 'Limpiar la caja del filtro de búsqueda', + 'Documentation' => 'Documentación', + 'Table of contents' => 'Tabla de contenido', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Ayuda con permisos del proyecto', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index d8c749a3..da462831 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Etä', 'Enabled' => 'Käytössä', 'Disabled' => 'Pois käytöstä', - 'Google account linked' => 'Google-tili liitetty', - 'Github account linked' => 'Github-tili liitetty', 'Username:' => 'Käyttäjänimi:', 'Name:' => 'Nimi:', 'Email:' => 'Sähköpostiosoite:', @@ -667,17 +665,7 @@ return array( // 'Horizontal scrolling' => '', // 'Compact/wide view' => '', // 'No results match:' => '', - // 'Remove hourly rate' => '', - // 'Do you really want to remove this hourly rate?' => '', - // 'Hourly rates' => '', - // 'Hourly rate' => '', // 'Currency' => '', - // 'Effective date' => '', - // 'Add new rate' => '', - // 'Rate removed successfully.' => '', - // 'Unable to remove this rate.' => '', - // 'Unable to save the hourly rate.' => '', - // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', // 'Comment' => '', @@ -703,34 +691,18 @@ return array( // 'Files' => '', // 'Images' => '', // 'Private project' => '', - // 'Amount' => '', // 'AUD - Australian Dollar' => '', - // 'Budget' => '', - // 'Budget line' => '', - // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', // 'Custom Stylesheet' => '', // 'download' => '', - // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', - // 'Expenses' => '', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - // 'New budget line' => '', // 'NZD - New Zealand Dollar' => '', - // 'Remove a budget line' => '', - // 'Remove budget line' => '', // 'RSD - Serbian dinar' => '', - // 'The budget line have been created successfully.' => '', - // 'Unable to create the budget line.' => '', - // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', - // 'Remaining' => '', // 'Destination column' => '', // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index 0c95c7eb..848b7624 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -75,19 +75,19 @@ return array( 'Change columns' => 'Changer les colonnes', 'Add a new column' => 'Ajouter une nouvelle colonne', 'Title' => 'Titre', - 'Nobody assigned' => 'Personne assigné', + 'Nobody assigned' => 'Personne assignée', 'Assigned to %s' => 'Assigné à %s', 'Remove a column' => 'Supprimer une colonne', 'Remove a column from a board' => 'Supprimer une colonne d\'un tableau', 'Unable to remove this column.' => 'Impossible de supprimer cette colonne.', 'Do you really want to remove this column: "%s"?' => 'Voulez vraiment supprimer cette colonne : « %s » ?', - 'This action will REMOVE ALL TASKS associated to this column!' => 'Cette action va supprimer toutes les tâches associées à cette colonne !', + 'This action will REMOVE ALL TASKS associated to this column!' => 'Cette action va supprimer toutes les tâches associées à cette colonne !', 'Settings' => 'Préférences', 'Application settings' => 'Paramètres de l\'application', 'Language' => 'Langue', 'Webhook token:' => 'Jeton de securité pour les webhooks :', 'API token:' => 'Jeton de securité pour l\'API :', - 'Database size:' => 'Taille de la base de données :', + 'Database size:' => 'Taille de la base de données :', 'Download the database' => 'Télécharger la base de données', 'Optimize the database' => 'Optimiser la base de données', '(VACUUM command)' => '(Commande VACUUM)', @@ -96,15 +96,15 @@ return array( 'Edit a task' => 'Modifier une tâche', 'Column' => 'Colonne', 'Color' => 'Couleur', - 'Assignee' => 'Personne assignée', + 'Assignee' => 'Personne assigné', 'Create another task' => 'Créer une autre tâche', 'New task' => 'Nouvelle tâche', 'Open a task' => 'Ouvrir une tâche', - 'Do you really want to open this task: "%s"?' => 'Voulez-vous vraiment ouvrir cette tâche : « %s » ?', + 'Do you really want to open this task: "%s"?' => 'Voulez-vous vraiment ouvrir cette tâche : « %s » ?', 'Back to the board' => 'Retour au tableau', 'Created on %B %e, %Y at %k:%M %p' => 'Créé le %d/%m/%Y à %H:%M', 'There is nobody assigned' => 'Il n\'y a personne d\'assigné à cette tâche', - 'Column on the board:' => 'Colonne sur le tableau : ', + 'Column on the board:' => 'Colonne sur le tableau : ', 'Status is open' => 'État ouvert', 'Status is closed' => 'État fermé', 'Close this task' => 'Fermer cette tâche', @@ -142,7 +142,7 @@ return array( 'Unable to open this task.' => 'Impossible d\'ouvrir cette tâche.', 'Task opened successfully.' => 'Tâche ouverte avec succès.', 'Unable to close this task.' => 'Impossible de fermer cette tâche.', - 'Task closed successfully.' => 'Tâche fermé avec succès.', + 'Task closed successfully.' => 'Tâche fermée avec succès.', 'Unable to update your task.' => 'Impossible de modifier cette tâche.', 'Task updated successfully.' => 'Tâche mise à jour avec succès.', 'Unable to create your task.' => 'Impossible de créer cette tâche.', @@ -167,11 +167,11 @@ return array( '%d closed tasks' => '%d tâches terminées', 'No task for this project' => 'Aucune tâche pour ce projet', 'Public link' => 'Lien public', - 'There is no column in your project!' => 'Il n\'y a aucune colonne dans votre projet !', + 'There is no column in your project!' => 'Il n\'y a aucune colonne dans votre projet !', 'Change assignee' => 'Changer la personne assignée', 'Change assignee for the task "%s"' => 'Changer la personne assignée pour la tâche « %s »', 'Timezone' => 'Fuseau horaire', - 'Sorry, I didn\'t find this information in my database!' => 'Désolé, je n\'ai pas trouvé cette information dans ma base de données !', + 'Sorry, I didn\'t find this information in my database!' => 'Désolé, je n\'ai pas trouvé cette information dans ma base de données !', 'Page not found' => 'Page introuvable', 'Complexity' => 'Complexité', 'Task limit' => 'Tâches Max.', @@ -197,7 +197,7 @@ return array( '%B %e, %Y' => '%d %B %Y', '%b %e, %Y' => '%d/%m/%Y', 'Automatic actions' => 'Actions automatisées', - 'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.', + 'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajoutée avec succès.', 'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.', 'Remove an action' => 'Supprimer une action', 'Unable to remove this action.' => 'Impossible de supprimer cette action', @@ -210,7 +210,7 @@ return array( 'Action parameters' => 'Paramètres de l\'action', 'Action' => 'Action', 'Event' => 'Événement', - 'When the selected event occurs execute the corresponding action.' => 'Lorsque l\'événement sélectionné se déclenche, executer l\'action correspondante.', + 'When the selected event occurs execute the corresponding action.' => 'Lorsque l\'événement sélectionné se déclenche, exécuter l\'action correspondante.', 'Next step' => 'Étape suivante', 'Define action parameters' => 'Définition des paramètres de l\'action', 'Save this action' => 'Sauvegarder cette action', @@ -237,10 +237,10 @@ return array( 'Comment removed successfully.' => 'Commentaire supprimé avec succès.', 'Unable to remove this comment.' => 'Impossible de supprimer ce commentaire.', 'Do you really want to remove this comment?' => 'Voulez-vous vraiment supprimer ce commentaire ?', - 'Only administrators or the creator of the comment can access to this page.' => 'Uniquement les administrateurs ou le créateur du commentaire peuvent accéder à cette page.', + 'Only administrators or the creator of the comment can access to this page.' => 'Seuls les administrateurs ou le créateur du commentaire peuvent accéder à cette page.', 'Current password for the user "%s"' => 'Mot de passe actuel pour l\'utilisateur « %s »', 'The current password is required' => 'Le mot de passe actuel est obligatoire', - 'Wrong password' => 'Mauvais mot de passe', + 'Wrong password' => 'Mot de passe invalide', 'Unknown' => 'Inconnu', 'Last logins' => 'Dernières connexions', 'Login date' => 'Date de connexion', @@ -263,10 +263,10 @@ return array( '%d comments' => '%d commentaires', '%d comment' => '%d commentaire', 'Email address invalid' => 'Adresse email invalide', - 'Your external account is not linked anymore to your profile.' => 'Votre compte externe n\'est plus relié à votre profile.', + 'Your external account is not linked anymore to your profile.' => 'Votre compte externe n\'est plus relié à votre profil.', 'Unable to unlink your external account.' => 'Impossible de supprimer votre compte externe.', - 'External authentication failed' => 'Authentification externe échouée', - 'Your external account is linked to your profile successfully.' => 'Votre compte externe est désormais lié à votre profile.', + 'External authentication failed' => 'L’authentification externe a échoué', + 'Your external account is linked to your profile successfully.' => 'Votre compte externe est désormais lié à votre profil.', 'Email' => 'Email', 'Link my Google Account' => 'Lier mon compte Google', 'Unlink my Google Account' => 'Ne plus utiliser mon compte Google', @@ -283,7 +283,7 @@ return array( 'Category:' => 'Catégorie :', 'Categories' => 'Catégories', 'Category not found.' => 'Catégorie introuvable', - 'Your category have been created successfully.' => 'Votre catégorie a été créé avec succès.', + 'Your category have been created successfully.' => 'Votre catégorie a été créée avec succès.', 'Unable to create your category.' => 'Impossible de créer votre catégorie.', 'Your category have been updated successfully.' => 'Votre catégorie a été mise à jour avec succès.', 'Unable to update your category.' => 'Impossible de mettre à jour votre catégorie.', @@ -311,13 +311,13 @@ return array( 'Summary' => 'Résumé', 'Time tracking' => 'Suivi du temps', 'Estimate:' => 'Estimation :', - 'Spent:' => 'Passé :', + 'Spent:' => 'Passé :', 'Do you really want to remove this sub-task?' => 'Voulez-vous vraiment supprimer cette sous-tâche ?', - 'Remaining:' => 'Restant :', + 'Remaining:' => 'Restant :', 'hours' => 'heures', 'spent' => 'passé', 'estimated' => 'estimé', - 'Sub-Tasks' => 'Sous-Tâches', + 'Sub-Tasks' => 'Sous-tâches', 'Add a sub-task' => 'Ajouter une sous-tâche', 'Original estimate' => 'Estimation originale', 'Create another sub-task' => 'Créer une autre sous-tâche', @@ -332,8 +332,8 @@ return array( 'Sub-task updated successfully.' => 'Sous-tâche mise à jour avec succès.', 'Unable to update your sub-task.' => 'Impossible de mettre à jour votre sous-tâche.', 'Unable to create your sub-task.' => 'Impossible de créer votre sous-tâche.', - 'Sub-task added successfully.' => 'Sous-tâche ajouté avec succès.', - 'Maximum size: ' => 'Taille maximum : ', + 'Sub-task added successfully.' => 'Sous-tâche ajoutée avec succès.', + 'Maximum size: ' => 'Taille maximum : ', 'Unable to upload the file.' => 'Impossible de transférer le fichier.', 'Display another project' => 'Afficher un autre projet', 'Login with my Github Account' => 'Se connecter avec mon compte Github', @@ -397,8 +397,6 @@ return array( 'Remote' => 'Distant', 'Enabled' => 'Activé', 'Disabled' => 'Désactivé', - 'Google account linked' => 'Compte Google attaché', - 'Github account linked' => 'Compte Github attaché', 'Username:' => 'Nom d\'utilisateur :', 'Name:' => 'Nom :', 'Email:' => 'Email :', @@ -447,10 +445,10 @@ return array( '%s moved the task #%d to the position %d in the column "%s"' => '%s a déplacé la tâche n°%d à la position n°%d dans la colonne « %s »', 'Activity' => 'Activité', 'Default values are "%s"' => 'Les valeurs par défaut sont « %s »', - 'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)', - 'Task assignee change' => 'Modification de la personne assignée sur une tâche', - '%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée sur la tâche nËš%d pour %s', - '%s changed the assignee of the task %s to %s' => '%s a changé la personne assignée sur la tâche %s pour %s', + 'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparation par des virgules)', + 'Task assignee change' => 'Modification de la personne assignée à une tâche', + '%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée à la tâche nËš%d pour %s', + '%s changed the assignee of the task %s to %s' => '%s a changé la personne assignée à la tâche %s pour %s', 'New password for the user "%s"' => 'Nouveau mot de passe pour l\'utilisateur « %s »', 'Choose an event' => 'Choisir un événement', 'Github commit received' => 'Commit reçu via Github', @@ -466,7 +464,7 @@ return array( 'Reference: %s' => 'Référence : %s', 'Label' => 'Libellé', 'Database' => 'Base de données', - 'About' => 'A propos', + 'About' => 'À propos', 'Database driver:' => 'Type de base de données :', 'Board settings' => 'Paramètres du tableau', 'URL and token' => 'URL et jeton de sécurité', @@ -529,12 +527,12 @@ return array( 'Previous' => 'Précédent', 'The id must be an integer' => 'L\'id doit être un entier', 'The project id must be an integer' => 'L\'id du projet doit être un entier', - 'The status must be an integer' => 'Le status doit être un entier', + 'The status must be an integer' => 'Le statut doit être un entier', 'The subtask id is required' => 'L\'id de la sous-tâche est obligatoire', - 'The subtask id must be an integer' => 'L\'id de la sous-tâche doit être en entier', + 'The subtask id must be an integer' => 'L\'id de la sous-tâche doit être un entier', 'The task id is required' => 'L\'id de la tâche est obligatoire', - 'The task id must be an integer' => 'L\'id de la tâche doit être en entier', - 'The user id must be an integer' => 'L\'id de l\'utilisateur doit être en entier', + 'The task id must be an integer' => 'L\'id de la tâche doit être un entier', + 'The user id must be an integer' => 'L\'id de l\'utilisateur doit être un entier', 'This value is required' => 'Cette valeur est obligatoire', 'This value must be numeric' => 'Cette valeur doit être numérique', 'Unable to create this task.' => 'Impossible de créer cette tâche', @@ -552,7 +550,7 @@ return array( 'Add a new swimlane' => 'Ajouter une nouvelle swimlane', 'Change default swimlane' => 'Modifier la swimlane par défaut', 'Default swimlane' => 'Swimlane par défaut', - 'Do you really want to remove this swimlane: "%s"?' => 'Voulez-vous vraiment supprimer cette swimlane : « %s » ?', + 'Do you really want to remove this swimlane: "%s"?' => 'Voulez-vous vraiment supprimer cette swimlane : « %s » ?', 'Inactive swimlanes' => 'Swimlanes inactives', 'Set project manager' => 'Mettre chef de projet', 'Set project member' => 'Mettre membre du projet', @@ -570,7 +568,7 @@ return array( 'Unable to update this swimlane.' => 'Impossible de mettre à jour cette swimlane.', 'Your swimlane have been created successfully.' => 'Votre swimlane a été créée avec succès.', 'Example: "Bug, Feature Request, Improvement"' => 'Exemple: « Incident, Demande de fonctionnalité, Amélioration »', - 'Default categories for new projects (Comma-separated)' => 'Catégories par défaut pour les nouveaux projets (séparé par des virgules)', + 'Default categories for new projects (Comma-separated)' => 'Catégories par défaut pour les nouveaux projets (séparation par des virgules)', 'Gitlab commit received' => 'Commit reçu via Gitlab', 'Gitlab issue opened' => 'Ouverture d\'un ticket sur Gitlab', 'Gitlab issue closed' => 'Fermeture d\'un ticket sur Gitlab', @@ -604,25 +602,25 @@ return array( 'User dashboard' => 'Tableau de bord de l\'utilisateur', 'Allow only one subtask in progress at the same time for a user' => 'Autoriser une seule sous-tâche en progrès en même temps pour un utilisateur', 'Edit column "%s"' => 'Modifier la colonne « %s »', - 'Select the new status of the subtask: "%s"' => 'Selectionnez le nouveau statut de la sous-tâche : « %s »', + 'Select the new status of the subtask: "%s"' => 'Selectionnez le nouveau statut de la sous-tâche : « %s »', 'Subtask timesheet' => 'Feuille de temps des sous-tâches', 'There is nothing to show.' => 'Il n\'y a rien à montrer.', 'Time Tracking' => 'Feuille de temps', 'You already have one subtask in progress' => 'Vous avez déjà une sous-tâche en progrès', - 'Which parts of the project do you want to duplicate?' => 'Quelles parties du projet voulez-vous dupliquer ?', + 'Which parts of the project do you want to duplicate?' => 'Quelles parties du projet voulez-vous dupliquer ?', 'Disallow login form' => 'Interdir le formulaire d\'authentification', 'Bitbucket commit received' => 'Commit reçu via Bitbucket', 'Bitbucket webhooks' => 'Webhook Bitbucket', 'Help on Bitbucket webhooks' => 'Aide sur les webhooks Bitbucket', 'Start' => 'Début', 'End' => 'Fin', - 'Task age in days' => 'Age de la tâche en jours', + 'Task age in days' => 'Âge de la tâche en jours', 'Days in this column' => 'Jours dans cette colonne', '%dd' => '%dj', 'Add a link' => 'Ajouter un lien', 'Add a new link' => 'Ajouter un nouveau lien', - 'Do you really want to remove this link: "%s"?' => 'Voulez-vous vraiment supprimer ce lien : « %s » ?', - 'Do you really want to remove this link with task #%d?' => 'Voulez-vous vraiment supprimer ce lien avec la tâche n°%d ?', + 'Do you really want to remove this link: "%s"?' => 'Voulez-vous vraiment supprimer ce lien : « %s » ?', + 'Do you really want to remove this link with task #%d?' => 'Voulez-vous vraiment supprimer ce lien avec la tâche n°%d ?', 'Field required' => 'Champ obligatoire', 'Link added successfully.' => 'Lien créé avec succès.', 'Link updated successfully.' => 'Lien mis à jour avec succès.', @@ -658,7 +656,7 @@ return array( 'Expand tasks' => 'Déplier les tâches', 'Collapse tasks' => 'Replier les tâches', 'Expand/collapse tasks' => 'Plier/déplier les tâches', - 'Close dialog box' => 'Fermer une boite de dialogue', + 'Close dialog box' => 'Fermer une boîte de dialogue', 'Submit a form' => 'Enregistrer un formulaire', 'Board view' => 'Page du tableau', 'Keyboard shortcuts' => 'Raccourcis clavier', @@ -669,17 +667,7 @@ return array( 'Horizontal scrolling' => 'Défilement horizontal', 'Compact/wide view' => 'Basculer entre la vue compacte et étendue', 'No results match:' => 'Aucun résultat :', - 'Remove hourly rate' => 'Supprimer un taux horaire', - 'Do you really want to remove this hourly rate?' => 'Voulez-vous vraiment supprimer ce taux horaire ?', - 'Hourly rates' => 'Taux horaires', - 'Hourly rate' => 'Taux horaire', 'Currency' => 'Devise', - 'Effective date' => 'Date d\'effet', - 'Add new rate' => 'Ajouter un nouveau taux horaire', - 'Rate removed successfully.' => 'Taux horaire supprimé avec succès.', - 'Unable to remove this rate.' => 'Impossible de supprimer ce taux horaire.', - 'Unable to save the hourly rate.' => 'Impossible de sauvegarder ce taux horaire.', - 'Hourly rate created successfully.' => 'Taux horaire créé avec succès.', 'Start time' => 'Date de début', 'End time' => 'Date de fin', 'Comment' => 'Commentaire', @@ -701,38 +689,22 @@ return array( 'Do you really want to remove this time slot?' => 'Voulez-vous vraiment supprimer ce créneau horaire ?', 'Remove time slot' => 'Supprimer un créneau horaire', 'Add new time slot' => 'Ajouter un créneau horaire', - 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ces horaires sont utilisés lorsque la case « Toute la journée » est cochée pour les heures d\'absences ou supplémentaires programmées.', + 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ces horaires sont utilisés lorsque la case « Toute la journée » est cochée pour les heures d\'absences ou supplémentaires programmées.', 'Files' => 'Fichiers', 'Images' => 'Images', 'Private project' => 'Projet privé', - 'Amount' => 'Montant', 'AUD - Australian Dollar' => 'AUD - Dollar australien', - 'Budget' => 'Budget', - 'Budget line' => 'Ligne budgétaire', - 'Budget line removed successfully.' => 'Ligne budgétaire supprimée avec succès.', - 'Budget lines' => 'Lignes budgétaire', 'CAD - Canadian Dollar' => 'CAD - Dollar canadien', 'CHF - Swiss Francs' => 'CHF - Franc suisse', - 'Cost' => 'Coût', - 'Cost breakdown' => 'Détail des coûts', 'Custom Stylesheet' => 'Feuille de style personalisée', 'download' => 'télécharger', - 'Do you really want to remove this budget line?' => 'Voulez-vous vraiment supprimer cette ligne budgétaire ?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Dépenses', 'GBP - British Pound' => 'GBP - Livre sterling', 'INR - Indian Rupee' => 'INR - Roupie indienne', 'JPY - Japanese Yen' => 'JPY - Yen', - 'New budget line' => 'Nouvelle ligne budgétaire', 'NZD - New Zealand Dollar' => 'NZD - Dollar néo-zélandais', - 'Remove a budget line' => 'Supprimer une ligne budgétaire', - 'Remove budget line' => 'Supprimer une ligne budgétaire', 'RSD - Serbian dinar' => 'RSD - Dinar serbe', - 'The budget line have been created successfully.' => 'La ligne de budgétaire a été créée avec succès.', - 'Unable to create the budget line.' => 'Impossible de créer cette ligne budgétaire.', - 'Unable to remove this budget line.' => 'Impossible de supprimer cette ligne budgétaire.', 'USD - US Dollar' => 'USD - Dollar américain', - 'Remaining' => 'Restant', 'Destination column' => 'Colonne de destination', 'Move the task to another column when assigned to a user' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci est assignée à quelqu\'un', 'Move the task to another column when assignee is cleared' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci n\'est plus assignée', @@ -748,7 +720,6 @@ return array( 'Rate' => 'Taux', 'Change reference currency' => 'Changer la monnaie de référence', 'Add a new currency rate' => 'Ajouter un nouveau taux pour une devise', - 'Currency rates are used to calculate project budget.' => 'Le cours des devises est utilisé pour calculer le budget des projets.', 'Reference currency' => 'Devise de référence', 'The currency rate have been added successfully.' => 'Le taux de change a été ajouté avec succès.', 'Unable to add this currency rate.' => 'Impossible d\'ajouter ce taux de change', @@ -769,8 +740,8 @@ return array( 'Code' => 'Code', 'Two factor authentication' => 'Authentification à deux-facteurs', 'Enable/disable two factor authentication' => 'Activer/désactiver l\'authentification à deux-facteurs', - 'This QR code contains the key URI: ' => 'Ce code QR contient l\'url de la clé : ', - 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Sauvegardez cette clé secrete dans votre logiciel TOTP (par exemple Google Authenticator ou FreeOTP).', + 'This QR code contains the key URI: ' => 'Ce code QR contient l\'url de la clé : ', + 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Sauvegardez cette clé secrète dans votre logiciel TOTP (par exemple Google Authenticator ou FreeOTP).', 'Check my code' => 'Vérifier mon code', 'Secret key: ' => 'Clé secrète : ', 'Test your device' => 'Testez votre appareil', @@ -796,9 +767,9 @@ return array( 'Sendgrid (incoming emails)' => 'Sendgrid (emails entrants)', 'Help on Sendgrid integration' => 'Aide sur l\'intégration avec Sendgrid', 'Disable two factor authentication' => 'Désactiver l\'authentification à deux facteurs', - 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Voulez-vous vraiment désactiver l\'authentification à deux facteurs pour cet utilisateur : « %s » ?', + 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Voulez-vous vraiment désactiver l\'authentification à deux facteurs pour cet utilisateur : « %s » ?', 'Edit link' => 'Modifier un lien', - 'Start to type task title...' => 'Entrez le titre de la tâche...', + 'Start to type task title...' => 'Entrez le titre de la tâche…', 'A task cannot be linked to itself' => 'Une tâche ne peut être liée à elle-même', 'The exact same link already exists' => 'Un lien identique existe déjà ', 'Recurrent task is scheduled to be generated' => 'La tâche récurrente est programmée pour être créée', @@ -814,17 +785,17 @@ return array( 'Timeframe to calculate new due date' => 'Échelle de temps pour calculer la nouvelle date d\'échéance', 'Base date to calculate new due date' => 'Date à utiliser pour calculer la nouvelle date d\'échéance', 'Action date' => 'Date de l\'action', - 'Base date to calculate new due date: ' => 'Date utilisée pour calculer la nouvelle date d\'échéance : ', - 'This task has created this child task: ' => 'Cette tâche a créée la tâche enfant : ', + 'Base date to calculate new due date: ' => 'Date utilisée pour calculer la nouvelle date d\'échéance : ', + 'This task has created this child task: ' => 'Cette tâche a créée la tâche enfant : ', 'Day(s)' => 'Jour(s)', 'Existing due date' => 'Date d\'échéance existante', - 'Factor to calculate new due date: ' => 'Facteur pour calculer la nouvelle date d\'échéance : ', + 'Factor to calculate new due date: ' => 'Facteur pour calculer la nouvelle date d\'échéance : ', 'Month(s)' => 'Mois', 'Recurrence' => 'Récurrence', - 'This task has been created by: ' => 'Cette tâche a été créée par :', - 'Recurrent task has been generated:' => 'Une tâche récurrente a été générée :', - 'Timeframe to calculate new due date: ' => 'Échelle de temps pour calculer la nouvelle date d\'échéance : ', - 'Trigger to generate recurrent task: ' => 'Déclencheur pour générer la tâche récurrente : ', + 'This task has been created by: ' => 'Cette tâche a été créée par :', + 'Recurrent task has been generated:' => 'Une tâche récurrente a été générée :', + 'Timeframe to calculate new due date: ' => 'Échelle de temps pour calculer la nouvelle date d\'échéance : ', + 'Trigger to generate recurrent task: ' => 'Déclencheur pour générer la tâche récurrente : ', 'When task is closed' => 'Lorsque la tâche est fermée', 'When task is moved from first column' => 'Lorsque la tâche est déplacée en dehors de la première colonne', 'When task is moved to last column' => 'Lorsque la tâche est déplacée dans la dernière colonne', @@ -836,7 +807,7 @@ return array( 'Jabber nickname' => 'Pseudonyme Jabber', 'Multi-user chat room' => 'Salon de discussion multi-utilisateurs', 'Help on Jabber integration' => 'Aide sur l\'intégration avec Jabber', - 'The server address must use this format: "tcp://hostname:5222"' => 'L\'adresse du serveur doit utiliser le format suivant : « tcp://hostname:5222 »', + 'The server address must use this format: "tcp://hostname:5222"' => 'L\'adresse du serveur doit utiliser le format suivant : « tcp://hostname:5222 »', 'Calendar settings' => 'Paramètres du calendrier', 'Project calendar view' => 'Vue en mode projet du calendrier', 'Project settings' => 'Paramètres du projet', @@ -849,7 +820,7 @@ return array( 'iCal feed' => 'Abonnement iCal', 'Preferences' => 'Préférences', 'Security' => 'Sécurité', - 'Two factor authentication disabled' => 'Authentification à deux facteurs désactivé', + 'Two factor authentication disabled' => 'Authentification à deux facteurs désactivée', 'Two factor authentication enabled' => 'Authentification à deux facteurs activée', 'Unable to update this user.' => 'Impossible de mettre à jour cet utilisateur.', 'There is no user management for private projects.' => 'Il n\'y a pas de gestion d\'utilisateurs pour les projets privés.', @@ -862,8 +833,8 @@ return array( 'Commit made by @%s on Github' => 'Commit fait par @%s sur Github', 'By @%s on Github' => 'Par @%s sur Github', 'Commit made by @%s on Gitlab' => 'Commit fait par @%s sur Gitlab', - 'Add a comment log when moving the task between columns' => 'Ajouter un commentaire d\'information lorsque une tâche est déplacée dans une autre colonnes', - 'Move the task to another column when the category is changed' => 'Déplacer une tâche vers une autre colonne lorsque la catégorie a changée', + 'Add a comment log when moving the task between columns' => 'Ajouter un commentaire d\'information lorsque une tâche est déplacée dans une autre colonne', + 'Move the task to another column when the category is changed' => 'Déplacer une tâche vers une autre colonne lorsque la catégorie a changé', 'Send a task by email to someone' => 'Envoyer une tâche par email à quelqu\'un', 'Reopen a task' => 'Rouvrir une tâche', 'Bitbucket issue opened' => 'Ticket Bitbucket ouvert', @@ -880,16 +851,13 @@ return array( '%s moved the task #%d to the first swimlane' => '%s a déplacé la tâche n°%d dans la première swimlane', '%s moved the task #%d to the swimlane "%s"' => '%s a déplacé la tâche n°%d dans la swimlane « %s »', 'Swimlane' => 'Swimlane', - 'Budget overview' => 'Vue d\'ensemble du budget', - 'Type' => 'Type', - 'There is not enough data to show something.' => 'Il n\'y a pas assez de données pour montrer quelque chose.', 'Gravatar' => 'Gravatar', 'Hipchat' => 'Hipchat', 'Slack' => 'Slack', '%s moved the task %s to the first swimlane' => '%s a déplacé la tâche %s dans la première swimlane', - '%s moved the task %s to the swimlane "%s"' => '%s a déplacé la tâche %s dans la swimlane « %s »', - 'This report contains all subtasks information for the given date range.' => 'Ce rapport contient les informations de toutes les sous-tâches pour la période selectionnée.', - 'This report contains all tasks information for the given date range.' => 'Ce rapport contient les informations de toutes les tâches pour la période selectionnée.', + '%s moved the task %s to the swimlane "%s"' => '%s a déplacé la tâche %s dans la swimlane « %s »', + 'This report contains all subtasks information for the given date range.' => 'Ce rapport contient les informations de toutes les sous-tâches pour la période sélectionnée.', + 'This report contains all tasks information for the given date range.' => 'Ce rapport contient les informations de toutes les tâches pour la période sélectionnée.', 'Project activities for %s' => 'Activité des projets pour « %s »', 'view the board on Kanboard' => 'voir le tableau sur Kanboard', 'The task have been moved to the first swimlane' => 'La tâche a été déplacée dans la première swimlane', @@ -907,15 +875,15 @@ return array( 'Recurrence settings have been modified' => 'Les réglages de la récurrence ont été modifiés', 'Time spent changed: %sh' => 'Le temps passé a été changé : %sh', 'Time estimated changed: %sh' => 'Le temps estimé a été changé : %sh', - 'The field "%s" have been updated' => 'Le champ « %s » a été mis à jour', + 'The field "%s" have been updated' => 'Le champ « %s » a été mis à jour', 'The description have been modified' => 'La description a été modifiée', - 'Do you really want to close the task "%s" as well as all subtasks?' => 'Voulez-vous vraiment fermer la tâche « %s » ainsi que toutes ses sous-tâches ?', + 'Do you really want to close the task "%s" as well as all subtasks?' => 'Voulez-vous vraiment fermer la tâche « %s » ainsi que toutes ses sous-tâches ?', 'Swimlane: %s' => 'Swimlane : %s', 'I want to receive notifications for:' => 'Je veux reçevoir les notifications pour :', 'All tasks' => 'Toutes les Tâches', 'Only for tasks assigned to me' => 'Seulement les tâches qui me sont assignées', 'Only for tasks created by me' => 'Seulement les tâches que j\'ai créées', - 'Only for tasks created by me and assigned to me' => 'Seulement les tâches créées par moi-même et celles qui me sont asignées', + 'Only for tasks created by me and assigned to me' => 'Seulement les tâches créées par moi-même et celles qui me sont assignées', '%A' => '%A', '%b %e, %Y, %k:%M %p' => '%d/%m/%Y %H:%M', 'New due date: %B %e, %Y' => 'Nouvelle date d\'échéance : %d/%m/%Y', @@ -995,7 +963,7 @@ return array( 'Github Id' => 'Identifiant Github', 'Remote user' => 'Utilisateur distant', 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Les utilisateurs distants ne stockent pas leur mot de passe dans la base de données de Kanboard, exemples : comptes LDAP, Github ou Google.', - 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si vous cochez la case « Interdir le formulaire d\'authentification », les identifiants entrés dans le formulaire d\'authentification seront ignorés.', + 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si vous cochez la case « Interdire le formulaire d\'authentification », les identifiants entrés dans le formulaire d\'authentification seront ignorés.', 'By @%s on Gitlab' => 'Par @%s sur Gitlab', 'Gitlab issue comment created' => 'Commentaire créé sur un ticket Gitlab', 'New remote user' => 'Créer un utilisateur distant', @@ -1023,14 +991,14 @@ return array( 'Sort by position' => 'Trier par position', 'Sort by date' => 'Trier par date', 'Add task' => 'Ajouter une tâche', - 'Start date:' => 'Date de début :', - 'Due date:' => 'Date d\'échéance :', + 'Start date:' => 'Date de début :', + 'Due date:' => 'Date d\'échéance :', 'There is no start date or due date for this task.' => 'Il n\'y a pas de date de début ou de date de fin pour cette tâche.', 'Moving or resizing a task will change the start and due date of the task.' => 'Déplacer ou redimensionner une tâche va changer la date de début et la date de fin de la tâche.', - 'There is no task in your project.' => 'Il n\'y a aucun tâche dans votre projet.', + 'There is no task in your project.' => 'Il n\'y a aucune tâche dans votre projet.', 'Gantt chart' => 'Diagramme de Gantt', - 'People who are project managers' => 'Personnes qui sont gestionnaire de projet', - 'People who are project members' => 'Personnes qui sont membre de projet', + 'People who are project managers' => 'Personnes qui sont gestionnaires de projet', + 'People who are project members' => 'Personnes qui sont membres de projet', 'NOK - Norwegian Krone' => 'NOK - Couronne norvégienne', 'Show this column' => 'Montrer cette colonne', 'Hide this column' => 'Cacher cette colonne', @@ -1043,14 +1011,14 @@ return array( 'Project managers' => 'Gestionnaires de projet', 'Project members' => 'Membres de projet', 'Gantt chart for all projects' => 'Diagramme de Gantt pour tous les projets', - 'Projects list' => 'List des projets', + 'Projects list' => 'Liste des projets', 'Gantt chart for this project' => 'Diagramme de Gantt pour ce projet', 'Project board' => 'Tableau du projet', - 'End date:' => 'Date de fin :', + 'End date:' => 'Date de fin :', 'There is no start date or end date for this project.' => 'Il n\'y a pas de date de début ou de date de fin pour ce projet.', 'Projects Gantt chart' => 'Diagramme de Gantt des projets', - 'Start date: %s' => 'Date de début : %s', - 'End date: %s' => 'Date de fin : %s', + 'Start date: %s' => 'Date de début : %s', + 'End date: %s' => 'Date de fin : %s', 'Link type' => 'Type de lien', 'Change task color when using a specific task link' => 'Changer la couleur de la tâche lorsqu\'un lien spécifique est utilisé', 'Task link creation or modification' => 'Création ou modification d\'un lien sur une tâche', diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index b346f1e3..a3bbd8f5 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Távoli', 'Enabled' => 'Engedélyezve', 'Disabled' => 'Letiltva', - 'Google account linked' => 'Google fiók összekapcsolva', - 'Github account linked' => 'Github fiók összekapcsolva', 'Username:' => 'Felhasználónév:', 'Name:' => 'Név:', 'Email:' => 'E-mail:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'VÃzszintes görgetés', 'Compact/wide view' => 'Kompakt/széles nézet', 'No results match:' => 'Nincs találat:', - 'Remove hourly rate' => 'Órabér törlése', - 'Do you really want to remove this hourly rate?' => 'Valóban törölni kÃvánja az órabért?', - 'Hourly rates' => 'Órabérek', - 'Hourly rate' => 'Órabér', 'Currency' => 'Pénznem', - 'Effective date' => 'Hatálybalépés ideje', - 'Add new rate' => 'Új bér', - 'Rate removed successfully.' => 'Bér sikeresen törölve.', - 'Unable to remove this rate.' => 'Bér törlése sikertelen.', - 'Unable to save the hourly rate.' => 'Órabér mentése sikertelen.', - 'Hourly rate created successfully.' => 'Órabér sikeresen mentve.', 'Start time' => 'Kezdés ideje', 'End time' => 'Végzés ideje', 'Comment' => 'Megjegyzés', @@ -703,34 +691,18 @@ return array( 'Files' => 'Fájlok', 'Images' => 'Képek', 'Private project' => 'Privát projekt', - 'Amount' => 'Összeg', 'AUD - Australian Dollar' => 'AUD - Ausztrál dollár', - 'Budget' => 'Költségvetés', - 'Budget line' => 'Költségvetési tétel', - 'Budget line removed successfully.' => 'Költségvetési tétel sikeresen törölve.', - 'Budget lines' => 'Költségvetési tételek', 'CAD - Canadian Dollar' => 'CAD - Kanadai dollár', 'CHF - Swiss Francs' => 'CHF - Svájci frank', - 'Cost' => 'Költség', - 'Cost breakdown' => 'Költség visszaszámlálás', 'Custom Stylesheet' => 'Egyéni sÃtluslap', 'download' => 'letöltés', - 'Do you really want to remove this budget line?' => 'Biztos törölni akarja ezt a költségvetési tételt?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Kiadások', 'GBP - British Pound' => 'GBP - Angol font', 'INR - Indian Rupee' => 'INR - Indiai rúpia', 'JPY - Japanese Yen' => 'JPY - Japán Yen', - 'New budget line' => 'Új költségvetési tétel', 'NZD - New Zealand Dollar' => 'NZD - Új-Zélandi dollár', - 'Remove a budget line' => 'Költségvetési tétel törlése', - 'Remove budget line' => 'Költségvetési tétel törlése', 'RSD - Serbian dinar' => 'RSD - Szerb dÃnár', - 'The budget line have been created successfully.' => 'Költségvetési tétel sikeresen létrehozva.', - 'Unable to create the budget line.' => 'Költségvetési tétel létrehozása sikertelen.', - 'Unable to remove this budget line.' => 'Költségvetési tétel törlése sikertelen.', 'USD - US Dollar' => 'USD - Amerikai ollár', - 'Remaining' => 'Maradék', 'Destination column' => 'Cél oszlop', 'Move the task to another column when assigned to a user' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés után', 'Move the task to another column when assignee is cleared' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés törlésekor', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php new file mode 100644 index 00000000..a7b52c6f --- /dev/null +++ b/app/Locale/id_ID/translations.php @@ -0,0 +1,1072 @@ +<?php + +return array( + 'number.decimals_separator' => ',', + 'number.thousands_separator' => ' ', + 'None' => 'Tidak satupun', + 'edit' => 'modifikasi', + 'Edit' => 'Modifikasi', + 'remove' => 'hapus', + 'Remove' => 'Hapus', + 'Update' => 'Perbaharui', + 'Yes' => 'Ya', + 'No' => 'Tidak', + 'cancel' => 'batal', + 'or' => 'atau', + 'Yellow' => 'Kuning', + 'Blue' => 'Biru', + 'Green' => 'Hijau', + 'Purple' => 'Ungu', + 'Red' => 'Merah', + 'Orange' => 'Jingga', + 'Grey' => 'Abu-abu', + 'Brown' => 'Coklat', + 'Deep Orange' => 'Oranye', + 'Dark Grey' => 'Abu-abu Gelap', + 'Pink' => 'Merah Muda', + 'Teal' => 'Teal', + 'Cyan'=> 'Sian', + 'Lime' => 'Lime', + 'Light Green' => 'Hijau Muda', + 'Amber' => 'Amber', + 'Save' => 'Simpan', + 'Login' => 'Masuk', + 'Official website:' => 'Situs resmi :', + 'Unassigned' => 'Belum ditugaskan', + 'View this task' => 'Lihat tugas ini', + 'Remove user' => 'Hapus pengguna', + 'Do you really want to remove this user: "%s"?' => 'Anda yakin akan menghapus pengguna ini : « %s » ?', + 'New user' => 'Pengguna baru', + 'All users' => 'Semua pengguna', + 'Username' => 'Nama pengguna', + 'Password' => 'Kata sandi', + 'Administrator' => 'Administrator', + 'Sign in' => 'Masuk', + 'Users' => 'Pengguna', + 'No user' => 'Tidak ada pengguna', + 'Forbidden' => 'Terlarang', + 'Access Forbidden' => 'Akses Dilarang', + 'Edit user' => 'Rubah Pengguna', + 'Logout' => 'Keluar', + 'Bad username or password' => 'Nama pengguna atau kata sandri buruk', + 'Edit project' => 'Rubah proyek', + 'Name' => 'Nama', + 'Projects' => 'Proyek', + 'No project' => 'Tidak ada proyek', + 'Project' => 'Proyek', + 'Status' => 'Status', + 'Tasks' => 'Tugas', + 'Board' => 'Papan', + 'Actions' => 'Tindakan', + 'Inactive' => 'Non Aktif', + 'Active' => 'Aktif', + 'Add this column' => 'Tambahkan kolom ini', + '%d tasks on the board' => '%d tugas di papan', + '%d tasks in total' => '%d tugas di total', + 'Unable to update this board.' => 'Tidak dapat memperbaharui papan ini', + 'Edit board' => 'Rubah papan', + 'Disable' => 'Nonaktifkan', + 'Enable' => 'Aktifkan', + 'New project' => 'Proyek Baru', + 'Do you really want to remove this project: "%s"?' => 'Apakah anda yakin akan menghapus proyek ini : « %s » ?', + 'Remove project' => 'Hapus proyek', + 'Edit the board for "%s"' => 'Rubah papan untuk « %s »', + 'All projects' => 'Semua proyek', + 'Change columns' => 'Rubah 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' => 'Pengaturan', + 'Application settings' => 'Pengaturan aplikasi', + 'Language' => 'Bahasa', + 'Webhook token:' => 'Token webhook :', + 'API token:' => 'Token API :', + 'Database size:' => 'Ukuran basis data :', + 'Download the database' => 'Unduh basis data', + 'Optimize the database' => 'Optimasi basis data', + '(VACUUM command)' => '(perintah VACUUM)', + '(Gzip compressed Sqlite file)' => '(File Sqlite yang terkompress Gzip)', + 'Close a task' => 'Tutup tugas', + 'Edit a task' => 'Edit tugas', + 'Column' => 'Kolom', + 'Color' => 'Warna', + 'Assignee' => 'Orang yang ditugaskan', + 'Create another task' => 'Buat tugas lain', + 'New task' => 'Tugas baru', + 'Open a task' => 'Buka tugas', + 'Do you really want to open this task: "%s"?' => 'Apakah anda yakin akan membuka tugas ini : « %s » ?', + 'Back to the board' => 'Kembali ke papan', + 'Created on %B %e, %Y at %k:%M %p' => 'Dibuat 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 deskripsi.', + 'Add a new task' => 'Tambah tugas baru', + 'The username is required' => 'nama pengguna diperlukan', + '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 sandi diperlukan', + 'This value must be an integer' => 'Nilai ini harus integer', + 'The username must be unique' => 'Nama pengguna harus unik', + 'The user id is required' => 'Id Pengguna diperlukan', + 'Passwords don\'t match' => 'Kata sandi tidak cocok', + 'The confirmation is required' => 'Konfirmasi diperlukan', + 'The project is required' => 'Proyek diperlukan', + 'The id is required' => 'Id diperlukan', + 'The project id is required' => 'Id proyek diperlukan', + 'The project name is required' => 'Nama proyek diperlukan', + 'This project must be unique' => 'Proyek ini harus unik', + 'The title is required' => 'Judul diperlukan', + 'Settings saved successfully.' => 'Pengaturan berhasil disimpan.', + 'Unable to save your settings.' => 'Tidak dapat menyimpan pengaturan anda.', + 'Database optimization done.' => 'Optimasi basis data selesai.', + 'Your project have been created successfully.' => 'Proyek anda berhasil dibuat.', + 'Unable to create your project.' => 'Tidak dapat membuat proyek anda.', + 'Project updated successfully.' => 'Proyek berhasil diperbaharui.', + 'Unable to update this project.' => 'Tidak dapat memperbaharui proyek ini.', + 'Unable to remove this project.' => 'Tidak dapat menghapus proyek ini.', + 'Project removed successfully.' => 'Proyek berhasil dihapus.', + 'Project activated successfully.' => 'Proyek berhasil diaktivasi.', + 'Unable to activate this project.' => 'Tidak dapat mengaktifkan proyek ini.', + 'Project disabled successfully.' => 'Proyek berhasil dinonaktifkan.', + 'Unable to disable this project.' => 'Tidak dapat menonaktifkan proyek 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 proyek ini', + 'Public link' => 'Tautan publik', + 'There is no column in your project!' => 'Tidak ada kolom didalam proyek anda!', + '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', + 'Edit project access list' => 'Modifikasi hak akses proyek', + 'Allow this user' => 'Memperbolehkan pengguna ini', + 'Don\'t forget that administrators have access to everything.' => 'Ingat bahwa administrator memiliki akses ke semua.', + 'Revoke' => 'Mencabut', + 'List of authorized users' => 'Daftar pengguna yang berwenang', + 'User' => 'Pengguna', + 'Nobody have access to this project.' => 'Tidak ada yang berwenang untuk mengakses proyek.', + '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 proyek 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 proyek 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 proyek lain', + 'Duplicate' => 'Duplikasi', + 'link' => 'tautan', + '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 sandi saat ini untuk pengguna « %s »', + 'The current password is required' => 'Kata sandi saat ini diperlukan', + 'Wrong password' => 'Kata sandi 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.' => 'Akun eksternal anda tidak lagi terhubung ke profil anda.', + 'Unable to unlink your external account.' => 'Tidak dapat memutuskan akun eksternal anda.', + 'External authentication failed' => 'Otentifikasi eksternal gagal', + 'Your external account is linked to your profile successfully.' => 'Akun eksternal anda berhasil dihubungkan ke profil anda.', + 'Email' => 'Email', + 'Link my Google Account' => 'Hubungkan akun Google saya', + 'Unlink my Google Account' => 'Putuskan akun Google saya', + 'Login with my Google Account' => 'Masuk menggunakan akun Google saya', + 'Project not found.' => 'Proyek 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 proyek « %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 » ?', + 'open' => 'buka', + '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 proyek lain', + 'Login with my Github Account' => 'Masuk menggunakan akun Github saya', + 'Link my Github Account' => 'Hubungkan akun Github saya ', + 'Unlink my Github Account' => 'Putuskan akun 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 proyek berhasil.', + 'Unable to clone this project.' => 'Tidak dapat mengkloning proyek.', + 'Email notifications' => 'Pemberitahuan email', + '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 ditambahkan', + 'New comment posted by %s' => 'Komentar baru ditambahkan oleh « %s »', + 'New attachment' => 'Lampirkan baru', + 'New comment' => 'Komentar baru', + 'Comment updated' => 'Komentar diperbaharui', + 'New subtask' => 'Sub-tugas baru', + 'Subtask updated' => 'Sub-tugas diperbaharui', + 'New task' => 'Tugas baru', + '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 proyek-proyek yang dipilih :', + 'view the task on Kanboard' => 'lihat tugas di Kanboard', + 'Public access' => 'Akses publik', + 'User management' => 'Manajemen pengguna', + 'Active tasks' => 'Tugas aktif', + 'Disable public access' => 'Nonaktifkan akses publik', + 'Enable public access' => 'Aktifkan akses publik', + 'Public access disabled' => 'Akses publik dinonaktifkan', + 'Do you really want to disable this project: "%s"?' => 'Apakah anda yakin akan menonaktifkan proyek ini : « %s » ?', + 'Do you really want to enable this project: "%s"?' => 'Apakah anda yakin akan mengaktifkan proyek ini : « %s » ?', + 'Project activation' => 'Aktivasi proyek', + 'Move the task to another project' => 'Pindahkan tugas ke proyek lain', + 'Move to another project' => 'Pindahkan ke proyek lain', + 'Do you really want to duplicate this task?' => 'Apakah anda yakin akan menduplikasi tugas ini ?', + 'Duplicate a task' => 'Duplikasi tugas', + 'External accounts' => 'Akun eksternal', + 'Account type' => 'Tipe akun', + 'Local' => 'Lokal', + 'Remote' => 'Jauh', + 'Enabled' => 'Aktif', + 'Disabled' => 'Nonaktif', + 'Google account linked' => 'Akun Google yang terhubung', + 'Github account linked' => 'Akun Github yang terhubung', + 'Username:' => 'Nama pengguna :', + 'Name:' => 'Nama :', + 'Email:' => 'Email :', + 'Notifications:' => 'Pemberitahuan :', + 'Notifications' => 'Pemberitahuan', + 'Group:' => 'Grup :', + 'Regular user' => 'Pengguna normal', + 'Account type:' => 'Tipe akun :', + 'Edit profile' => 'Modifikasi profil', + 'Change password' => 'Rubah kata sandri', + 'Password modification' => 'Modifikasi kata sandi', + 'External authentications' => 'Otentifikasi eksternal', + 'Google Account' => 'Akun Google', + 'Github Account' => 'Akun Github', + 'Never connected.' => 'Tidak pernah terhubung.', + 'No account linked.' => 'Tidak ada akun terhubung.', + 'Account linked.' => 'Akun terhubung.', + 'No external authentication enabled.' => 'Tidak ada otentifikasi eksternal yang aktif.', + 'Password modified successfully.' => 'Kata sandi berhasil dimodifikasi.', + 'Unable to change the password.' => 'Tidak dapat merubah kata sandir.', + 'Change category for the task "%s"' => 'Rubah kategori untuk tugas « %s »', + 'Change category' => 'Rubah 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' => 'Tidak ada 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 proyek 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 sandi baru untuk pengguna « %s »', + 'Choose an event' => 'Pilih acara', + 'Github commit received' => 'Menerima komit dari Github', + 'Github issue opened' => 'Tiket Github dibuka', + 'Github issue closed' => 'Tiket Github ditutup', + 'Github issue reopened' => 'Tiket Github dibuka kembali', + 'Github issue assignee change' => 'Rubah penugasan tiket Github', + 'Github issue label change' => 'Perubahan label pada tiket Github', + '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' => 'Basis data', + 'About' => 'Tentang', + 'Database driver:' => 'Driver basis data :', + 'Board settings' => 'Pengaturan papan', + 'URL and token' => 'URL dan token', + 'Webhook settings' => 'Pengaturan webhook', + 'URL for task creation:' => 'URL untuk pembuatan tugas :', + 'Reset token' => 'Mereset 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 detik)', + 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frequensi 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://exemple.kanboard.net/ (digunakan untuk pemberitahuan email)', + 'Token regenerated.' => 'Token diregenerasi.', + 'Date format' => 'Format tanggal', + 'ISO format is always accepted, example: "%s" and "%s"' => 'Format ISO selalu diterima, contoh : « %s » et « %s »', + 'New private project' => 'Proyek pribadi baru', + 'This project is private' => 'Proyek ini adalah pribadi', + 'Type here to create a new sub-task' => 'Ketik disini untuk membuat sub-tugas baru', + 'Add' => 'Tambah', + 'Estimated time: %s hours' => 'Perkiraan waktu: %s jam', + 'Time spent: %s hours' => 'Waktu dihabiskan : %s jam', + 'Started on %B %e, %Y' => 'Dimulai pada %d/%m/%Y', + 'Start date' => 'Tanggal mulai', + 'Time estimated' => 'Perkiraan waktu', + '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 proyek ini', + 'Everybody have access to this project.' => 'Semua orang mendapat akses untuk proyek ini.', + 'Webhooks' => 'Webhooks', + 'API' => 'API', + 'Github webhooks' => 'Webhook Github', + 'Help on Github webhooks' => 'Bantuan pada webhook Github', + 'Create a comment from an external provider' => 'Buat komentar dari pemasok eksternal', + 'Github issue comment created' => 'Komentar dibuat pada tiket Github', + 'Project management' => 'Manajemen proyek', + 'My projects' => 'Proyek saya', + 'Columns' => 'Kolom', + 'Task' => 'Tugas', + 'Your are not member of any project.' => 'Anda bukan anggota dari setiap proyek.', + '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 proyek ini', + 'Column removed successfully.' => 'Kolom berhasil dihapus.', + 'Github Issue' => 'Tiket Github', + '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 proyek 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 proyek harian', + 'Daily project summary export' => 'Ekspor ringkasan proyek harian', + 'Daily project summary export for "%s"' => 'Ekspor ringkasan proyek 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...' => 'Tidak ada yang dapat dilihat...', + 'Preview' => 'Preview', + 'Write' => 'Tulis', + 'Active swimlanes' => 'Swimlanes aktif', + 'Add a new swimlane' => 'Tambah swimlane baru', + 'Change default swimlane' => 'Modifikasi standar swimlane', + 'Default swimlane' => 'Standar swimlane', + 'Do you really want to remove this swimlane: "%s"?' => 'Apakah anda yakin akan menghapus swimlane ini : « %s » ?', + 'Inactive swimlanes' => 'Swimlanes tidak aktif', + 'Set project manager' => 'Masukan manajer proyek', + 'Set project member' => 'Masukan anggota proyek ', + 'Remove a swimlane' => 'Supprimer une swimlane', + 'Rename' => 'Ganti nama', + 'Show default swimlane' => 'Perlihatkan standar swimlane', + 'Swimlane modification for the project "%s"' => 'Modifikasi swimlane untuk proyek « %s »', + 'Swimlane not found.' => 'Swimlane tidak ditemukan.', + 'Swimlane removed successfully.' => 'Swimlane berhasil dihapus.', + 'Swimlanes' => 'Swimlanes', + 'Swimlane updated successfully.' => 'Swimlane berhasil diperbaharui.', + '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 Fitur, Perbaikan »', + 'Default categories for new projects (Comma-separated)' => 'Standar kategori untuk proyek baru (dipisahkan dengan koma)', + 'Gitlab commit received' => 'Menerima komit Gitlab', + 'Gitlab issue opened' => 'Tiket Gitlab dibuka', + 'Gitlab issue closed' => 'Tiket Gitlab ditutup', + 'Gitlab webhooks' => 'Webhook Gitlab', + 'Help on Gitlab webhooks' => 'Bantuan pada webhook Gitlab', + 'Integrations' => 'Integrasi', + 'Integration with third-party services' => 'Integrasi dengan layanan pihak ketiga', + 'Role for this project' => 'Peran untuk proyek ini', + 'Project manager' => 'Manajer proyek', + 'Project member' => 'Anggota proyek', + 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Seorang manajer proyek dapat mengubah pengaturan proyek dan memiliki lebih banyak keistimewaan dibandingkan dengan pengguna biasa.', + 'Gitlab Issue' => 'Tiket Gitlab', + 'Subtask Id' => 'Id Subtugas', + 'Subtasks' => 'Subtugas', + 'Subtasks Export' => 'Ekspor Subtugas', + 'Subtasks exportation for "%s"' => 'Ekspor subtugas untuk « %s »', + 'Task Title' => 'Judul Tugas', + 'Untitled' => 'Tanpa nama', + 'Application default' => 'Aplikasi standar', + 'Language:' => 'Bahasa :', + 'Timezone:' => 'Zona waktu :', + 'All columns' => 'Semua kolom', + 'Calendar' => 'Kalender', + 'Next' => 'Selanjutnya', + '#%d' => 'nËš%d', + 'All swimlanes' => 'Semua swimlane', + 'All colors' => 'Semua warna', + 'All status' => 'Semua status', + 'Moved to column %s' => 'Pindah ke kolom %s', + 'Change description' => 'Rubah deskripsi', + 'User dashboard' => 'Dasbor 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 proyek mana yang ingin anda duplikasi?', + 'Disallow login form' => 'Larang formulir masuk', + 'Bitbucket commit received' => 'Menerima komit Bitbucket', + 'Bitbucket webhooks' => 'Webhook Bitbucket', + 'Help on Bitbucket webhooks' => 'Bantuan pada webhook Bitbucket', + 'Start' => 'Mulai', + 'End' => 'Selesai', + 'Task age in days' => 'Usia tugas dalam hari', + 'Days in this column' => 'Hari dalam kolom ini', + '%dd' => '%dj', + 'Add a link' => 'Menambahkan tautan', + 'Add a new link' => 'Tambah tautan baru', + 'Do you really want to remove this link: "%s"?' => 'Apakah anda yakin akan menghapus tautan ini : « %s » ?', + 'Do you really want to remove this link with task #%d?' => 'Apakah anda yakin akan menghapus tautan ini dengan tugas n°%d ?', + 'Field required' => 'Field diperlukan', + 'Link added successfully.' => 'Tautan berhasil ditambahkan.', + 'Link updated successfully.' => 'Tautan berhasil diperbaharui.', + 'Link removed successfully.' => 'Tautan berhasil dihapus.', + 'Link labels' => 'Label tautan', + 'Link modification' => 'Modifikasi tautan', + 'Links' => 'Tautan', + 'Link settings' => 'Pengaturan tautan', + 'Opposite label' => 'Label berlawanan', + 'Remove a link' => 'Hapus tautan', + 'Task\'s links' => 'Tautan tugas', + 'The labels must be different' => 'Label harus berbeda', + 'There is no link.' => 'Tidak ada tautan.', + 'This label must be unique' => 'Label ini harus unik', + 'Unable to create your link.' => 'Tidak dapat membuat tautan anda.', + 'Unable to update your link.' => 'Tidak dapat memperbaharui tautan anda.', + 'Unable to remove this link.' => 'Tidak dapat menghapus tautan 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 :', + 'Remove hourly rate' => 'Hapus tarif per jam', + 'Do you really want to remove this hourly rate?' => 'Apakah anda yakin akan menghapus tarif per jam ini?', + 'Hourly rates' => 'Tarif per jam', + 'Hourly rate' => 'Tarif per jam', + 'Currency' => 'Mata uang', + 'Effective date' => 'Tanggal berlaku', + 'Add new rate' => 'Tambah tarif per jam baru', + 'Rate removed successfully.' => 'Tarif per jam berhasil dihapus.', + 'Unable to remove this rate.' => 'Tidak dapat menghapus tarif per jam ini.', + 'Unable to save the hourly rate.' => 'Tidak dapat menyimpan tarif per jam.', + 'Hourly rate created successfully.' => 'Tarif per jam berhasil dibuat.', + 'Start time' => 'Waktu mulai', + 'End time' => 'Waktu selesai', + 'Comment' => 'Komentar', + 'All day' => 'Semua hari', + 'Day' => 'Hari', + 'Manage timetable' => 'Mengatur jadwal', + 'Overtime timetable' => 'Jadwal lembur', + 'Time off timetable' => 'Jam absensi', + 'Timetable' => 'Jadwal', + 'Work timetable' => 'Jadwal kerja', + 'Week timetable' => 'Jadwal mingguan', + 'Day timetable' => 'Jadwal harian', + 'From' => 'Dari', + 'To' => 'Untuk', + 'Time slot created successfully.' => 'Slot waktu berhasil dibuat.', + 'Unable to save this time slot.' => 'Tidak dapat menyimpan slot waktu ini.', + 'Time slot removed successfully.' => 'Slot waktu berhasil dihapus.', + 'Unable to remove this time slot.' => 'Tidak dapat menghapus slot waktu ini.', + 'Do you really want to remove this time slot?' => 'Apakah anda yakin akan menghapus slot waktu ini?', + 'Remove time slot' => 'Hapus slot waktu', + 'Add new time slot' => 'Tambah slot waktu baru', + 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Jadwal ini digunakan ketika kotak centang "sepanjang hari" dicentang untuk dijadwalkan cuti dan lembur.', + 'Files' => 'Arsip', + 'Images' => 'Gambar', + 'Private project' => 'Proyek pribadi', + 'Amount' => 'Jumlah', + 'AUD - Australian Dollar' => 'AUD - Dollar Australia', + 'Budget' => 'Anggaran', + 'Budget line' => 'Garis anggaran', + 'Budget line removed successfully.' => 'Garis anggaran berhasil dihapus.', + 'Budget lines' => 'Garis anggaran', + 'CAD - Canadian Dollar' => 'CAD - Dollar Kanada', + 'CHF - Swiss Francs' => 'CHF - Swiss Prancis', + 'Cost' => 'Biaya', + 'Cost breakdown' => 'Rincian biaya', + 'Custom Stylesheet' => 'Kustomisasi Stylesheet', + 'download' => 'unduh', + 'Do you really want to remove this budget line?' => 'Apakah anda yakin akan menghapus garis anggaran ini?', + 'EUR - Euro' => 'EUR - Euro', + 'Expenses' => 'Beban', + 'GBP - British Pound' => 'GBP - Poundsterling inggris', + 'INR - Indian Rupee' => 'INR - Rupe India', + 'JPY - Japanese Yen' => 'JPY - Yen Jepang', + 'New budget line' => 'Garis anggaran baru', + 'NZD - New Zealand Dollar' => 'NZD - Dollar Selandia baru', + 'Remove a budget line' => 'Hapus garis anggaran', + 'Remove budget line' => 'Hapus garis anggaran', + 'RSD - Serbian dinar' => 'RSD - Dinar Serbia', + 'The budget line have been created successfully.' => 'Garis anggaran berhasil dibuat.', + 'Unable to create the budget line.' => 'Tidak dapat membuat garis anggaran.', + 'Unable to remove this budget line.' => 'Tidak dapat menghapus garis anggaran.', + 'USD - US Dollar' => 'USD - Dollar Amerika', + 'Remaining' => 'Sisa', + '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', + 'Show subtask estimates (forecast of future work)' => 'Lihat perkiraan subtugas(perkiraan di masa depan)', + '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', + 'Currency rates are used to calculate project budget.' => 'Nilai tukar mata uang digunakan untuk menghitung anggaran proyek.', + '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', + 'Send notifications to a Slack channel' => 'Kirim pemberitahuan ke saluran Slack', + 'Webhook URL' => 'URL webhook', + 'Help on Slack integration' => 'Bantuan pada integrasi Slack', + '%s remove the assignee of the task %s' => '%s menghapus penugasan dari tugas %s', + 'Send notifications to Hipchat' => 'Kirim pemberitahuan ke Hipchat', + 'API URL' => 'API URL', + 'Room API ID or name' => 'Id kamar API atau nama ', + 'Room notification token' => 'Token notifikasi kamar', + 'Help on Hipchat integration' => 'Bantuan pada integrasi Hipchat', + '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', + 'Enable/disable two factor authentication' => 'Matikan/hidupkan dua faktor otentifikasi', + 'This QR code contains the key URI: ' => 'kode QR ini mengandung kunci URI : ', + 'Save the secret key in your TOTP software (by example Google Authenticator or FreeOTP).' => 'Menyimpan kunci rahasia ini dalam perangkat lunak TOTP anda(misalnya Googel Authenticator atau FreeOTP).', + '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 proyek adalah kode alfanumerik opsional digunakan untuk mengidentifikasi proyek Anda.', + 'Identifier' => 'Identifier', + 'Postmark (incoming emails)' => 'Postmark (email masuk)', + 'Help on Postmark integration' => 'Bantuan pada integrasi Postmark', + 'Mailgun (incoming emails)' => 'Mailgun (email masuk)', + 'Help on Mailgun integration' => 'Bantuan pada integrasi Mailgun', + 'Sendgrid (incoming emails)' => 'Sendgrid (email masuk)', + 'Help on Sendgrid integration' => 'Bantuan pada integrasi Sendgrid', + '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 tautan', + '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' => 'Tautan 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', + 'Jabber (XMPP)' => 'Jabber (XMPP)', + 'Send notifications to Jabber' => 'Kirim pemberitahuan ke Jabber', + 'XMPP server address' => 'alamat server XMPP', + 'Jabber domain' => 'Domain Jabber', + 'Jabber nickname' => 'Nickname Jabber', + 'Multi-user chat room' => 'Multi-pengguna kamar obrolan', + 'Help on Jabber integration' => 'Bantuan pada integrasi Jabber', + 'The server address must use this format: "tcp://hostname:5222"' => 'Alamat server harus menggunakan format ini : « tcp://hostname:5222 »', + 'Calendar settings' => 'Pengaturan kalender', + 'Project calendar view' => 'Tampilan kalender proyek', + 'Project settings' => 'Pengaturan proyek', + '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' => 'Memperbarui tanggal mulai otomatis', + 'iCal feed' => 'iCal feed', + 'Preferences' => 'Preferensi', + '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 proyek-proyek pribadi.', + 'User that will receive the email' => 'Pengguna yang akan menerima email', + 'Email subject' => 'Subjek Email', + 'Date' => 'Tanggal', + 'By @%s on Bitbucket' => 'Oleh @%s pada Bitbucket', + 'Bitbucket Issue' => 'Tiket Bitbucket', + 'Commit made by @%s on Bitbucket' => 'Komit dibuat oleh @%s pada Bitbucket', + 'Commit made by @%s on Github' => 'Komit dibuat oleh @%s pada Github', + 'By @%s on Github' => 'Oleh @%s pada Github', + 'Commit made by @%s on Gitlab' => 'Komit dibuat oleh @%s pada Gitlab', + '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', + 'Bitbucket issue opened' => 'Tiket Bitbucket dibuka', + 'Bitbucket issue closed' => 'Tiket Bitbucket ditutup', + 'Bitbucket issue reopened' => 'Tiket Bitbucket dibuka kembali', + 'Bitbucket issue assignee change' => 'Perubahan penugasan tiket Bitbucket', + 'Bitbucket issue comment created' => 'Komentar dibuat tiket Bitbucket', + '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', + 'Budget overview' => 'Gambaran anggaran', + 'Type' => 'Tipe', + 'There is not enough data to show something.' => 'Tidak ada data yang cukup untuk menunjukkan sesuatu.', + 'Gravatar' => 'Gravatar', + 'Hipchat' => 'Hipchat', + 'Slack' => 'Slack', + '%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 proyek 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 proyek « %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 proyek', + '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 proyek : ', + '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', + 'Channel/Group/User (Optional)' => 'Kanal/Grup/Pengguna (pilihan)', + '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 sandi mereka dalam basis data Kanboard, contoh: akun 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.', + 'By @%s on Gitlab' => 'Dengan @%s pada Gitlab', + 'Gitlab issue comment created' => 'Komentar dibuat pada tiket Gitlab', + '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.' => 'Fitur ini tidak dapat digunakan di semua browsers', + 'There is no destination project available.' => 'Tidak ada destinasi proyek yang tersedia.', + 'Trigger automatically subtask time tracking' => 'Otomatis memicu pelacakan untuk subtugas', + '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' => 'tidak ada kategori', + 'Current assignee: %s' => 'Saat ini ditugaskan : %s', + 'not assigned' => 'Belum ditugaskan', + 'Author:' => 'Penulis :', + 'contributors' => 'kontributor', + 'License:' => 'Lisensi :', + 'License' => 'Lisensi', + 'Project Administrator' => 'Administrator proyek', + 'Enter the text below' => 'Masukkan teks di bawah', + 'Gantt chart for %s' => 'Grafik 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.' => 'Tidak ada 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.' => 'Tidak ada tugas didalam proyek anda.', + 'Gantt chart' => 'Grafik Gantt', + 'People who are project managers' => 'Orang-orang yang menjadi manajer proyek', + 'People who are project members' => 'Orang-orang yang menjadi anggota proyek', + 'NOK - Norwegian Krone' => 'NOK - Krone Norwegia', + 'Show this column' => 'Perlihatkan kolom ini', + 'Hide this column' => 'Sembunyikan kolom ini', + 'open file' => 'buka berkas', + 'End date' => 'Waktu berakhir', + 'Users overview' => 'Ikhtisar pengguna', + 'Managers' => 'Manajer', + 'Members' => 'Anggota', + 'Shared project' => 'Proyek bersama', + 'Project managers' => 'Manajer proyek', + 'Project members' => 'Anggota proyek', + 'Gantt chart for all projects' => 'Grafik Gantt untuk semua proyek', + 'Projects list' => 'Daftar proyek', + 'Gantt chart for this project' => 'Grafik Gantt untuk proyek ini', + 'Project board' => 'Papan proyek', + 'End date:' => 'Waktu berakhir :', + 'There is no start date or end date for this project.' => 'Tidak ada waktu mulai atau waktu berakhir untuk proyek ini', + 'Projects Gantt chart' => 'Proyek grafik Gantt', + 'Start date: %s' => 'Waktu mulai : %s', + 'End date: %s' => 'Waktu berakhir : %s', + 'Link type' => 'Tipe tautan', + 'Change task color when using a specific task link' => 'Rubah warna tugas ketika menggunakan tautan tugas yang spesifik', + 'Task link creation or modification' => 'Tautan pembuatan atau modifikasi tugas ', + 'Login with my Gitlab Account' => 'Masuk menggunakan akun Gitlab saya', + 'Milestone' => 'Milestone', + 'Gitlab Authentication' => 'Authentification Gitlab', + 'Help on Gitlab authentication' => 'Bantuan pada otentifikasi Gitlab', + 'Gitlab Id' => 'Id Gitlab', + 'Gitlab Account' => 'Akun Gitlab', + 'Link my Gitlab Account' => 'Hubungkan akun Gitlab saya', + 'Unlink my Gitlab Account' => 'Putuskan akun Gitlab saya', + 'Documentation: %s' => 'Dokumentasi : %s', + 'Switch to the Gantt chart view' => 'Beralih ke tampilan grafik Gantt', + 'Reset the search/filter box' => 'Atur ulang pencarian/kotak filter', + 'Documentation' => 'Dokumentasi', + 'Table of contents' => 'Daftar isi', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Bantuan dengan izin proyek', +); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index 06e2c5ca..e27245f9 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remoto', 'Enabled' => 'Abilitato', 'Disabled' => 'Disabilitato', - 'Google account linked' => 'Account Google collegato', - 'Github account linked' => 'Account Github collegato', // 'Username:' => '', 'Name:' => 'Nome:', // 'Email:' => '', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Scrolling orizzontale', 'Compact/wide view' => 'Vista compatta/estesa', 'No results match:' => 'Nessun risultato trovato:', - 'Remove hourly rate' => 'Rimuovi tariffa oraria', - 'Do you really want to remove this hourly rate?' => 'Vuoi davvero rimuovere questa tariffa oraria?', - 'Hourly rates' => 'Tariffe orarie', - 'Hourly rate' => 'Tariffa oraria', 'Currency' => 'Valuta', - 'Effective date' => 'Data effettiva', - 'Add new rate' => 'Aggiungi una nuova tariffa', - 'Rate removed successfully.' => 'Tariffa rimossa con successo.', - 'Unable to remove this rate.' => 'Impossibile rimuovere questa tariffa.', - 'Unable to save the hourly rate.' => 'Impossibile salvare la tariffa oraria.', - 'Hourly rate created successfully.' => 'Tariffa oraria creata con successo.', 'Start time' => 'Data di inizio', 'End time' => 'Data di completamento', 'Comment' => 'Commento', @@ -703,34 +691,18 @@ return array( // 'Files' => '', 'Images' => 'Immagini', 'Private project' => 'Progetto privato', - 'Amount' => 'Totale', 'AUD - Australian Dollar' => 'AUD - Dollari Australiani', - 'Budget' => 'Bilancio', - 'Budget line' => 'Limite di bilancio', - 'Budget line removed successfully.' => 'Limite al bilancio rimosso con successo.', - 'Budget lines' => 'Limiti al bilancio', 'CAD - Canadian Dollar' => 'CAD - Dollari Canadesi', 'CHF - Swiss Francs' => 'CHF - Franchi Svizzeri', - 'Cost' => 'Costi', - 'Cost breakdown' => 'Abbattimento dei costi', 'Custom Stylesheet' => 'CSS personalizzato', // 'download' => '', - 'Do you really want to remove this budget line?' => 'Vuoi davvero rimuovere questo limite al bilancio?', // 'EUR - Euro' => '', - 'Expenses' => 'Spese', 'GBP - British Pound' => 'GBP - Pound Inglesi', 'INR - Indian Rupee' => 'INR - Rupie Indiani', 'JPY - Japanese Yen' => 'JPY - Yen Giapponesi', - 'New budget line' => 'Nuovo limite al bilancio', 'NZD - New Zealand Dollar' => 'NZD - Dollari della Nuova Zelanda', - 'Remove a budget line' => 'Rimuovi un limite al bilancio', - 'Remove budget line' => 'Rimuovi limite di bilancio', 'RSD - Serbian dinar' => 'RSD - Dinar Serbi', - 'The budget line have been created successfully.' => 'Il limite al bilancio è stato creato correttamente', - 'Unable to create the budget line.' => 'Impossibile creare il limite al bilancio', - 'Unable to remove this budget line.' => 'Impossibile rimuovere questo limite al bilancio.', 'USD - US Dollar' => 'USD - Dollari Americani', - 'Remaining' => 'Restanti', 'Destination column' => 'Colonna destinazione', 'Move the task to another column when assigned to a user' => 'Sposta il compito in un\'altra colonna quando viene assegnato ad un utente', 'Move the task to another column when assignee is cleared' => 'Sposta il compito in un\'altra colonna quando l\'assegnatario cancellato', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Cambio', 'Change reference currency' => 'Cambia la valuta di riferimento', 'Add a new currency rate' => 'Aggiungi un nuovo tasso di cambio', - 'Currency rates are used to calculate project budget.' => 'I tassi di cambio sono utilizzati per calcolare i bilanci dei progetti', 'Reference currency' => 'Valuta di riferimento', 'The currency rate have been added successfully.' => 'Il tasso di cambio è stato aggiunto con successo.', 'Unable to add this currency rate.' => 'Impossibile aggiungere questo tasso di cambio.', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index cb8c550b..49f92f27 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'リモート', 'Enabled' => '有効', 'Disabled' => '無効', - 'Google account linked' => 'Google アカウントãŒãƒªãƒ³ã‚¯', - 'Github account linked' => 'Github ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒãƒªãƒ³ã‚¯', 'Username:' => 'ユーザå:', 'Name:' => 'åå‰:', 'Email:' => 'Email:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => '縦スクãƒãƒ¼ãƒ«', 'Compact/wide view' => 'コンパクトï¼ãƒ¯ã‚¤ãƒ‰ãƒ“ュー', 'No results match:' => 'çµæžœãŒä¸€è‡´ã—ã¾ã›ã‚“ã§ã—ãŸ', - 'Remove hourly rate' => '毎時レートを削除', - 'Do you really want to remove this hourly rate?' => '毎時レートを削除ã—ã¾ã™ã‹ï¼Ÿ', - 'Hourly rates' => '毎時レート', - 'Hourly rate' => '毎時レート', 'Currency' => '通貨', - 'Effective date' => '有効期é™', - 'Add new rate' => 'æ–°ã—ã„レート', - 'Rate removed successfully.' => 'レートã®å‰Šé™¤ã«æˆåŠŸã—ã¾ã—ãŸã€‚', - 'Unable to remove this rate.' => 'レートを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚', - 'Unable to save the hourly rate.' => '時間毎ã®ãƒ¬ãƒ¼ãƒˆã‚’ä¿å˜ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚', - 'Hourly rate created successfully.' => '時間毎ã®ãƒ¬ãƒ¼ãƒˆã‚’作æˆã—ã¾ã—ãŸã€‚', 'Start time' => '開始時間', 'End time' => '終了時間', 'Comment' => 'コメント', @@ -703,34 +691,18 @@ return array( 'Files' => 'ファイル', 'Images' => 'ç”»åƒ', 'Private project' => 'プライベートプãƒã‚¸ã‚§ã‚¯ãƒˆ', - 'Amount' => 'æ•°é‡', 'AUD - Australian Dollar' => 'AUD - 豪ドル', - 'Budget' => '予算', - 'Budget line' => '予算ライン', - 'Budget line removed successfully.' => '予算ラインを削除ã—ã¾ã—ãŸ.', - 'Budget lines' => '予算ライン', 'CAD - Canadian Dollar' => 'CAD - åŠ ãƒ‰ãƒ«', 'CHF - Swiss Francs' => 'CHF - スイスフラン', - 'Cost' => 'コスト', - 'Cost breakdown' => 'コストブレークダウン', 'Custom Stylesheet' => 'カスタムスタイルシート', 'download' => 'ダウンãƒãƒ¼ãƒ‰', - 'Do you really want to remove this budget line?' => 'ã“ã®äºˆç®—ラインを本当ã«å‰Šé™¤ã—ã¾ã™ã‹ï¼Ÿ', 'EUR - Euro' => 'EUR - ユーãƒ', - 'Expenses' => '支出', 'GBP - British Pound' => 'GBP - 独ãƒãƒ³ãƒ‰', 'INR - Indian Rupee' => 'INR - 伊ルピー', 'JPY - Japanese Yen' => 'JPY - 日本円', - 'New budget line' => 'æ–°ã—ã„予算ライン', 'NZD - New Zealand Dollar' => 'NZD - NZ ドル', - 'Remove a budget line' => '予算ラインã®å‰Šé™¤', - 'Remove budget line' => '予算ラインã®å‰Šé™¤', 'RSD - Serbian dinar' => 'RSD - セルビアデナール', - 'The budget line have been created successfully.' => '予算ラインを作æˆã—ã¾ã—ãŸ', - 'Unable to create the budget line.' => '予算ラインを作æˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚', - 'Unable to remove this budget line.' => '予算ラインを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚', 'USD - US Dollar' => 'USD - 米ドル', - 'Remaining' => '残り', 'Destination column' => '移動先ã®ã‚«ãƒ©ãƒ ', 'Move the task to another column when assigned to a user' => 'ユーザã®å‰²ã‚Šå½“ã¦ã‚’ã—ãŸã‚‰ã‚¿ã‚¹ã‚¯ã‚’ä»–ã®ã‚«ãƒ©ãƒ ã«ç§»å‹•', 'Move the task to another column when assignee is cleared' => 'ユーザã®å‰²ã‚Šå½“ã¦ãŒãªããªã£ãŸã‚‰ã‚¿ã‚¹ã‚¯ã‚’ä»–ã®ã‚«ãƒ©ãƒ ã«ç§»å‹•', @@ -746,7 +718,6 @@ return array( 'Rate' => 'レート', 'Change reference currency' => 'ç¾åœ¨ã®åŸºè»¸é€šè²¨', 'Add a new currency rate' => 'æ–°ã—ã„é€šè²¨ãƒ¬ãƒ¼ãƒˆã‚’è¿½åŠ ', - 'Currency rates are used to calculate project budget.' => '通貨レートã¯ãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆäºˆç®—ã®ç®—出ã«åˆ©ç”¨ã•れã¾ã™ã€‚', 'Reference currency' => '基軸通貨', // 'The currency rate have been added successfully.' => '', 'Unable to add this currency rate.' => 'ã“ã®é€šè²¨ãƒ¬ãƒ¼ãƒˆã‚’è¿½åŠ ã§ãã¾ã›ã‚“。', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php index 155d49b4..9880b921 100644..100755 --- a/app/Locale/nb_NO/translations.php +++ b/app/Locale/nb_NO/translations.php @@ -1,8 +1,8 @@ <?php return array( - // 'number.decimals_separator' => '', - // 'number.thousands_separator' => '', + 'number.decimals_separator' => ',', + 'number.thousands_separator' => '.', 'None' => 'Ingen', 'edit' => 'rediger', 'Edit' => 'Rediger', @@ -14,12 +14,12 @@ return array( 'cancel' => 'avbryt', 'or' => 'eller', 'Yellow' => 'Gul', - 'Blue' => 'BlÃ¥', - 'Green' => 'Grønn', + 'Blue' => 'Blå', + 'Green' => 'Grønn', 'Purple' => 'Lilla', - 'Red' => 'Rød', + 'Red' => 'Rød', 'Orange' => 'Orange', - 'Grey' => 'GrÃ¥', + 'Grey' => 'Grå', // 'Brown' => '', // 'Deep Orange' => '', // 'Dark Grey' => '', @@ -61,7 +61,7 @@ return array( 'Inactive' => 'Inaktiv', 'Active' => 'Aktiv', 'Add this column' => 'Legg til denne kolonnen', - '%d tasks on the board' => '%d Oppgaver pÃ¥ hovedsiden', + '%d tasks on the board' => '%d Oppgaver på hovedsiden', '%d tasks in total' => '%d Oppgaver i alt', 'Unable to update this board.' => 'Ikke mulig at oppdatere hovedsiden', 'Edit board' => 'Endre prosjektsiden', @@ -79,15 +79,15 @@ return array( 'Assigned to %s' => 'Tildelt: %s', 'Remove a column' => 'Fjern en kolonne', 'Remove a column from a board' => 'Fjern en kolonne fra et board', - 'Unable to remove this column.' => 'Ikke mulig fjerne denne kolonnen', + 'Unable to remove this column.' => 'Ikke mulig ø fjerne denne kolonnen', 'Do you really want to remove this column: "%s"?' => 'Vil du fjerne denne kolonnen: "%s"?', 'This action will REMOVE ALL TASKS associated to this column!' => 'Denne handlingen vil SLETTE ALLE OPPGAVER tilknyttet denne kolonnen', 'Settings' => 'Innstillinger', 'Application settings' => 'Applikasjonsinnstillinger', - 'Language' => 'SprÃ¥k', + 'Language' => 'Språk', 'Webhook token:' => 'Webhook token:', 'API token:' => 'API Token:', - 'Database size:' => 'Databasestørrelse:', + 'Database size:' => 'Databasestørrelse:', 'Download the database' => 'Last ned databasen', 'Optimize the database' => 'Optimaliser databasen', '(VACUUM command)' => '(VACUUM kommando)', @@ -99,36 +99,37 @@ return array( 'Assignee' => 'Tildelt', 'Create another task' => 'Opprett en annen oppgave', 'New task' => 'Ny oppgave', - 'Open a task' => 'Ã…pne en oppgave', - 'Do you really want to open this task: "%s"?' => 'Vil du Ã¥pe denne oppgaven: "%s"?', + 'Open a task' => 'Åpne en oppgave', + 'Do you really want to open this task: "%s"?' => 'Vil du åpne denne oppgaven: "%s"?', 'Back to the board' => 'Tilbake til prosjektsiden', 'Created on %B %e, %Y at %k:%M %p' => 'Opprettet %d.%m.%Y - %H:%M', 'There is nobody assigned' => 'Mangler tildeling', 'Column on the board:' => 'Kolonne:', - 'Status is open' => 'Status: Ã¥pen', + 'Status is open' => 'Status: åpen', 'Status is closed' => 'Status: lukket', 'Close this task' => 'Lukk oppgaven', - 'Open this task' => 'Ã…pne denne oppgaven', + 'Open this task' => 'Åpne denne oppgaven', 'There is no description.' => 'Det er ingen beskrivelse.', 'Add a new task' => 'Opprett ny oppgave', - 'The username is required' => 'Brukernavn er pÃ¥krevd', + 'The username is required' => 'Brukernavn er påkrevd', 'The maximum length is %d characters' => 'Den maksimale lengden er %d tegn', 'The minimum length is %d characters' => 'Den minimale lengden er %d tegn', - 'The password is required' => 'Passord er pÃ¥krevet', - 'This value must be an integer' => 'Denne verdien skal være et tall', - 'The username must be unique' => 'Brukernavnet skal være unikt', - 'The user id is required' => 'Bruker-id er pÃ¥krevet', + 'The password is required' => 'Passord er påkrevet', + 'This value must be an integer' => 'Denne verdien skal være et tall', + 'The username must be unique' => 'Brukernavnet skal være unikt', + 'The user id is required' => 'Bruker-id er påkrevet', 'Passwords don\'t match' => 'Passordene stemmer ikke overens', - 'The confirmation is required' => 'Bekreftelse er nødvendig', - 'The project is required' => 'Prosjektet er pÃ¥krevet', - 'The id is required' => 'Id\'en er pÃ¥krevd', - 'The project id is required' => 'Prosjektet-id er pÃ¥krevet', - 'The project name is required' => 'Prosjektnavn er pÃ¥krevet', - 'This project must be unique' => 'Prosjektnavnet skal være unikt', - 'The title is required' => 'Tittel er pÃ¥revet', + 'The confirmation is required' => 'Bekreftelse er nødvendig', + 'The project is required' => 'Prosjektet er påkrevet', + 'The id is required' => 'Id\'en er pøøkrevet', + 'The project id is required' => 'Prosjektet-id er påkrevet', + 'The project name is required' => 'Prosjektnavn er påkrevet', + 'This project must be unique' => 'Prosjektnavnet skal være unikt', + 'The title is required' => 'Tittel er pårevet', + 'There is no active project, the first step is to create a new project.' => 'Det er ingen aktive prosjekter. Førstesteg er åopprette et nytt prosjekt.', 'Settings saved successfully.' => 'Innstillinger lagret.', 'Unable to save your settings.' => 'Innstillinger kunne ikke lagres.', - 'Database optimization done.' => 'Databaseoptimering er fullført.', + 'Database optimization done.' => 'Databaseoptimering er fullført.', 'Your project have been created successfully.' => 'Ditt prosjekt er opprettet.', 'Unable to create your project.' => 'Prosjektet kunne ikke opprettes', 'Project updated successfully.' => 'Prosjektet er oppdatert.', @@ -139,9 +140,9 @@ return array( 'Unable to activate this project.' => 'Prosjektet kunne ikke aktiveres.', 'Project disabled successfully.' => 'Prosjektet er deaktiveret.', 'Unable to disable this project.' => 'Prosjektet kunne ikke deaktiveres.', - 'Unable to open this task.' => 'Oppgaven kunne ikke Ã¥pnes.', - 'Task opened successfully.' => 'Oppgaven er Ã¥pnet.', - 'Unable to close this task.' => 'Oppgaven kunne ikke Ã¥pnes.', + 'Unable to open this task.' => 'Oppgaven kunne ikke åpnes.', + 'Task opened successfully.' => 'Oppgaven er åpnet.', + 'Unable to close this task.' => 'Oppgaven kunne ikke åpnes.', 'Task closed successfully.' => 'Oppgaven er lukket.', 'Unable to update your task.' => 'Oppgaven kunne ikke oppdateres.', 'Task updated successfully.' => 'Oppgaven er oppdatert.', @@ -149,7 +150,7 @@ return array( 'Task created successfully.' => 'Oppgaven er opprettet.', 'User created successfully.' => 'Brukeren er opprettet.', 'Unable to create your user.' => 'Brukeren kunne ikke opprettes.', - 'User updated successfully.' => 'Brukeren er opdateret', + 'User updated successfully.' => 'Brukeren er oppdatert', 'Unable to update your user.' => 'Din bruker kunne ikke oppdateres.', 'User removed successfully.' => 'Brukeren er fjernet.', 'Unable to remove this user.' => 'Brukeren kunne ikke slettes.', @@ -157,13 +158,15 @@ return array( 'Ready' => 'Klar', 'Backlog' => 'Backlog', 'Work in progress' => 'Under arbeid', - 'Done' => 'Utført', + 'Done' => 'Utført', 'Application version:' => 'Versjon:', - 'Completed on %B %e, %Y at %k:%M %p' => 'Fullført %d.%m.%Y - %H:%M', + 'Completed on %B %e, %Y at %k:%M %p' => 'Fullført %d.%m.%Y - %H:%M', '%B %e, %Y at %k:%M %p' => '%d.%m.%Y - %H:%M', 'Date created' => 'Dato for opprettelse', - 'Date completed' => 'Dato for fullført', + 'Date completed' => 'Dato for fullført', 'Id' => 'ID', + 'Completed tasks' => 'Fullførte oppgaver', + 'Completed tasks for "%s"' => 'Fullførte oppgaver for "%s"', '%d closed tasks' => '%d lukkede oppgaver', 'No task for this project' => 'Ingen oppgaver i dette prosjektet', 'Public link' => 'Offentligt lenke', @@ -175,10 +178,10 @@ return array( 'Page not found' => 'Siden er ikke funnet', 'Complexity' => 'Kompleksitet', 'Task limit' => 'Oppgave begrensning', - // 'Task count' => '', + 'Task count' => 'Antall oppgaver', 'Edit project access list' => 'Endre tillatelser for prosjektet', 'Allow this user' => 'Tillat denne brukeren', - 'Don\'t forget that administrators have access to everything.' => 'Hust at administratorer har tilgang til alt.', + 'Don\'t forget that administrators have access to everything.' => 'Husk at administratorer har tilgang til alt.', 'Revoke' => 'Fjern', 'List of authorized users' => 'Liste over autoriserte brukere', 'User' => 'Bruker', @@ -186,14 +189,14 @@ return array( 'Comments' => 'Kommentarer', 'Write your text in Markdown' => 'Skriv din tekst i markdown', 'Leave a comment' => 'Legg inn en kommentar', - 'Comment is required' => 'Kommentar mÃ¥ legges inn', + 'Comment is required' => 'Kommentar må legges inn', 'Leave a description' => 'Legg inn en beskrivelse...', 'Comment added successfully.' => 'Kommentaren er lagt til.', 'Unable to create your comment.' => 'Din kommentar kunne ikke opprettes.', 'Edit this task' => 'Rediger oppgaven', 'Due Date' => 'Forfallsdato', 'Invalid date' => 'Ugyldig dato', - 'Must be done before %B %e, %Y' => 'Skal være utført innen %d.%m.%Y', + 'Must be done before %B %e, %Y' => 'Skal være utført innen %d.%m.%Y', '%B %e, %Y' => '%d.%m.%Y', // '%b %e, %Y' => '', 'Automatic actions' => 'Automatiske handlinger', @@ -205,19 +208,19 @@ return array( 'Automatic actions for the project "%s"' => 'Automatiske handlinger for prosjektet "%s"', 'Defined actions' => 'Definerte handlinger', 'Add an action' => 'Legg til en handling', - 'Event name' => 'Begivenhet', + 'Event name' => 'Hendelsehet', 'Action name' => 'Handling', 'Action parameters' => 'Handlingsparametre', 'Action' => 'Handling', - 'Event' => 'Begivenhet', - 'When the selected event occurs execute the corresponding action.' => 'NÃ¥r den valgtebegivenheten oppstÃ¥r, utføre tilsvarende handlin.', + 'Event' => 'Hendelse', + 'When the selected event occurs execute the corresponding action.' => 'Når den valgte hendelsen oppstår, utfør tilsvarende handling.', 'Next step' => 'Neste', 'Define action parameters' => 'Definer handlingsparametre', 'Save this action' => 'Lagre handlingen', - 'Do you really want to remove this action: "%s"?' => 'Vil du virkelig slette denne handlingen: "%s"?', + 'Do you really want to remove this action: "%s"?' => 'Vil du slette denne handlingen: "%s"?', 'Remove an automatic action' => 'Fjern en automatisk handling', 'Assign the task to a specific user' => 'Tildel oppgaven til en bestemt bruker', - 'Assign the task to the person who does the action' => 'Tildel oppgaven til den person, som utfører handlingen', + 'Assign the task to the person who does the action' => 'Tildel oppgaven til den person, som utfører handlingen', 'Duplicate the task to another project' => 'Kopier oppgaven til et annet prosjekt', 'Move a task to another column' => 'Flytt oppgaven til en annen kolonne', 'Task modification' => 'Oppgaveendring', @@ -236,37 +239,41 @@ return array( 'Remove a comment' => 'Fjern en kommentar', 'Comment removed successfully.' => 'Kommentaren ble fjernet.', 'Unable to remove this comment.' => 'Kommentaren kunne ikke fjernes.', - 'Do you really want to remove this comment?' => 'Vil du virkelig fjerne denne kommentaren?', + 'Do you really want to remove this comment?' => 'Vil du fjerne denne kommentaren?', 'Only administrators or the creator of the comment can access to this page.' => 'Kun administrator eller brukeren, som har oprettet kommentaren har adgang til denne siden.', 'Current password for the user "%s"' => 'Aktivt passord for brukeren "%s"', - 'The current password is required' => 'Passord er pÃ¥krevet', + 'The current password is required' => 'Passord er påkrevet', 'Wrong password' => 'Feil passord', 'Unknown' => 'Ukjent', - 'Last logins' => 'Siste login', + 'Last logins' => 'Siste innlogging', 'Login date' => 'Login dato', 'Authentication method' => 'Godkjenningsmetode', 'IP address' => 'IP Adresse', 'User agent' => 'User Agent', 'Persistent connections' => 'Varige forbindelser', 'No session.' => 'Ingen session.', - 'Expiration date' => 'Utløpsdato', + 'Expiration date' => 'Utløpsdato', 'Remember Me' => 'Husk meg', 'Creation date' => 'Opprettelsesdato', + 'Filter by user' => 'Filtrer efter bruker', + 'Filter by due date' => 'Filtrer etter forfallsdato', 'Everybody' => 'Alle', - 'Open' => 'Ã…pen', + 'Open' => 'Åpen', 'Closed' => 'Lukket', - 'Search' => 'Søk', + 'Search' => 'Søk', 'Nothing found.' => 'Intet funnet.', + 'Search in the project "%s"' => 'Søk i prosjektet "%s"', 'Due date' => 'Forfallsdato', 'Others formats accepted: %s and %s' => 'Andre formater: %s og %s', 'Description' => 'Beskrivelse', '%d comments' => '%d kommentarer', '%d comment' => '%d kommentar', 'Email address invalid' => 'Ugyldig epost', - // 'Your external account is not linked anymore to your profile.' => '', - // 'Unable to unlink your external account.' => '', - // 'External authentication failed' => '', - // 'Your external account is linked to your profile successfully.' => '', + 'Your Google Account is not linked anymore to your profile.' => 'Din Google-konto er ikke lengre knyttet til din profil.', + 'Unable to unlink your Google Account.' => 'Det var ikke mulig ø fjerne din Google-konto.', + 'Google authentication failed' => 'Google godjenning mislyktes', + 'Unable to link your Google Account.' => 'Det var ikke mulig åknytte opp til din Google-konto.', + 'Your Google Account is linked to your profile successfully.' => 'Din Google-konto er knyttet til din profil.', 'Email' => 'Epost', 'Link my Google Account' => 'Knytt til min Google-konto', 'Unlink my Google Account' => 'Fjern knytningen til min Google-konto', @@ -275,9 +282,9 @@ return array( 'Task removed successfully.' => 'Oppgaven er fjernet.', 'Unable to remove this task.' => 'Oppgaven kunne ikke fjernes.', 'Remove a task' => 'Fjern en oppgave', - 'Do you really want to remove this task: "%s"?' => 'Vil du virkelig fjerne denne opgave: "%s"?', + 'Do you really want to remove this task: "%s"?' => 'Vil du fjerne denne oppgaven: "%s"?', 'Assign automatically a color based on a category' => 'Tildel automatisk en farge baseret for en kategori', - 'Assign automatically a category based on a color' => 'Tildel automatisk en kategori basert pÃ¥ en farve', + 'Assign automatically a category based on a color' => 'Tildel automatisk en kategori basert på en farve', 'Task creation or modification' => 'Oppgaveopprettelse eller endring', 'Category' => 'Kategori', 'Category:' => 'Kategori:', @@ -293,17 +300,18 @@ return array( 'Category modification for the project "%s"' => 'Endring av kategori for prosjektet "%s"', 'Category Name' => 'Kategorinavn', 'Add a new category' => 'Legg til ny kategori', - 'Do you really want to remove this category: "%s"?' => 'Vil du virkelig fjerne kategorien: "%s"?', + 'Do you really want to remove this category: "%s"?' => 'Vil du fjerne kategorien: "%s"?', + 'Filter by category' => 'Filter etter kategori', 'All categories' => 'Alle kategorier', 'No category' => 'Ingen kategori', - 'The name is required' => 'Navnet er pÃ¥krevet', + 'The name is required' => 'Navnet er påkrevet', 'Remove a file' => 'Fjern en fil', 'Unable to remove this file.' => 'Filen kunne ikke fjernes.', 'File removed successfully.' => 'Filen er fjernet.', 'Attach a document' => 'Legg til et dokument', - 'Do you really want to remove this file: "%s"?' => 'Vil du virkelig fjerne filen: "%s"?', - 'open' => 'Ã¥pen', - 'Attachments' => 'Vedleggr', + 'Do you really want to remove this file: "%s"?' => 'Vil du fjerne filen: "%s"?', + 'open' => 'øpen', + 'Attachments' => 'Vedlegg', 'Edit the task' => 'Rediger oppgaven', 'Edit the description' => 'Rediger beskrivelsen', 'Add a comment' => 'Legg til en kommentar', @@ -312,8 +320,8 @@ return array( 'Time tracking' => 'Tidsregistrering', 'Estimate:' => 'Estimat:', 'Spent:' => 'Brukt:', - 'Do you really want to remove this sub-task?' => 'Vil du virkelig fjerne denne deloppgaven?', - 'Remaining:' => 'Gjenværende:', + 'Do you really want to remove this sub-task?' => 'Vil du fjerne denne deloppgaven?', + 'Remaining:' => 'Gjenværende:', 'hours' => 'timer', 'spent' => 'brukt', 'estimated' => 'estimat', @@ -324,8 +332,8 @@ return array( 'Time spent' => 'Tidsforbruk', 'Edit a sub-task' => 'Rediger en deloppgave', 'Remove a sub-task' => 'Fjern en deloppgave', - 'The time must be a numeric value' => 'Tiden skal være en nummerisk erdi', - 'Todo' => 'GjøremÃ¥l', + 'The time must be a numeric value' => 'Tiden skal være en nummerisk erdi', + 'Todo' => 'Gjøremål', 'In progress' => 'Under arbeid', 'Sub-task removed successfully.' => 'Deloppgaven er fjernet.', 'Unable to remove this sub-task.' => 'Deloppgaven kunne ikke fjernes.', @@ -333,19 +341,24 @@ return array( 'Unable to update your sub-task.' => 'Deloppgaven kunne ikke opdateres.', 'Unable to create your sub-task.' => 'Deloppgaven kunne ikke oprettes.', 'Sub-task added successfully.' => 'Deloppgaven er lagt til.', - 'Maximum size: ' => 'Maksimum størrelse: ', + 'Maximum size: ' => 'Maksimum størrelse: ', 'Unable to upload the file.' => 'Filen kunne ikke lastes opp.', 'Display another project' => 'Vis annet prosjekt...', - // 'Login with my Github Account' => '', - // 'Link my Github Account' => '', - // 'Unlink my Github Account' => '', + 'Your GitHub account was successfully linked to your profile.' => 'Din GitHub-konto er knyttet til din profil.', + 'Unable to link your GitHub Account.' => 'Det var ikke mulig å knytte din GitHub-konto.', + 'GitHub authentication failed' => 'GitHub godkjenning mislyktes', + 'Your GitHub account is no longer linked to your profile.' => 'Din GitHub-konto er ikke lengere knyttet til din profil.', + 'Unable to unlink your GitHub Account.' => 'Det var ikke muligt at fjerne forbindelsen til din GitHub-konto.', + 'Login with my GitHub Account' => 'Login med min GitHub-konto', + 'Link my GitHub Account' => 'Knytt min GitHub-konto', + 'Unlink my GitHub Account' => 'Fjern knytningen til min GitHub-konto', 'Created by %s' => 'Opprettet av %s', 'Last modified on %B %e, %Y at %k:%M %p' => 'Sist endret %d.%m.%Y - %H:%M', 'Tasks Export' => 'Oppgave eksport', 'Tasks exportation for "%s"' => 'Oppgaveeksportering for "%s"', 'Start Date' => 'Start-dato', 'End Date' => 'Slutt-dato', - 'Execute' => 'KKjør', + 'Execute' => 'KKjør', 'Task Id' => 'Oppgave ID', 'Creator' => 'Laget av', 'Modification date' => 'Endringsdato', @@ -354,15 +367,15 @@ return array( 'Project cloned successfully.' => 'Prosjektet er kopiert.', 'Unable to clone this project.' => 'Prosjektet kunne ikke kopieres', 'Email notifications' => 'Epostvarslinger', - 'Enable email notifications' => 'Aktiver eposvarslinger', + 'Enable email notifications' => 'Aktiver epostvarslinger', 'Task position:' => 'Oppgaveposisjon:', - 'The task #%d have been opened.' => 'Oppgaven #%d er Ã¥pnet.', + 'The task #%d have been opened.' => 'Oppgaven #%d er åpnet.', 'The task #%d have been closed.' => 'Oppgaven #%d er lukket.', 'Sub-task updated' => 'Deloppgaven er oppdatert', 'Title:' => 'Tittel:', 'Status:' => 'Status:', 'Assignee:' => 'Ansvarlig:', - 'Time tracking:' => 'TidsmÃ¥ling:', + 'Time tracking:' => 'Tidsmåling:', 'New sub-task' => 'Ny deloppgave', 'New attachment added "%s"' => 'Nytt vedlegg er lagt tilet "%s"', 'Comment updated' => 'Kommentar oppdatert', @@ -373,21 +386,21 @@ return array( 'Subtask updated' => 'Deloppgave oppdatert', 'Task updated' => 'Oppgave oppdatert', 'Task closed' => 'Oppgave lukket', - 'Task opened' => 'Oppgave Ã¥pnet', + 'Task opened' => 'Oppgave åpnet', 'I want to receive notifications only for those projects:' => 'Jeg vil kun ha varslinger for disse prosjekter:', - 'view the task on Kanboard' => 'se oppgaven pÃ¥hovedsiden', + 'view the task on Kanboard' => 'se oppgaven påhovedsiden', 'Public access' => 'Offentlig tilgang', 'User management' => 'Brukere', 'Active tasks' => 'Aktive oppgaver', 'Disable public access' => 'Deaktiver offentlig tilgang', 'Enable public access' => 'Aktiver offentlig tilgang', 'Public access disabled' => 'Offentlig tilgang er deaktivert', - 'Do you really want to disable this project: "%s"?' => 'Vil du virkelig deaktivere prosjektet: "%s"?', - 'Do you really want to enable this project: "%s"?' => 'Vil du virkelig aktivere prosjektet: "%s"?', + 'Do you really want to disable this project: "%s"?' => 'Vil du deaktivere prosjektet: "%s"?', + 'Do you really want to enable this project: "%s"?' => 'Vil du aktivere prosjektet: "%s"?', 'Project activation' => 'Prosjekt aktivering', 'Move the task to another project' => 'Flytt oppgaven til et annet prosjekt', 'Move to another project' => 'Flytt til et annet prosjekt', - 'Do you really want to duplicate this task?' => 'Vil du virkelig kopiere denne oppgaven?', + 'Do you really want to duplicate this task?' => 'Vil du kopiere denne oppgaven?', 'Duplicate a task' => 'Kopier en oppgave', 'External accounts' => 'Eksterne kontoer', 'Account type' => 'Kontotype', @@ -411,7 +424,7 @@ return array( 'External authentications' => 'Ekstern godkjenning', 'Google Account' => 'Google-konto', 'Github Account' => 'GitHub-konto', - 'Never connected.' => 'Aldri knyttet.', + 'Never connected.' => 'Aldri innlogget.', 'No account linked.' => 'Ingen kontoer knyttet.', 'Account linked.' => 'Konto knyttet.', 'No external authentication enabled.' => 'Ingen eksterne godkjenninger aktiveret.', @@ -420,18 +433,19 @@ return array( 'Change category for the task "%s"' => 'Endre kategori for oppgaven "%s"', 'Change category' => 'Endre kategori', '%s updated the task %s' => '%s oppdaterte oppgaven %s', - '%s opened the task %s' => '%s Ã¥pnet oppgaven %s', + '%s opened the task %s' => '%s åpnet oppgaven %s', '%s moved the task %s to the position #%d in the column "%s"' => '%s flyttet oppgaven %s til posisjonen #%d i kolonnen "%s"', '%s moved the task %s to the column "%s"' => '%s flyttet oppgaven %s til kolonnen "%s"', '%s created the task %s' => '%s opprettet oppgaven %s', '%s closed the task %s' => '%s lukket oppgaven %s', '%s created a subtask for the task %s' => '%s opprettet en deloppgave for oppgaven %s', '%s updated a subtask for the task %s' => '%s oppdaterte en deloppgave for oppgaven %s', - 'Assigned to %s with an estimate of %s/%sh' => 'Tildelt til %s med et estimat pÃ¥ %s/%sh', + 'Assigned to %s with an estimate of %s/%sh' => 'Tildelt til %s med et estimat på %s/%sh', 'Not assigned, estimate of %sh' => 'Ikke tildelt, estimert til %sh', '%s updated a comment on the task %s' => '%s oppdaterte en kommentar til oppgaven %s', '%s commented the task %s' => '%s har kommentert oppgaven %s', '%s\'s activity' => '%s\'s aktvitet', + 'No activity.' => 'Ingen aktivitet', 'RSS feed' => 'RSS feed', '%s updated a comment on the task #%d' => '%s oppdaterte en kommentar til oppgaven #%d', '%s commented on the task #%d' => '%s kommenterte oppgaven #%d', @@ -440,7 +454,7 @@ return array( '%s updated the task #%d' => '%s oppdaterte oppgaven #%d', '%s created the task #%d' => '%s opprettet oppgaven #%d', '%s closed the task #%d' => '%s lukket oppgaven #%d', - '%s open the task #%d' => '%s Ã¥pnet oppgaven #%d', + '%s open the task #%d' => '%s åpnet oppgaven #%d', '%s moved the task #%d to the column "%s"' => '%s flyttet oppgaven #%d til kolonnen "%s"', '%s moved the task #%d to the position %d in the column "%s"' => '%s flyttet oppgaven #%d til posisjonen %d i kolonnen "%s"', 'Activity' => 'Aktivitetslogg', @@ -452,21 +466,21 @@ return array( 'New password for the user "%s"' => 'Nytt passord for brukeren "%s"', 'Choose an event' => 'Velg en hendelse', 'Github commit received' => 'Github forpliktelse mottatt', - 'Github issue opened' => 'Github problem Ã¥pnet', + 'Github issue opened' => 'Github problem åpnet', 'Github issue closed' => 'Github problem lukket', - 'Github issue reopened' => 'Github problem gjenÃ¥pnet', + 'Github issue reopened' => 'Github problem gjenåpnet', 'Github issue assignee change' => 'Endre ansvarlig for Github problem', 'Github issue label change' => 'Endre etikett for Github problem', 'Create a task from an external provider' => 'Oppret en oppgave fra en ekstern tilbyder', - 'Change the assignee based on an external username' => 'Endre ansvarlige baseret pÃ¥ et eksternt brukernavn', - 'Change the category based on an external label' => 'Endre kategorien basert pÃ¥ en ekstern etikett', + 'Change the assignee based on an external username' => 'Endre ansvarlige baseret på et eksternt brukernavn', + 'Change the category based on an external label' => 'Endre kategorien basert på en ekstern etikett', 'Reference' => 'Referanse', 'Reference: %s' => 'Referanse: %s', 'Label' => 'Etikett', 'Database' => 'Database', 'About' => 'Om', 'Database driver:' => 'Database driver:', - 'Board settings' => 'Innstillinger for ptosjektside', + 'Board settings' => 'Innstillinger for prosjektside', 'URL and token' => 'URL og token', 'Webhook settings' => 'Webhook innstillinger', 'URL for task creation:' => 'URL for oppgaveopprettelse:', @@ -475,9 +489,9 @@ return array( 'Refresh interval for private board' => 'Oppdateringsintervall for privat hovedside', 'Refresh interval for public board' => 'Oppdateringsintervall for offentlig hovedside', 'Task highlight period' => 'Fremhevingsperiode for oppgave', - 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode for Ã¥ anta at en oppgave nylig ble endretg (0 for Ã¥ deaktivere, 2 dager som standard)', + 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode for ø anta at en oppgave nylig ble endretg (0 for å deaktivere, 2 dager som standard)', 'Frequency in second (60 seconds by default)' => 'Frekevens i sekunder (60 sekunder som standard)', - 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekvens i sekunder (0 for Ã¥ deaktivere denne funksjonen, 10 sekunder som standard)', + 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekvens i sekunder (0 for øt deaktivere denne funksjonen, 10 sekunder som standard)', 'Application URL' => 'Applikasjons URL', 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Eksempel: http://example.kanboard.net/ (bruges til email notifikationer)', 'Token regenerated.' => 'Token regenerert.', @@ -485,7 +499,7 @@ return array( 'ISO format is always accepted, example: "%s" and "%s"' => 'ISO format er alltid akseptert, eksempelvis: "%s" og "%s"', 'New private project' => 'Nytt privat prosjekt', 'This project is private' => 'Dette projektet er privat', - 'Type here to create a new sub-task' => 'Skriv her for Ã¥ opprette en ny deloppgave', + 'Type here to create a new sub-task' => 'Skriv her for ø opprette en ny deloppgave', 'Add' => 'Legg til', 'Estimated time: %s hours' => 'Estimert tid: %s timer', 'Time spent: %s hours' => 'Tid brukt: %s timer', @@ -510,21 +524,21 @@ return array( 'Columns' => 'Kolonner', 'Task' => 'Oppgave', // 'Your are not member of any project.' => '', - // 'Percentage' => '', - // 'Number of tasks' => '', - // 'Task distribution' => '', - // 'Reportings' => '', + 'Percentage' => 'Prosent', + 'Number of tasks' => 'Antall oppgaver', + 'Task distribution' => 'Kolonnefordeling', + 'Reportings' => 'Rapportering', // 'Task repartition for "%s"' => '', 'Analytics' => 'Analyser', - // 'Subtask' => '', + 'Subtask' => 'Deloppgave', 'My subtasks' => 'Mine deloppgaver', - // 'User repartition' => '', + 'User repartition' => 'Brukerfordeling', // 'User repartition for "%s"' => '', 'Clone this project' => 'Kopier dette prosjektet', - // 'Column removed successfully.' => '', + 'Column removed successfully.' => 'Kolonne flyttet', // 'Github Issue' => '', // 'Not enough data to show the graph.' => '', - // 'Previous' => '', + 'Previous' => 'Forrige', // 'The id must be an integer' => '', // 'The project id must be an integer' => '', // 'The status must be an integer' => '', @@ -536,32 +550,32 @@ return array( // 'This value is required' => '', // 'This value must be numeric' => '', // 'Unable to create this task.' => '', - // 'Cumulative flow diagram' => '', + 'Cumulative flow diagram' => 'Kumulativt flytdiagram', // 'Cumulative flow diagram for "%s"' => '', - // 'Daily project summary' => '', + 'Daily project summary' => 'Daglig prosjektsammendrag', // 'Daily project summary export' => '', // 'Daily project summary export for "%s"' => '', 'Exports' => 'Eksporter', // 'This export contains the number of tasks per column grouped per day.' => '', - 'Nothing to preview...' => 'Ingenting Ã¥ forhÃ¥ndsvise', - 'Preview' => 'ForhÃ¥ndsvisning', + 'Nothing to preview...' => 'Ingenting å forhåndsvise', + 'Preview' => 'Forhåndsvisning', 'Write' => 'Skriv', - 'Active swimlanes' => 'Aktive svæmmebaner', - 'Add a new swimlane' => 'Legg til en ny svømmebane', - 'Change default swimlane' => 'Endre standard svømmebane', - 'Default swimlane' => 'Standard svømmebane', + 'Active swimlanes' => 'Aktive svømmebaner', + 'Add a new swimlane' => 'Legg til en ny svømmebane', + 'Change default swimlane' => 'Endre standard svømmebane', + 'Default swimlane' => 'Standard svømmebane', // 'Do you really want to remove this swimlane: "%s"?' => '', // 'Inactive swimlanes' => '', 'Set project manager' => 'Velg prosjektleder', 'Set project member' => 'Velg prosjektmedlem', - 'Remove a swimlane' => 'Fjern en svømmebane', + 'Remove a swimlane' => 'Fjern en svømmebane', 'Rename' => 'Endre navn', - 'Show default swimlane' => 'Vis standard svømmebane', + 'Show default swimlane' => 'Vis standard svømmebane', // 'Swimlane modification for the project "%s"' => '', - // 'Swimlane not found.' => '', - // 'Swimlane removed successfully.' => '', - 'Swimlanes' => 'Svømmebaner', - 'Swimlane updated successfully.' => 'Svæmmebane oppdatert', + 'Swimlane not found.' => 'Svømmebane ikke funnet', + 'Swimlane removed successfully.' => 'Svømmebane fjernet', + 'Swimlanes' => 'Svømmebaner', + 'Swimlane updated successfully.' => 'Svømmebane oppdatert', // 'The default swimlane have been updated successfully.' => '', // 'Unable to create your swimlane.' => '', // 'Unable to remove this swimlane.' => '', @@ -576,27 +590,32 @@ return array( // 'Help on Gitlab webhooks' => '', 'Integrations' => 'Integrasjoner', 'Integration with third-party services' => 'Integrasjoner med tredje-parts tjenester', - // 'Role for this project' => '', + 'Role for this project' => 'Rolle for dette prosjektet', 'Project manager' => 'Prosjektleder', 'Project member' => 'Prosjektmedlem', 'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Prosjektlederen kan endre flere innstillinger for prosjektet enn den en vanlig bruker kan.', // 'Gitlab Issue' => '', - // 'Subtask Id' => '', - // 'Subtasks' => '', - // 'Subtasks Export' => '', + 'Subtask Id' => 'Deloppgave ID', + 'Subtasks' => 'Deloppgaver', + 'Subtasks Export' => 'Eksporter deloppgaver', // 'Subtasks exportation for "%s"' => '', - // 'Task Title' => '', + 'Task Title' => 'Oppgavetittel', // 'Untitled' => '', 'Application default' => 'Standardinstilling', - 'Language:' => 'SprÃ¥k', + 'Language:' => 'Språk', 'Timezone:' => 'Tidssone', - // 'All columns' => '', + 'All columns' => 'Alle kolonner', + 'Calendar for "%s"' => 'Kalender for "%s"', + 'Filter by column' => 'Filtrer etter kolonne', + 'Filter by status' => 'Filtrer etter status', 'Calendar' => 'Kalender', - // 'Next' => '', + 'Next' => 'Neste', // '#%d' => '', - // 'All swimlanes' => '', - // 'All colors' => '', - // 'All status' => '', + 'Filter by color' => 'Filtrer etter farge', + 'Filter by swimlane' => 'Filtrer etter svømmebane', + 'All swimlanes' => 'Alle svømmebaner', + 'All colors' => 'Alle farger', + 'All status' => 'Alle statuser', // 'Moved to column %s' => '', 'Change description' => 'Endre beskrivelse', 'User dashboard' => 'Brukerens hovedside', @@ -604,16 +623,23 @@ return array( // 'Edit column "%s"' => '', // 'Select the new status of the subtask: "%s"' => '', 'Subtask timesheet' => 'Tidsskjema for deloppgaver', - 'There is nothing to show.' => 'Ingen data Ã¥ vise', + 'There is nothing to show.' => 'Ingen data å vise', // 'Time Tracking' => '', // 'You already have one subtask in progress' => '', - 'Which parts of the project do you want to duplicate?' => 'Hvilke deler av dette prosjektet ønsker du Ã¥ kopiere?', - // 'Disallow login form' => '', + 'Which parts of the project do you want to duplicate?' => 'Hvilke deler av dette prosjektet ønsker du å kopiere?', + 'Change dashboard view' => 'Endre visning', + 'Show/hide activities' => 'Vis/skjul aktiviteter', + 'Show/hide projects' => 'Vis/skjul prosjekter', + 'Show/hide subtasks' => 'Vis/skjul deloppgaver', + 'Show/hide tasks' => 'Vis/skjul oppgaver', + 'Disable login form' => 'Deaktiver innlogging', + 'Show/hide calendar' => 'Vis/skjul kalender', + 'User calendar' => 'Brukerens kalender', // 'Bitbucket commit received' => '', // 'Bitbucket webhooks' => '', // 'Help on Bitbucket webhooks' => '', - // 'Start' => '', - // 'End' => '', + 'Start' => 'Start', + 'End' => 'Slutt', 'Task age in days' => 'Dager siden oppgaven ble opprettet', 'Days in this column' => 'Dager siden oppgaven ble lagt i denne kolonnen', // '%dd' => '', @@ -621,7 +647,7 @@ return array( 'Add a new link' => 'Legg til en ny relasjon', // 'Do you really want to remove this link: "%s"?' => '', // 'Do you really want to remove this link with task #%d?' => '', - // 'Field required' => '', + 'Field required' => 'Feltet må fylles ut', 'Link added successfully.' => 'Ny relasjon er lagt til', 'Link updated successfully.' => 'Relasjon er oppdatert', 'Link removed successfully.' => 'Relasjon er fjernet', @@ -647,8 +673,8 @@ return array( 'is a parent of' => 'er en overordnet oppgave av', 'targets milestone' => 'milepel', 'is a milestone of' => 'er en milepel av', - 'fixes' => 'løser', - 'is fixed by' => 'løses av', + 'fixes' => 'løser', + 'is fixed by' => 'løses av', 'This task' => 'Denne oppgaven', // '<1h' => '', // '%dh' => '', @@ -662,7 +688,9 @@ return array( 'Keyboard shortcuts' => 'Hurtigtaster', // 'Open board switcher' => '', // 'Application' => '', + 'Filter recently updated' => 'Filter nylig oppdatert', 'since %B %e, %Y at %k:%M %p' => 'siden %B %e, %Y at %k:%M %p', + 'More filters' => 'Flere filtre', 'Compact view' => 'Kompakt visning', 'Horizontal scrolling' => 'Bla horisontalt', 'Compact/wide view' => 'Kompakt/bred visning', @@ -680,9 +708,9 @@ return array( // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', - // 'Comment' => '', - // 'All day' => '', - // 'Day' => '', + 'Comment' => 'Kommentar', + 'All day' => 'Alle dager', + 'Day' => 'Dag', 'Manage timetable' => 'Tidstabell', 'Overtime timetable' => 'Overtidstabell', 'Time off timetable' => 'Fritidstabell', @@ -703,18 +731,18 @@ return array( 'Files' => 'Filer', 'Images' => 'Bilder', 'Private project' => 'Privat prosjekt', - // 'Amount' => '', + 'Amount' => 'Beløp', // 'AUD - Australian Dollar' => '', 'Budget' => 'Budsjett', // 'Budget line' => '', // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', + 'Budget lines' => 'Budsjettlinjer', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', + 'Cost' => 'Kostnad', + 'Cost breakdown' => 'Kostnadsnedbryting', // 'Custom Stylesheet' => '', - // 'download' => '', + 'download' => 'last ned', // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', // 'Expenses' => '', @@ -731,10 +759,10 @@ return array( // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', // 'Remaining' => '', - // 'Destination column' => '', - 'Move the task to another column when assigned to a user' => 'Flytt oppgaven til en annen kolonne nÃ¥r den er tildelt en bruker', - 'Move the task to another column when assignee is cleared' => 'Flytt oppgaven til en annen kolonne nÃ¥r ppgavetildeling fjernes ', - // 'Source column' => '', + 'Destination column' => 'Ny kolonne', + 'Move the task to another column when assigned to a user' => 'Flytt oppgaven til en annen kolonne når den er tildelt en bruker', + 'Move the task to another column when assignee is cleared' => 'Flytt oppgaven til en annen kolonne når ppgavetildeling fjernes ', + 'Source column' => 'Opprinnelig kolonne', // 'Show subtask estimates (forecast of future work)' => '', 'Transitions' => 'Statusendringer', // 'Executer' => '', @@ -782,10 +810,10 @@ return array( // 'This chart show the task complexity over the time (Work Remaining).' => '', // 'Screenshot taken %s' => '', 'Add a screenshot' => 'Legg til et skjermbilde', - 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Ta et skjermbilde og trykk CTRL+V for Ã¥ lime det inn her.', + 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Ta et skjermbilde og trykk CTRL+V for å lime det inn her.', 'Screenshot uploaded successfully.' => 'Skjermbilde opplastet', // 'SEK - Swedish Krona' => '', - 'The project identifier is an optional alphanumeric code used to identify your project.' => 'Prosjektkoden er en alfanumerisk kode som kan brukes for Ã¥ identifisere prosjektet', + 'The project identifier is an optional alphanumeric code used to identify your project.' => 'Prosjektkoden er en alfanumerisk kode som kan brukes for å identifisere prosjektet', 'Identifier' => 'Prosjektkode', // 'Postmark (incoming emails)' => '', // 'Help on Postmark integration' => '', @@ -807,26 +835,26 @@ return array( // 'This value must be alphanumeric' => '', 'Edit recurrence' => 'Endre gjentakelser', 'Generate recurrent task' => 'Opprett gjentagende oppgave', - 'Trigger to generate recurrent task' => 'Betingelse for Ã¥ generere gjentakende oppgave', - 'Factor to calculate new due date' => 'Faktor for Ã¥ beregne ny tidsfrist', - 'Timeframe to calculate new due date' => 'Tidsramme for Ã¥ beregne ny tidsfrist', - 'Base date to calculate new due date' => 'Grunnlagsdato for Ã¥ beregne ny tidsfrist', + 'Trigger to generate recurrent task' => 'Betingelse for å generere gjentakende oppgave', + 'Factor to calculate new due date' => 'Faktor for å beregne ny tidsfrist', + 'Timeframe to calculate new due date' => 'Tidsramme for å beregne ny tidsfrist', + 'Base date to calculate new due date' => 'Grunnlagsdato for å beregne ny tidsfrist', 'Action date' => 'Hendelsesdato', - 'Base date to calculate new due date: ' => 'Grunnlagsdato for Ã¥ beregne ny tidsfrist', + 'Base date to calculate new due date: ' => 'Grunnlagsdato for å beregne ny tidsfrist', 'This task has created this child task: ' => 'Denne oppgaven har opprettet denne relaterte oppgaven', 'Day(s)' => 'Dager', 'Existing due date' => 'Eksisterende forfallsdato', - 'Factor to calculate new due date: ' => 'Faktor for Ã¥ beregne ny tidsfrist', - 'Month(s)' => 'MÃ¥neder', + 'Factor to calculate new due date: ' => 'Faktor for å beregne ny tidsfrist', + 'Month(s)' => 'Måneder', 'Recurrence' => 'Gjentakelse', 'This task has been created by: ' => 'Denne oppgaven er opprettet av:', // 'Recurrent task has been generated:' => '', // 'Timeframe to calculate new due date: ' => '', // 'Trigger to generate recurrent task: ' => '', - 'When task is closed' => 'NÃ¥r oppgaven er lukket', - 'When task is moved from first column' => 'NÃ¥r oppgaven er flyttet fra første kolon', - 'When task is moved to last column' => 'NÃ¥r oppgaven er flyttet til siste kolonne', - 'Year(s)' => 'Ã¥r', + 'When task is closed' => 'Når oppgaven er lukket', + 'When task is moved from first column' => 'Når oppgaven er flyttet fra første kolon', + 'When task is moved to last column' => 'Når oppgaven er flyttet til siste kolonne', + 'Year(s)' => 'år', // 'Jabber (XMPP)' => '', // 'Send notifications to Jabber' => '', // 'XMPP server address' => '', @@ -853,16 +881,16 @@ return array( // 'There is no user management for private projects.' => '', // 'User that will receive the email' => '', // 'Email subject' => '', - // 'Date' => '', + 'Date' => 'Dato', // 'By @%s on Bitbucket' => '', // 'Bitbucket Issue' => '', // 'Commit made by @%s on Bitbucket' => '', // 'Commit made by @%s on Github' => '', // 'By @%s on Github' => '', // 'Commit made by @%s on Gitlab' => '', - 'Add a comment log when moving the task between columns' => 'Legg til en kommentar i loggen nÃ¥r en oppgave flyttes mellom kolonnene', - 'Move the task to another column when the category is changed' => 'Flytt oppgaven til en annen kolonne nÃ¥r kategorien endres', - 'Send a task by email to someone' => 'Send en oppgave pÃ¥ epost til noen', + 'Add a comment log when moving the task between columns' => 'Legg til en kommentar i loggen når en oppgave flyttes mellom kolonnene', + 'Move the task to another column when the category is changed' => 'Flytt oppgaven til en annen kolonne når kategorien endres', + 'Send a task by email to someone' => 'Send en oppgave på epost til noen', // 'Reopen a task' => '', // 'Bitbucket issue opened' => '', // 'Bitbucket issue closed' => '', @@ -871,14 +899,14 @@ return array( // 'Bitbucket issue comment created' => '', 'Column change' => 'Endret kolonne', 'Position change' => 'Posisjonsendring', - 'Swimlane change' => 'Endret svømmebane', + 'Swimlane change' => 'Endret svømmebane', 'Assignee change' => 'Endret eier', // '[%s] Overdue tasks' => '', 'Notification' => 'Varsel', // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', - // 'Swimlane' => '', - // 'Budget overview' => '', + 'Swimlane' => 'Svømmebane', + 'Budget overview' => 'Budsjettoversikt', // 'Type' => '', // 'There is not enough data to show something.' => '', // 'Gravatar' => '', @@ -893,6 +921,7 @@ return array( // 'The task have been moved to the first swimlane' => '', // 'The task have been moved to another swimlane:' => '', // 'Overdue tasks for the project "%s"' => '', + 'There is no completed tasks at the moment.' => 'Ingen fullførte oppgaver funnet.', // 'New title: %s' => '', // 'The task is not assigned anymore' => '', // 'New assignee: %s' => '', @@ -908,61 +937,62 @@ return array( // 'The field "%s" have been updated' => '', // 'The description have been modified' => '', // 'Do you really want to close the task "%s" as well as all subtasks?' => '', - // 'Swimlane: %s' => '', - // 'I want to receive notifications for:' => '', + 'Swimlane: %s' => 'Svømmebane: %s', + 'Project calendar' => 'Prosjektkalender', + 'I want to receive notifications for:' => 'Jeg vil motta varslinger om:', 'All tasks' => 'Alle oppgaver', - // 'Only for tasks assigned to me' => '', - // 'Only for tasks created by me' => '', - // 'Only for tasks created by me and assigned to me' => '', + 'Only for tasks assigned to me' => 'Kun oppgaver som er tildelt meg', + 'Only for tasks created by me' => 'Kun oppgaver som er opprettet av meg', + 'Only for tasks created by me and assigned to me' => 'Kun oppgaver som er opprettet av meg og tildelt meg', // '%A' => '', // '%b %e, %Y, %k:%M %p' => '', // 'New due date: %B %e, %Y' => '', // 'Start date changed: %B %e, %Y' => '', // '%k:%M %p' => '', // '%%Y-%%m-%%d' => '', - // 'Total for all columns' => '', - // 'You need at least 2 days of data to show the chart.' => '', + 'Total for all columns' => 'Totalt for alle kolonner', + //'You need at least 2 days of data to show the chart.' => '', // '<15m' => '', // '<30m' => '', 'Stop timer' => 'Stopp timer', 'Start timer' => 'Start timer', 'Add project member' => 'Legg til prosjektmedlem', 'Enable notifications' => 'Aktiver varslinger', - // 'My activity stream' => '', - // 'My calendar' => '', - // 'Search tasks' => '', - // 'Back to the calendar' => '', - // 'Filters' => '', - // 'Reset filters' => '', - // 'My tasks due tomorrow' => '', - // 'Tasks due today' => '', - // 'Tasks due tomorrow' => '', - // 'Tasks due yesterday' => '', - // 'Closed tasks' => '', - // 'Open tasks' => '', - // 'Not assigned' => '', - // 'View advanced search syntax' => '', - // 'Overview' => '', + 'My activity stream' => 'Aktivitetslogg', + 'My calendar' => 'Min kalender', + 'Search tasks' => 'Søk oppgave', + 'Back to the calendar' => 'Tilbake til kalender', + 'Filters' => 'Filtere', + 'Reset filters' => 'Nullstill filter', + 'My tasks due tomorrow' => 'Mine oppgaver med frist i morgen', + 'Tasks due today' => 'Oppgaver med frist i dag', + 'Tasks due tomorrow' => 'Oppgaver med frist i morgen', + 'Tasks due yesterday' => 'Oppgaver med frist i går', + 'Closed tasks' => 'Fullførte oppgaver', + 'Open tasks' => 'Åpne oppgaver', + 'Not assigned' => 'Ikke tildelt', + 'View advanced search syntax' => 'Vis hjelp for avansert søk ', + 'Overview' => 'Oversikt', // '%b %e %Y' => '', - // 'Board/Calendar/List view' => '', - // 'Switch to the board view' => '', - // 'Switch to the calendar view' => '', - // 'Switch to the list view' => '', - // 'Go to the search/filter box' => '', - // 'There is no activity yet.' => '', - // 'No tasks found.' => '', - // 'Keyboard shortcut: "%s"' => '', - // 'List' => '', - // 'Filter' => '', - // 'Advanced search' => '', - // 'Example of query: ' => '', - // 'Search by project: ' => '', - // 'Search by column: ' => '', - // 'Search by assignee: ' => '', - // 'Search by color: ' => '', - // 'Search by category: ' => '', - // 'Search by description: ' => '', - // 'Search by due date: ' => '', + 'Board/Calendar/List view' => 'Oversikt/kalender/listevisning', + 'Switch to the board view' => 'Oversiktsvisning', + 'Switch to the calendar view' => 'Kalendevisning', + 'Switch to the list view' => 'Listevisning', + 'Go to the search/filter box' => 'Gå til søk/filter', + 'There is no activity yet.' => 'Ingen aktiviteter ennå.', + 'No tasks found.' => 'Ingen oppgaver funnet', + 'Keyboard shortcut: "%s"' => 'Hurtigtaster: "%s"', + 'List' => 'Liste', + 'Filter' => 'Filter', + 'Advanced search' => 'Avansert søk', + 'Example of query: ' => 'Eksempel på spørring', + 'Search by project: ' => 'Søk etter prosjekt', + 'Search by column: ' => 'Søk etter kolonne', + 'Search by assignee: ' => 'Søk etter tildelt', + 'Search by color: ' => 'Søk etter farge', + 'Search by category: ' => 'Søk etter kategori', + 'Search by description: ' => 'Søk etter beskrivelse', + 'Search by due date: ' => 'Søk etter frist', // 'Lead and Cycle time for "%s"' => '', // 'Average time spent into each column for "%s"' => '', // 'Average time spent into each column' => '', @@ -996,75 +1026,75 @@ return array( // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '', // 'By @%s on Gitlab' => '', // 'Gitlab issue comment created' => '', - // 'New remote user' => '', - // 'New local user' => '', - // 'Default task color' => '', - // 'Hide sidebar' => '', - // 'Expand sidebar' => '', + 'New remote user' => 'Ny eksternbruker', + 'New local user' => 'Ny internbruker', + 'Default task color' => 'Standard oppgavefarge', + 'Hide sidebar' => 'Skjul sidemeny', + 'Expand sidebar' => 'Vis sidemeny', // 'This feature does not work with all browsers.' => '', // 'There is no destination project available.' => '', // 'Trigger automatically subtask time tracking' => '', // 'Include closed tasks in the cumulative flow diagram' => '', - // 'Current swimlane: %s' => '', - // 'Current column: %s' => '', - // 'Current category: %s' => '', - // 'no category' => '', - // 'Current assignee: %s' => '', - // 'not assigned' => '', - // 'Author:' => '', - // 'contributors' => '', - // 'License:' => '', - // 'License' => '', - // 'Project Administrator' => '', - // 'Enter the text below' => '', - // 'Gantt chart for %s' => '', + 'Current swimlane: %s' => 'Nåværende svømmebane: %s', + 'Current column: %s' => 'Nåværende kolonne: %s', + 'Current category: %s' => ': %s', + 'no category' => 'ingen kategori', + 'Current assignee: %s' => 'Tildelt til %s', + 'not assigned' => 'ikke tildelt', + 'Author:' => 'Opprettet av', + 'contributors' => 'bidragsytere', + 'License:' => 'Lisens:', + 'License' => 'Lisens', + 'Project Administrator' => 'Prosjektadministrator', + 'Enter the text below' => 'Legg inn teksten nedenfor', + 'Gantt chart for %s' => 'Gantt skjema for %s', // 'Sort by position' => '', - // 'Sort by date' => '', - // 'Add task' => '', - // 'Start date:' => '', - // 'Due date:' => '', - // 'There is no start date or due date for this task.' => '', + 'Sort by date' => 'Sorter etter dato', + 'Add task' => 'Legg til oppgave', + 'Start date:' => 'Startdato:', + 'Due date:' => 'Frist:', + 'There is no start date or due date for this task.' => 'Det er ingen startdato eller frist for denne oppgaven', // 'Moving or resizing a task will change the start and due date of the task.' => '', - // 'There is no task in your project.' => '', - // 'Gantt chart' => '', - // 'People who are project managers' => '', - // 'People who are project members' => '', + 'There is no task in your project.' => 'Det er ingen oppgaver i dette prosjektet', + 'Gantt chart' => 'Gantt skjema', + 'People who are project managers' => 'Prosjektledere', + 'People who are project members' => 'Prosjektmedlemmer', // 'NOK - Norwegian Krone' => '', - // 'Show this column' => '', - // 'Hide this column' => '', - // 'open file' => '', - // 'End date' => '', - // 'Users overview' => '', - // 'Managers' => '', - // 'Members' => '', - // 'Shared project' => '', - // 'Project managers' => '', - // 'Project members' => '', + 'Show this column' => 'Vis denne kolonnen', + 'Hide this column' => 'Skjul denne kolonnen', + 'open file' => 'Åpne fil', + 'End date' => 'Sluttdato', + 'Users overview' => 'Brukeroversikt', + 'Managers' => 'Ledere', + 'Members' => 'Medlemmer', + 'Shared project' => 'Delt prosjekt', + 'Project managers' => 'Prosjektledere', + 'Project members' => 'Prosjektmedlemmer', // 'Gantt chart for all projects' => '', - // 'Projects list' => '', - // 'Gantt chart for this project' => '', - // 'Project board' => '', - // 'End date:' => '', + 'Projects list' => 'Prosjektliste', + 'Gantt chart for this project' => 'Gantt skjema for dette prosjektet', + 'Project board' => 'Prosjektsiden', + 'End date:' => 'Sluttdato:', // 'There is no start date or end date for this project.' => '', - // 'Projects Gantt chart' => '', - // 'Start date: %s' => '', - // 'End date: %s' => '', - // 'Link type' => '', + 'Projects Gantt chart' => 'Gantt skjema for prosjekter', + 'Start date: %s' => 'Startdato: %s', + 'End date: %s' => 'Sluttdato: %s', + 'Link type' => 'Relasjonstype', // 'Change task color when using a specific task link' => '', // 'Task link creation or modification' => '', // 'Login with my Gitlab Account' => '', - // 'Milestone' => '', + 'Milestone' => 'Milepæl', // 'Gitlab Authentication' => '', // 'Help on Gitlab authentication' => '', // 'Gitlab Id' => '', // 'Gitlab Account' => '', // 'Link my Gitlab Account' => '', // 'Unlink my Gitlab Account' => '', - // 'Documentation: %s' => '', - // 'Switch to the Gantt chart view' => '', - // 'Reset the search/filter box' => '', - // 'Documentation' => '', - // 'Table of contents' => '', - // 'Gantt' => '', - // 'Help with project permissions' => '', + 'Documentation: %s' => 'Dokumentasjon: %s', + 'Switch to the Gantt chart view' => 'Gantt skjema visning', + 'Reset the search/filter box' => 'Nullstill søk/filter', + 'Documentation' => 'Dokumentasjon', + 'Table of contents' => 'Innholdsfortegnelse', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Hjelp med prosjekttilganger', ); diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php index 23d64163..8be0c61d 100644 --- a/app/Locale/nl_NL/translations.php +++ b/app/Locale/nl_NL/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remote', 'Enabled' => 'Actief', 'Disabled' => 'Inactief', - 'Google account linked' => 'Gelinkt Google Account', - 'Github account linked' => 'Gelinkt Github Account', 'Username:' => 'Gebruikersnaam :', 'Name:' => 'Naam :', 'Email:' => 'Email :', @@ -667,17 +665,7 @@ return array( // 'Horizontal scrolling' => '', // 'Compact/wide view' => '', // 'No results match:' => '', - // 'Remove hourly rate' => '', - // 'Do you really want to remove this hourly rate?' => '', - // 'Hourly rates' => '', - // 'Hourly rate' => '', // 'Currency' => '', - // 'Effective date' => '', - // 'Add new rate' => '', - // 'Rate removed successfully.' => '', - // 'Unable to remove this rate.' => '', - // 'Unable to save the hourly rate.' => '', - // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', // 'Comment' => '', @@ -703,34 +691,18 @@ return array( // 'Files' => '', // 'Images' => '', // 'Private project' => '', - // 'Amount' => '', // 'AUD - Australian Dollar' => '', - // 'Budget' => '', - // 'Budget line' => '', - // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', // 'Custom Stylesheet' => '', // 'download' => '', - // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', - // 'Expenses' => '', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - // 'New budget line' => '', // 'NZD - New Zealand Dollar' => '', - // 'Remove a budget line' => '', - // 'Remove budget line' => '', // 'RSD - Serbian dinar' => '', - // 'The budget line have been created successfully.' => '', - // 'Unable to create the budget line.' => '', - // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', - // 'Remaining' => '', // 'Destination column' => '', // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 9947cf31..d9cfcdbc 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Zdalne', 'Enabled' => 'Odblokowane', 'Disabled' => 'Zablokowane', - 'Google account linked' => 'Połączone konto Google', - 'Github account linked' => 'Połączone konto Github', 'Username:' => 'Nazwa Użytkownika:', 'Name:' => 'ImiÄ™ i Nazwisko', 'Email:' => 'Email: ', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Przewijanie poziome', 'Compact/wide view' => 'PeÅ‚ny/Kompaktowy widok', 'No results match:' => 'Brak wyników:', - 'Remove hourly rate' => 'UsuÅ„ stawkÄ™ godzinowÄ…', - 'Do you really want to remove this hourly rate?' => 'Czy na pewno chcesz usunąć stawkÄ™ godzinowÄ…?', - 'Hourly rates' => 'Stawki godzinowe', - 'Hourly rate' => 'Stawka godzinowa', 'Currency' => 'Waluta', - 'Effective date' => 'Data efektywna', - 'Add new rate' => 'Dodaj nowÄ… stawkÄ™', - 'Rate removed successfully.' => 'Stawka usuniÄ™ta.', - 'Unable to remove this rate.' => 'Nie można usunąć tej stawki.', - 'Unable to save the hourly rate.' => 'Nie można zapisać tej stawki godzinowej.', - 'Hourly rate created successfully.' => 'Stawka godzinowa utworzona pomyÅ›lnie.', 'Start time' => 'RozpoczÄ™to', 'End time' => 'ZakoÅ„czono', 'Comment' => 'Komentarz', @@ -703,34 +691,18 @@ return array( 'Files' => 'Pliki', 'Images' => 'Obrazy', 'Private project' => 'Projekt prywatny', - 'Amount' => 'Ilość', 'AUD - Australian Dollar' => 'AUD - Dolar australijski', - 'Budget' => 'Budżet', - 'Budget line' => 'Linia budżetowa', - 'Budget line removed successfully.' => 'Linia budżetowa usuniÄ™ta.', - 'Budget lines' => 'Linie budżetowe', 'CAD - Canadian Dollar' => 'CAD - Dolar kanadyjski', 'CHF - Swiss Francs' => 'CHF - Frank szwajcarski', - 'Cost' => 'Koszt', - 'Cost breakdown' => 'Analiza kosztów', 'Custom Stylesheet' => 'Niestandardowy arkusz stylów', 'download' => 'pobierz', - 'Do you really want to remove this budget line?' => 'Czy chcesz usunąć tÄ… liniÄ™ budżetowÄ…?', // 'EUR - Euro' => '', - 'Expenses' => 'Wydatki', 'GBP - British Pound' => 'GBP - Funt brytyjski', 'INR - Indian Rupee' => 'INR - Rupia indyjska', 'JPY - Japanese Yen' => 'JPY - Jen japoÅ„ski', - 'New budget line' => 'Nowa linia budżetowa', 'NZD - New Zealand Dollar' => 'NZD - Dolar nowozelandzki', - 'Remove a budget line' => 'UsuÅ„ liniÄ™ budżetowÄ…', - 'Remove budget line' => 'UsuÅ„ liniÄ™ budżetowÄ…', 'RSD - Serbian dinar' => 'RSD - Dinar serbski', - // 'The budget line have been created successfully.' => '', - 'Unable to create the budget line.' => 'Nie można utworzyć linii budżetowej', - 'Unable to remove this budget line.' => 'Nie można usunąć tej linii budżetowej', 'USD - US Dollar' => 'USD - Dolar amerykaÅ„ski', - 'Remaining' => 'PozostaÅ‚o', 'Destination column' => 'Kolumna docelowa', 'Move the task to another column when assigned to a user' => 'PrzenieÅ› zadanie do innej kolumny gdy zostanie przypisane do osoby', 'Move the task to another column when assignee is cleared' => 'PrzenieÅ› zadanie do innej kolumny gdy osoba odpowiedzialna zostanie usuniÄ™ta', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Kurs', 'Change reference currency' => 'ZmieÅ„ walutÄ™ referencyjnÄ…', 'Add a new currency rate' => 'Dodaj nowy kurs waluty', - 'Currency rates are used to calculate project budget.' => 'Kursy walut sÄ… używane do obliczeÅ„ budżetu projektu.', 'Reference currency' => 'Waluta referencyjna', 'The currency rate have been added successfully.' => 'Dodano kurs waluty', 'Unable to add this currency rate.' => 'Nie można dodać kursu waluty', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index 6aa2f4dd..5f849457 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remoto', 'Enabled' => 'Habilitado', 'Disabled' => 'Desabilitado', - 'Google account linked' => 'Conta do Google associada', - 'Github account linked' => 'Conta do Github associada', 'Username:' => 'Usuário:', 'Name:' => 'Nome:', 'Email:' => 'E-mail:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Rolagem horizontal', 'Compact/wide view' => 'Alternar entre a vista compacta e ampliada', 'No results match:' => 'Nenhum resultado:', - 'Remove hourly rate' => 'Retirar taxa horária', - 'Do you really want to remove this hourly rate?' => 'Você deseja realmente remover esta taxa horária?', - 'Hourly rates' => 'Taxas horárias', - 'Hourly rate' => 'Taxa horária', 'Currency' => 'Moeda', - 'Effective date' => 'Data efetiva', - 'Add new rate' => 'Adicionar nova taxa', - 'Rate removed successfully.' => 'Taxa removido com sucesso.', - 'Unable to remove this rate.' => 'ImpossÃvel de remover esta taxa.', - 'Unable to save the hourly rate.' => 'ImpossÃvel salvar a taxa horária.', - 'Hourly rate created successfully.' => 'Taxa horária criada com sucesso.', 'Start time' => 'Horário de inÃcio', 'End time' => 'Horário de término', 'Comment' => 'comentário', @@ -703,34 +691,18 @@ return array( 'Files' => 'Arquivos', 'Images' => 'Imagens', 'Private project' => 'Projeto privado', - 'Amount' => 'Quantia', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', - 'Budget' => 'Orçamento', - 'Budget line' => 'Rubrica orçamental', - 'Budget line removed successfully.' => 'Rubrica orçamental removida com sucesso', - 'Budget lines' => 'Rubricas orçamentais', 'CAD - Canadian Dollar' => 'CAD - Dólar canadense', 'CHF - Swiss Francs' => 'CHF - Francos SuÃços', - 'Cost' => 'Custo', - 'Cost breakdown' => 'Repartição dos custos', 'Custom Stylesheet' => 'Folha de estilo personalizado', 'download' => 'baixar', - 'Do you really want to remove this budget line?' => 'Você deseja realmente remover esta rubrica orçamental?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Despesas', 'GBP - British Pound' => 'GBP - Libra Esterlina', 'INR - Indian Rupee' => 'INR - Rúpia indiana', 'JPY - Japanese Yen' => 'JPY - Iene japonês', - 'New budget line' => 'Nova rubrica orçamental', 'NZD - New Zealand Dollar' => 'NZD - Dólar Neozelandês', - 'Remove a budget line' => 'Remover uma rubrica orçamental', - 'Remove budget line' => 'Remover uma rubrica orçamental', 'RSD - Serbian dinar' => 'RSD - Dinar sérvio', - 'The budget line have been created successfully.' => 'A rubrica orçamental foi criada com sucesso.', - 'Unable to create the budget line.' => 'ImpossÃvel de adicionar esta rubrica orçamental.', - 'Unable to remove this budget line.' => 'ImpossÃvel de remover esta rubrica orçamental.', 'USD - US Dollar' => 'USD - Dólar norte-americano', - 'Remaining' => 'Restante', 'Destination column' => 'Coluna de destino', 'Move the task to another column when assigned to a user' => 'Mover a tarefa para uma outra coluna quando esta está atribuÃda a um usuário', 'Move the task to another column when assignee is cleared' => 'Mover a tarefa para uma outra coluna quando esta não está atribuÃda', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Taxa', 'Change reference currency' => 'Mudar a moeda de referência', 'Add a new currency rate' => 'Adicionar uma nova taxa para uma moeda', - 'Currency rates are used to calculate project budget.' => 'As taxas de câmbio são utilizadas para calcular o orçamento do projeto.', 'Reference currency' => 'Moeda de Referência', 'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.', 'Unable to add this currency rate.' => 'ImpossÃvel de adicionar essa taxa de câmbio.', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s moveu a tarefa n° %d no primeiro swimlane', '%s moved the task #%d to the swimlane "%s"' => '%s moveu a tarefa n° %d no swimlane "%s"', 'Swimlane' => 'Swimlane', - 'Budget overview' => 'Visão geral do orçamento', - 'Type' => 'Tipo', - 'There is not enough data to show something.' => 'Não há dados suficientes para mostrar alguma coisa.', 'Gravatar' => 'Gravatar', 'Hipchat' => 'Hipchat', 'Slack' => 'Slack', @@ -1060,11 +1028,11 @@ return array( 'Gitlab Account' => 'Conta Gitlab', 'Link my Gitlab Account' => 'Vincular minha conta Gitlab', 'Unlink my Gitlab Account' => 'Desvincular minha conta Gitlab', - // 'Documentation: %s' => '', - // 'Switch to the Gantt chart view' => '', - // 'Reset the search/filter box' => '', - // 'Documentation' => '', - // 'Table of contents' => '', - // 'Gantt' => '', - // 'Help with project permissions' => '', + 'Documentation: %s' => 'Documentação: %s', + 'Switch to the Gantt chart view' => 'Mudar para a vista gráfico de Gantt', + 'Reset the search/filter box' => 'Reiniciar o campo de pesquisa', + 'Documentation' => 'Documentação', + 'Table of contents' => 'Ãndice', + 'Gantt' => 'Gantt', + 'Help with project permissions' => 'Ajuda com as permissões dos projetos', ); diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php index ae73af1e..9e20b112 100644 --- a/app/Locale/pt_PT/translations.php +++ b/app/Locale/pt_PT/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Remoto', 'Enabled' => 'Activado', 'Disabled' => 'Desactivado', - 'Google account linked' => 'Conta do Google associada', - 'Github account linked' => 'Conta do Github associada', 'Username:' => 'Utilizador:', 'Name:' => 'Nome:', 'Email:' => 'E-mail:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Deslocamento horizontal', 'Compact/wide view' => 'Alternar entre a vista compacta e ampliada', 'No results match:' => 'Nenhum resultado:', - 'Remove hourly rate' => 'Retirar taxa horária', - 'Do you really want to remove this hourly rate?' => 'Tem a certeza que quer remover esta taxa horária?', - 'Hourly rates' => 'Taxas horárias', - 'Hourly rate' => 'Taxa horária', 'Currency' => 'Moeda', - 'Effective date' => 'Data efectiva', - 'Add new rate' => 'Adicionar nova taxa', - 'Rate removed successfully.' => 'Taxa removido com sucesso.', - 'Unable to remove this rate.' => 'ImpossÃvel de remover esta taxa.', - 'Unable to save the hourly rate.' => 'ImpossÃvel salvar a taxa horária.', - 'Hourly rate created successfully.' => 'Taxa horária criada com sucesso.', 'Start time' => 'Horário de inÃcio', 'End time' => 'Horário de término', 'Comment' => 'comentário', @@ -703,34 +691,18 @@ return array( 'Files' => 'Arquivos', 'Images' => 'Imagens', 'Private project' => 'Projecto privado', - 'Amount' => 'Quantia', 'AUD - Australian Dollar' => 'AUD - Dólar australiano', - 'Budget' => 'Orçamento', - 'Budget line' => 'Rubrica orçamental', - 'Budget line removed successfully.' => 'Rubrica orçamental removida com sucesso', - 'Budget lines' => 'Rubricas orçamentais', 'CAD - Canadian Dollar' => 'CAD - Dólar canadense', 'CHF - Swiss Francs' => 'CHF - Francos SuÃços', - 'Cost' => 'Custo', - 'Cost breakdown' => 'Repartição dos custos', 'Custom Stylesheet' => 'Folha de estilos personalizada', 'download' => 'transferir', - 'Do you really want to remove this budget line?' => 'Tem a certeza que quer remover esta rubrica orçamental?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Despesas', 'GBP - British Pound' => 'GBP - Libra Esterlina', 'INR - Indian Rupee' => 'INR - Rúpia indiana', 'JPY - Japanese Yen' => 'JPY - Iene japonês', - 'New budget line' => 'Nova rubrica orçamental', 'NZD - New Zealand Dollar' => 'NZD - Dólar Neozelandês', - 'Remove a budget line' => 'Remover uma rubrica orçamental', - 'Remove budget line' => 'Remover uma rubrica orçamental', 'RSD - Serbian dinar' => 'RSD - Dinar sérvio', - 'The budget line have been created successfully.' => 'A rubrica orçamental foi criada com sucesso.', - 'Unable to create the budget line.' => 'ImpossÃvel adicionar esta rubrica orçamental.', - 'Unable to remove this budget line.' => 'ImpossÃvel remover esta rubrica orçamental.', 'USD - US Dollar' => 'USD - Dólar norte-americano', - 'Remaining' => 'Restante', 'Destination column' => 'Coluna de destino', 'Move the task to another column when assigned to a user' => 'Mover a tarefa para uma outra coluna quando esta está atribuÃda a um utilizador', 'Move the task to another column when assignee is cleared' => 'Mover a tarefa para uma outra coluna quando esta não está atribuÃda', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Taxa', 'Change reference currency' => 'Mudar a moeda de referência', 'Add a new currency rate' => 'Adicionar uma nova taxa para uma moeda', - 'Currency rates are used to calculate project budget.' => 'As taxas de câmbio são utilizadas para calcular o orçamento do projecto.', 'Reference currency' => 'Moeda de Referência', 'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.', 'Unable to add this currency rate.' => 'ImpossÃvel adicionar essa taxa de câmbio.', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s moveu a tarefa n° %d no primeiro swimlane', '%s moved the task #%d to the swimlane "%s"' => '%s moveu a tarefa n° %d no swimlane "%s"', 'Swimlane' => 'Swimlane', - 'Budget overview' => 'Visão geral do orçamento', - 'Type' => 'Tipo', - 'There is not enough data to show something.' => 'Não há dados suficientes para mostrar alguma coisa.', 'Gravatar' => 'Gravatar', 'Hipchat' => 'Hipchat', 'Slack' => 'Slack', diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index 0ad983ff..054e2ac8 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Удаленный', 'Enabled' => 'Включен', 'Disabled' => 'Выключены', - 'Google account linked' => 'Профиль Google ÑвÑзан', - 'Github account linked' => 'Профиль Github ÑвÑзан', 'Username:' => 'Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ:', 'Name:' => 'ИмÑ:', 'Email:' => 'E-mail:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Широкий вид', 'Compact/wide view' => 'Компактный/широкий вид', 'No results match:' => 'ОтÑутÑтвуют результаты:', - 'Remove hourly rate' => 'Удалить почаÑовую Ñтавку', - 'Do you really want to remove this hourly rate?' => 'Ð’Ñ‹ дейÑтвительно хотите удалить Ñту почаÑовую Ñтавку?', - 'Hourly rates' => 'ПочаÑовые Ñтавки', - 'Hourly rate' => 'ПочаÑÐ¾Ð²Ð°Ñ Ñтавка', 'Currency' => 'Валюта', - 'Effective date' => 'Дата вÑÑ‚ÑƒÐ¿Ð»ÐµÐ½Ð¸Ñ Ð² Ñилу', - 'Add new rate' => 'Добавить новый показатель', - 'Rate removed successfully.' => 'Показатель уÑпешно удален.', - 'Unable to remove this rate.' => 'Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ Ñтот показатель.', - 'Unable to save the hourly rate.' => 'Ðе удаетÑÑ Ñохранить почаÑовую Ñтавку.', - 'Hourly rate created successfully.' => 'ПочаÑÐ¾Ð²Ð°Ñ Ñтавка уÑпешно Ñоздана.', 'Start time' => 'Ð’Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ‡Ð°Ð»Ð°', 'End time' => 'Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ', 'Comment' => 'Комментарий', @@ -703,34 +691,18 @@ return array( 'Files' => 'Файлы', 'Images' => 'ИзображениÑ', 'Private project' => 'Приватный проект', - 'Amount' => 'КоличеÑтво', 'AUD - Australian Dollar' => 'AUD - ÐвÑтралийÑкий доллар', - 'Budget' => 'Бюджет', - 'Budget line' => 'Ð¡Ñ‚Ð°Ñ‚ÑŒÑ Ð±ÑŽÐ´Ð¶ÐµÑ‚Ð°', - 'Budget line removed successfully.' => 'Ð‘ÑŽÐ´Ð¶ÐµÑ‚Ð½Ð°Ñ ÑÑ‚Ð°Ñ‚ÑŒÑ ÑƒÑпешно удалена.', - 'Budget lines' => 'Статьи бюджета', 'CAD - Canadian Dollar' => 'CAD - КанадÑкий доллар', 'CHF - Swiss Francs' => 'CHF - ШвейцарÑкий Франк', - 'Cost' => 'СтоимоÑть', - 'Cost breakdown' => 'Ð”ÐµÑ‚Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°Ñ‚Ñ€Ð°Ñ‚', 'Custom Stylesheet' => 'ПользовательÑкий Ñтиль', 'download' => 'загрузить', - 'Do you really want to remove this budget line?' => 'Ð’Ñ‹ дейÑтвительно хотите удалить Ñту Ñтатью бюджета?', 'EUR - Euro' => 'EUR - Евро', - 'Expenses' => 'РаÑходы', 'GBP - British Pound' => 'GBP - БританÑкий фунт', 'INR - Indian Rupee' => 'INR - ИндийÑкий рупий', 'JPY - Japanese Yen' => 'JPY - ЯпонÑкай йена', - 'New budget line' => 'ÐÐ¾Ð²Ð°Ñ ÑÑ‚Ð°Ñ‚ÑŒÑ Ð±ÑŽÐ´Ð¶ÐµÑ‚Ð°', 'NZD - New Zealand Dollar' => 'NZD - ÐовозеландÑкий доллар', - 'Remove a budget line' => 'Удалить Ñтроку в бюджете', - 'Remove budget line' => 'Удалить Ñтатью бюджета', 'RSD - Serbian dinar' => 'RSD - СербÑкий динар', - 'The budget line have been created successfully.' => 'Ð¡Ñ‚Ð°Ñ‚ÑŒÑ Ð±ÑŽÐ´Ð¶ÐµÑ‚Ð° уÑпешно Ñоздана.', - 'Unable to create the budget line.' => 'Ðе удаетÑÑ Ñоздать Ñту Ñтатью бюджета.', - 'Unable to remove this budget line.' => 'Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ Ñту Ñтатью бюджета.', 'USD - US Dollar' => 'USD - доллар СШÐ', - 'Remaining' => 'Прочее', 'Destination column' => 'Колонка назначениÑ', 'Move the task to another column when assigned to a user' => 'ПеремеÑтить задачу в другую колонку, когда она назначена пользователю', 'Move the task to another column when assignee is cleared' => 'ПеремеÑтить задачу в другую колонку, когда назначение ÑнÑто ', @@ -746,7 +718,6 @@ return array( 'Rate' => 'КурÑ', 'Change reference currency' => 'Изменить Ñправочник валют', 'Add a new currency rate' => 'Добавить новый валютный курÑ', - 'Currency rates are used to calculate project budget.' => 'КурÑÑ‹ валют иÑпользуютÑÑ Ð´Ð»Ñ Ñ€Ð°Ñчета бюджета проекта.', 'Reference currency' => 'Справочник валют', 'The currency rate have been added successfully.' => 'ÐšÑƒÑ€Ñ Ð²Ð°Ð»ÑŽÑ‚Ñ‹ был уÑпешно добавлен.', 'Unable to add this currency rate.' => 'Ðевозможно добавить Ñтот ÐºÑƒÑ€Ñ Ð²Ð°Ð»ÑŽÑ‚Ñ‹.', @@ -895,7 +866,7 @@ return array( 'Overdue tasks for the project "%s"' => 'ПроÑроченные задачи Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð° "%s"', 'New title: %s' => 'Ðовый заголовок: %s', 'The task is not assigned anymore' => 'Задача больше не назначена', - 'New assignee: %s' => '', + // 'New assignee: %s' => '', 'There is no category now' => 'Ð’ наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð·Ð´ÐµÑÑŒ нет категорий', 'New category: %s' => 'ÐÐ¾Ð²Ð°Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ: %s', 'New color: %s' => 'Ðовый цвет: %s', @@ -919,7 +890,7 @@ return array( 'New due date: %B %e, %Y' => 'ÐÐ¾Ð²Ð°Ñ Ð´Ð°Ñ‚Ð° завершениÑ: %B %e, %Y', 'Start date changed: %B %e, %Y' => 'Изменить дату начала: %B %e, %Y', '%k:%M %p' => '%k:%M %p', - '%%Y-%%m-%%d' => '%%Г-%%м-%%д', + '%%Y-%%m-%%d' => '%%Y-%%m-%%d', 'Total for all columns' => 'Суммарно Ð´Ð»Ñ Ð²Ñех колонок', 'You need at least 2 days of data to show the chart.' => 'Ð”Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð¸Ð°Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ нужно по крайней мере 2 днÑ.', '<15m' => '<15м', diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php index 0bc5c248..a05d67d3 100644 --- a/app/Locale/sr_Latn_RS/translations.php +++ b/app/Locale/sr_Latn_RS/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Udaljno', 'Enabled' => 'Omogući', 'Disabled' => 'Onemogući', - 'Google account linked' => 'Połączone konto Google', - 'Github account linked' => 'Połączone konto Github', 'Username:' => 'KorisniÄko ime:', 'Name:' => 'Ime i Prezime', 'Email:' => 'Email: ', @@ -667,17 +665,7 @@ return array( // 'Horizontal scrolling' => '', // 'Compact/wide view' => '', // 'No results match:' => '', - // 'Remove hourly rate' => '', - // 'Do you really want to remove this hourly rate?' => '', - // 'Hourly rates' => '', - // 'Hourly rate' => '', // 'Currency' => '', - // 'Effective date' => '', - // 'Add new rate' => '', - // 'Rate removed successfully.' => '', - // 'Unable to remove this rate.' => '', - // 'Unable to save the hourly rate.' => '', - // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', // 'Comment' => '', @@ -703,34 +691,18 @@ return array( // 'Files' => '', // 'Images' => '', // 'Private project' => '', - // 'Amount' => '', // 'AUD - Australian Dollar' => '', - // 'Budget' => '', - // 'Budget line' => '', - // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', // 'Custom Stylesheet' => '', // 'download' => '', - // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', - // 'Expenses' => '', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - // 'New budget line' => '', // 'NZD - New Zealand Dollar' => '', - // 'Remove a budget line' => '', - // 'Remove budget line' => '', // 'RSD - Serbian dinar' => '', - // 'The budget line have been created successfully.' => '', - // 'Unable to create the budget line.' => '', - // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', - // 'Remaining' => '', // 'Destination column' => '', // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index 9c769724..e8bdb9ce 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Fjärr', 'Enabled' => 'Aktiverad', 'Disabled' => 'Inaktiverad', - 'Google account linked' => 'Googlekonto länkat', - 'Github account linked' => 'Githubkonto länkat', 'Username:' => 'Användarnam:', 'Name:' => 'Namn:', 'Email:' => 'E-post:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'Horisontell scroll', 'Compact/wide view' => 'Kompakt/bred vy', 'No results match:' => 'Inga matchande resultat', - 'Remove hourly rate' => 'Ta bort timtaxa', - 'Do you really want to remove this hourly rate?' => 'Vill du verkligen ta bort denna timtaxa?', - 'Hourly rates' => 'Timtaxor', - 'Hourly rate' => 'Timtaxa', 'Currency' => 'Valuta', - 'Effective date' => 'Giltighetsdatum', - 'Add new rate' => 'Lägg till ny taxa', - 'Rate removed successfully.' => 'Taxan togs bort.', - 'Unable to remove this rate.' => 'Kunde inte ta bort taxan.', - 'Unable to save the hourly rate.' => 'Kunde inte spara timtaxan.', - 'Hourly rate created successfully.' => 'Timtaxan skapades.', 'Start time' => 'Starttid', 'End time' => 'Sluttid', 'Comment' => 'Kommentar', @@ -703,34 +691,18 @@ return array( 'Files' => 'Filer', 'Images' => 'Bilder', 'Private project' => 'Privat projekt', - 'Amount' => 'Belopp', 'AUD - Australian Dollar' => 'AUD - Australiska dollar', - 'Budget' => 'Budget', - 'Budget line' => 'Budgetlinje', - 'Budget line removed successfully.' => 'Budgetlinjen togs bort.', - 'Budget lines' => 'Budgetlinjer', 'CAD - Canadian Dollar' => 'CAD - Kanadensiska dollar', 'CHF - Swiss Francs' => 'CHF - Schweiziska Franc', - 'Cost' => 'Kostnad', - 'Cost breakdown' => 'Kostnadssammanställning', 'Custom Stylesheet' => 'Anpassad stilmall', 'download' => 'ladda ned', - 'Do you really want to remove this budget line?' => 'Vill du verkligen ta bort budgetlinjen?', 'EUR - Euro' => 'EUR - Euro', - 'Expenses' => 'Utgifter', 'GBP - British Pound' => 'GBP - Brittiska Pund', 'INR - Indian Rupee' => 'INR - Indiska Rupier', 'JPY - Japanese Yen' => 'JPY - Japanska Yen', - 'New budget line' => 'Ny budgetlinje', 'NZD - New Zealand Dollar' => 'NZD - Nya Zeeländska Dollar', - 'Remove a budget line' => 'Ta bort en budgetlinje', - 'Remove budget line' => 'Ta bort budgetlinje', 'RSD - Serbian dinar' => 'RSD - Serbiska Dinarer', - 'The budget line have been created successfully.' => 'Budgetlinjen har skapats.', - 'Unable to create the budget line.' => 'Kunde inte skapa budgetlinjen.', - 'Unable to remove this budget line.' => 'Kunde inte ta bort budgetlinjen.', 'USD - US Dollar' => 'USD - Amerikanska Dollar', - 'Remaining' => 'Ã…terstÃ¥ende', 'Destination column' => 'MÃ¥lkolumn', 'Move the task to another column when assigned to a user' => 'Flytta uppgiften till en annan kolumn när den tilldelats en användare', 'Move the task to another column when assignee is cleared' => 'Flytta uppgiften till en annan kolumn när tilldelningen tas bort.', @@ -746,7 +718,6 @@ return array( 'Rate' => 'Kurs', 'Change reference currency' => 'Ändra referenskurs', 'Add a new currency rate' => 'Lägg till ny valutakurs', - 'Currency rates are used to calculate project budget.' => 'Valutakurser används för att beräkna projektbudget.', 'Reference currency' => 'Referensvaluta', 'The currency rate have been added successfully.' => 'Valutakursen har lagts till.', 'Unable to add this currency rate.' => 'Kunde inte lägga till valutakursen.', @@ -878,9 +849,6 @@ return array( '%s moved the task #%d to the first swimlane' => '%s flyttade uppgiften #%d till första swimlane', '%s moved the task #%d to the swimlane "%s"' => '%s flyttade uppgiften #%d till swimlane "%s"', 'Swimlane' => 'Swimlane', - 'Budget overview' => 'Budgetöversikt', - 'Type' => 'Typ', - 'There is not enough data to show something.' => 'Det finns inte tillräckligt mycket data för att visa nÃ¥got.', 'Gravatar' => 'Gravatar', 'Hipchat' => 'Hipchat', 'Slack' => 'Slack', diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index a5ed2474..d94107ad 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'รีโมท', 'Enabled' => 'เปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰', 'Disabled' => 'ปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰', - 'Google account linked' => 'เชื่à¸à¸¡à¸à¸±à¸šà¸à¸¹à¹€à¸à¸´à¸¥à¹à¸à¸„เคาท์', - 'Github account linked' => 'เชื่à¸à¸¡à¸à¸±à¸šà¸à¸´à¸—ฮับà¹à¸à¸„เคาท์', 'Username:' => 'ชื่à¸à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰:', 'Name:' => 'ชื่à¸:', 'Email:' => 'à¸à¸µà¹€à¸¡à¸¥:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'เลื่à¸à¸™à¸•ามà¹à¸™à¸§à¸™à¸à¸™', 'Compact/wide view' => 'พà¸à¸”ี/à¸à¸§à¹‰à¸²à¸‡ มุมมà¸à¸‡', 'No results match:' => 'ไม่มีผลลัพท์ที่ตรง', - 'Remove hourly rate' => 'ลบà¸à¸±à¸•รารายชั่วโมง', - 'Do you really want to remove this hourly rate?' => 'คุณต้à¸à¸‡à¸à¸²à¸£à¸¥à¸šà¸à¸±à¸•รารายชั่วโมง?', - 'Hourly rates' => 'à¸à¸±à¸•รารายชั่วโมง', - 'Hourly rate' => 'à¸à¸±à¸•รารายชั่วโมง', 'Currency' => 'สà¸à¸¸à¸¥à¹€à¸‡à¸´à¸™', - 'Effective date' => 'วันที่จ่าย', - 'Add new rate' => 'เพิ่มà¸à¸±à¸•ราใหม่', - 'Rate removed successfully.' => 'ลบà¸à¸±à¸•ราเรียบร้à¸à¸¢à¹à¸¥à¹‰à¸§', - 'Unable to remove this rate.' => 'ไม่สามารถลบà¸à¸±à¸•รานี้ได้', - 'Unable to save the hourly rate.' => 'ไม่สามารถบันทึà¸à¸à¸±à¸•รารายชั่วโมง', - 'Hourly rate created successfully.' => 'à¸à¸±à¸•รารายชั่วโมงสร้างเรียบร้à¸à¸¢à¹à¸¥à¹‰à¸§', 'Start time' => 'เวลาเริ่มต้น', 'End time' => 'เวลาจบ', 'Comment' => 'ความคิดเห็น', @@ -703,34 +691,18 @@ return array( 'Files' => 'ไฟล์', 'Images' => 'รูปภาพ', 'Private project' => 'โปรเจคส่วนตัว', - 'Amount' => 'จำนวนเงิน', // 'AUD - Australian Dollar' => '', - 'Budget' => 'งบประมาณ', - 'Budget line' => 'วงเงินงบประมาณ', - 'Budget line removed successfully.' => 'ลบวงเงินประมาณเรียบร้à¸à¸¢à¹à¸¥à¹‰à¸§', - 'Budget lines' => 'วงเงินงบประมาณ', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - 'Cost' => 'มูลค่า', - 'Cost breakdown' => 'รายละเà¸à¸µà¸¢à¸”ค่าใช้จ่าย', // 'Custom Stylesheet' => '', 'download' => 'ดาวน์โหลด', - 'Do you really want to remove this budget line?' => 'คุณต้à¸à¸‡à¸à¸²à¸£à¸¥à¸šà¸§à¸‡à¹€à¸‡à¸´à¸™à¸‡à¸šà¸›à¸£à¸°à¸¡à¸²à¸“นี้?', // 'EUR - Euro' => '', - 'Expenses' => 'รายจ่าย', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - 'New budget line' => 'วงเงินงบประมาณใหม่', // 'NZD - New Zealand Dollar' => '', - 'Remove a budget line' => 'ลบวงเงินประมาณ', - 'Remove budget line' => 'ลบวงเงินประมาณ', // 'RSD - Serbian dinar' => '', - 'The budget line have been created successfully.' => 'สร้างวงเงินงบประมาณเรียบร้à¸à¸¢à¹à¸¥à¹‰à¸§', - 'Unable to create the budget line.' => 'ไม่สามารถสร้างวงเงินงบประมาณได้', - 'Unable to remove this budget line.' => 'ไม่สามารถลบวงเงินงบประมาณนี้', // 'USD - US Dollar' => '', - 'Remaining' => 'เหลืà¸à¸à¸¢à¸¹à¹ˆ', 'Destination column' => 'คà¸à¸¥à¸±à¸¡à¸™à¹Œà¹€à¸›à¹‰à¸²à¸«à¸¡à¸²à¸¢', 'Move the task to another column when assigned to a user' => 'ย้ายงานไปคà¸à¸¥à¸±à¸¡à¸™à¹Œà¸à¸·à¹ˆà¸™à¹€à¸¡à¸·à¹ˆà¸à¸à¸³à¸«à¸™à¸”บุคคลรับผิดชà¸à¸š', 'Move the task to another column when assignee is cleared' => 'ย้ายงานไปคà¸à¸¥à¸±à¸¡à¸™à¹Œà¸à¸·à¹ˆà¸™à¹€à¸¡à¸·à¹ˆà¸à¹„ม่à¸à¸³à¸«à¸™à¸”บุคคลรับผิดชà¸à¸š', @@ -746,7 +718,6 @@ return array( 'Rate' => 'à¸à¸±à¸•รา', // 'Change reference currency' => '', 'Add a new currency rate' => 'เพิ่มà¸à¸±à¸•ราà¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸‡à¸´à¸™à¸•ราใหม่', - 'Currency rates are used to calculate project budget.' => 'à¸à¸±à¸•ราà¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸‡à¸´à¸™à¸•ราถูà¸à¹ƒà¸Šà¹‰à¹ƒà¸™à¸à¸²à¸£à¸„ำนวณงบประมาณขà¸à¸‡à¹‚ปรเจค', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php index 9eb5c41e..87cccac7 100644 --- a/app/Locale/tr_TR/translations.php +++ b/app/Locale/tr_TR/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => 'Uzak', 'Enabled' => 'EtkinleÅŸtirildi', 'Disabled' => 'Devre dışı bırakıldı', - 'Google account linked' => 'Google hesabıyla baÄŸlı', - 'Github account linked' => 'Github hesabıyla baÄŸlı', 'Username:' => 'Kullanıcı adı', 'Name:' => 'Ad', 'Email:' => 'E-Posta', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => 'GeniÅŸ görünüm', 'Compact/wide view' => 'Ekrana sığdır / GeniÅŸ görünüm', // 'No results match:' => '', - // 'Remove hourly rate' => '', - // 'Do you really want to remove this hourly rate?' => '', - // 'Hourly rates' => '', - // 'Hourly rate' => '', // 'Currency' => '', - // 'Effective date' => '', - // 'Add new rate' => '', - // 'Rate removed successfully.' => '', - // 'Unable to remove this rate.' => '', - // 'Unable to save the hourly rate.' => '', - // 'Hourly rate created successfully.' => '', // 'Start time' => '', // 'End time' => '', // 'Comment' => '', @@ -703,34 +691,18 @@ return array( // 'Files' => '', // 'Images' => '', // 'Private project' => '', - // 'Amount' => '', // 'AUD - Australian Dollar' => '', - // 'Budget' => '', - // 'Budget line' => '', - // 'Budget line removed successfully.' => '', - // 'Budget lines' => '', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - // 'Cost' => '', - // 'Cost breakdown' => '', // 'Custom Stylesheet' => '', // 'download' => '', - // 'Do you really want to remove this budget line?' => '', // 'EUR - Euro' => '', - // 'Expenses' => '', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - // 'New budget line' => '', // 'NZD - New Zealand Dollar' => '', - // 'Remove a budget line' => '', - // 'Remove budget line' => '', // 'RSD - Serbian dinar' => '', - // 'The budget line have been created successfully.' => '', - // 'Unable to create the budget line.' => '', - // 'Unable to remove this budget line.' => '', // 'USD - US Dollar' => '', - // 'Remaining' => '', // 'Destination column' => '', // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', @@ -746,7 +718,6 @@ return array( // 'Rate' => '', // 'Change reference currency' => '', // 'Add a new currency rate' => '', - // 'Currency rates are used to calculate project budget.' => '', // 'Reference currency' => '', // 'The currency rate have been added successfully.' => '', // 'Unable to add this currency rate.' => '', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - // 'Budget overview' => '', - // 'Type' => '', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index 910bc0b4..102252e5 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -395,8 +395,6 @@ return array( 'Remote' => '远程', 'Enabled' => 'å¯ç”¨', 'Disabled' => 'åœç”¨', - 'Google account linked' => 'å·²ç»é“¾æŽ¥è°·æŒè´¦å·', - 'Github account linked' => 'å·²ç»é“¾æŽ¥Githubè´¦å·', 'Username:' => '用户å:', 'Name:' => 'å§“å:', 'Email:' => '电å邮件:', @@ -667,17 +665,7 @@ return array( 'Horizontal scrolling' => '水平滚动', 'Compact/wide view' => '紧凑/宽视图', 'No results match:' => 'æ— åŒ¹é…结果:', - 'Remove hourly rate' => 'åˆ é™¤å°æ—¶å·¥èµ„', - 'Do you really want to remove this hourly rate?' => '确定è¦åˆ 除æ¤è®¡æ—¶å·¥èµ„å—?', - 'Hourly rates' => 'å°æ—¶å·¥èµ„', - 'Hourly rate' => 'å°æ—¶å·¥èµ„', 'Currency' => 'è´§å¸', - 'Effective date' => '开始时间', - 'Add new rate' => 'æ·»åŠ å°æ—¶å·¥èµ„', - 'Rate removed successfully.' => 'æˆåŠŸåˆ é™¤å·¥èµ„ã€‚', - 'Unable to remove this rate.' => 'æ— æ³•åˆ é™¤æ¤å°æ—¶å·¥èµ„。', - 'Unable to save the hourly rate.' => 'æ— æ³•åˆ é™¤å°æ—¶å·¥èµ„。', - 'Hourly rate created successfully.' => 'æˆåŠŸåˆ›å»ºå°æ—¶å·¥èµ„。', 'Start time' => '开始时间', 'End time' => 'ç»“æŸæ—¶1é—´', 'Comment' => '注释', @@ -703,34 +691,18 @@ return array( 'Files' => '文件', 'Images' => '图片', 'Private project' => 'ç§äººé¡¹ç›®', - 'Amount' => 'æ•°é‡', // 'AUD - Australian Dollar' => '', - 'Budget' => '预算', - 'Budget line' => '预算线', - 'Budget line removed successfully.' => 'æˆåŠŸåˆ é™¤é¢„ç®—çº¿', - 'Budget lines' => '预算线', // 'CAD - Canadian Dollar' => '', // 'CHF - Swiss Francs' => '', - 'Cost' => 'æˆæœ¬', - 'Cost breakdown' => 'æˆæœ¬åˆ†è§£', 'Custom Stylesheet' => 'è‡ªå®šä¹‰æ ·å¼è¡¨', 'download' => '下载', - 'Do you really want to remove this budget line?' => '确定è¦åˆ 除æ¤é¢„算线å—?', // 'EUR - Euro' => '', - 'Expenses' => '花费', // 'GBP - British Pound' => '', // 'INR - Indian Rupee' => '', // 'JPY - Japanese Yen' => '', - 'New budget line' => '新预算线', // 'NZD - New Zealand Dollar' => '', - 'Remove a budget line' => 'åˆ é™¤é¢„ç®—çº¿', - 'Remove budget line' => 'åˆ é™¤é¢„ç®—çº¿', // 'RSD - Serbian dinar' => '', - 'The budget line have been created successfully.' => 'æˆåŠŸåˆ›å»ºé¢„ç®—çº¿ã€‚', - 'Unable to create the budget line.' => 'æ— æ³•åˆ›å»ºé¢„ç®—çº¿ã€‚', - 'Unable to remove this budget line.' => 'æ— æ³•åˆ é™¤æ¤é¢„算线。', // 'USD - US Dollar' => '', - 'Remaining' => '剩余', 'Destination column' => 'ç›®æ ‡æ ç›®', 'Move the task to another column when assigned to a user' => '指定负责人时移动到其它æ ç›®', 'Move the task to another column when assignee is cleared' => '移除负责人时移动到其它æ ç›®', @@ -746,7 +718,6 @@ return array( 'Rate' => '汇率', 'Change reference currency' => '修改å‚考货å¸', 'Add a new currency rate' => 'æ·»åŠ æ–°æ±‡çŽ‡', - 'Currency rates are used to calculate project budget.' => '汇率会用æ¥è®¡ç®—项目预算。', 'Reference currency' => 'å‚考货å¸', 'The currency rate have been added successfully.' => 'æˆåŠŸæ·»åŠ æ±‡çŽ‡ã€‚', 'Unable to add this currency rate.' => 'æ— æ³•æ·»åŠ æ¤æ±‡çއ', @@ -878,9 +849,6 @@ return array( // '%s moved the task #%d to the first swimlane' => '', // '%s moved the task #%d to the swimlane "%s"' => '', // 'Swimlane' => '', - 'Budget overview' => '预算概览', - 'Type' => '类型', - // 'There is not enough data to show something.' => '', // 'Gravatar' => '', // 'Hipchat' => '', // 'Slack' => '', diff --git a/app/Model/Acl.php b/app/Model/Acl.php index 8c28cb1a..9a227cf5 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -64,7 +64,6 @@ class Acl extends Base 'export' => '*', 'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'), 'swimlane' => '*', - 'budget' => '*', 'gantt' => array('project', 'savetaskdate', 'task', 'savetask'), ); @@ -95,6 +94,18 @@ class Acl extends Base ); /** + * Extend ACL rules + * + * @access public + * @param string $acl_name + * @param aray $rules + */ + public function extend($acl_name, array $rules) + { + $this->$acl_name = array_merge($this->$acl_name, $rules); + } + + /** * Return true if the specified controller/action match the given acl * * @access public diff --git a/app/Model/Budget.php b/app/Model/Budget.php deleted file mode 100644 index 76c42ca9..00000000 --- a/app/Model/Budget.php +++ /dev/null @@ -1,214 +0,0 @@ -<?php - -namespace Model; - -use DateInterval; -use DateTime; -use SimpleValidator\Validator; -use SimpleValidator\Validators; - -/** - * Budget - * - * @package model - * @author Frederic Guillot - */ -class Budget extends Base -{ - /** - * SQL table name - * - * @var string - */ - const TABLE = 'budget_lines'; - - /** - * Get all budget lines for a project - * - * @access public - * @param integer $project_id - * @return array - */ - public function getAll($project_id) - { - return $this->db->table(self::TABLE)->eq('project_id', $project_id)->desc('date')->findAll(); - } - - /** - * Get the current total of the budget - * - * @access public - * @param integer $project_id - * @return float - */ - public function getTotal($project_id) - { - $result = $this->db->table(self::TABLE)->columns('SUM(amount) as total')->eq('project_id', $project_id)->findOne(); - return isset($result['total']) ? (float) $result['total'] : 0; - } - - /** - * Get breakdown by tasks/subtasks/users - * - * @access public - * @param integer $project_id - * @return \PicoDb\Table - */ - public function getSubtaskBreakdown($project_id) - { - return $this->db - ->table(SubtaskTimeTracking::TABLE) - ->columns( - SubtaskTimeTracking::TABLE.'.id', - SubtaskTimeTracking::TABLE.'.user_id', - SubtaskTimeTracking::TABLE.'.subtask_id', - SubtaskTimeTracking::TABLE.'.start', - SubtaskTimeTracking::TABLE.'.time_spent', - Subtask::TABLE.'.task_id', - Subtask::TABLE.'.title AS subtask_title', - Task::TABLE.'.title AS task_title', - Task::TABLE.'.project_id', - User::TABLE.'.username', - User::TABLE.'.name' - ) - ->join(Subtask::TABLE, 'id', 'subtask_id') - ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE) - ->join(User::TABLE, 'id', 'user_id') - ->eq(Task::TABLE.'.project_id', $project_id) - ->callback(array($this, 'applyUserRate')); - } - - /** - * Gather necessary information to display the budget graph - * - * @access public - * @param integer $project_id - * @return array - */ - public function getDailyBudgetBreakdown($project_id) - { - $out = array(); - $in = $this->db->hashtable(self::TABLE)->eq('project_id', $project_id)->gt('amount', 0)->asc('date')->getAll('date', 'amount'); - $time_slots = $this->getSubtaskBreakdown($project_id)->findAll(); - - foreach ($time_slots as $slot) { - $date = date('Y-m-d', $slot['start']); - - if (! isset($out[$date])) { - $out[$date] = 0; - } - - $out[$date] += $slot['cost']; - } - - $start = key($in) ?: key($out); - $end = new DateTime; - $left = 0; - $serie = array(); - - for ($today = new DateTime($start); $today <= $end; $today->add(new DateInterval('P1D'))) { - - $date = $today->format('Y-m-d'); - $today_in = isset($in[$date]) ? (int) $in[$date] : 0; - $today_out = isset($out[$date]) ? (int) $out[$date] : 0; - - if ($today_in > 0 || $today_out > 0) { - - $left += $today_in; - $left -= $today_out; - - $serie[] = array( - 'date' => $date, - 'in' => $today_in, - 'out' => -$today_out, - 'left' => $left, - ); - } - } - - return $serie; - } - - /** - * Filter callback to apply the rate according to the effective date - * - * @access public - * @param array $records - * @return array - */ - public function applyUserRate(array $records) - { - $rates = $this->hourlyRate->getAllByProject($records[0]['project_id']); - - foreach ($records as &$record) { - - $hourly_price = 0; - - foreach ($rates as $rate) { - - if ($rate['user_id'] == $record['user_id'] && date('Y-m-d', $rate['date_effective']) <= date('Y-m-d', $record['start'])) { - $hourly_price = $this->currency->getPrice($rate['currency'], $rate['rate']); - break; - } - } - - $record['cost'] = $hourly_price * $record['time_spent']; - } - - return $records; - } - - /** - * Add a new budget line in the database - * - * @access public - * @param integer $project_id - * @param float $amount - * @param string $comment - * @param string $date - * @return boolean|integer - */ - public function create($project_id, $amount, $comment, $date = '') - { - $values = array( - 'project_id' => $project_id, - 'amount' => $amount, - 'comment' => $comment, - 'date' => $date ?: date('Y-m-d'), - ); - - return $this->persist(self::TABLE, $values); - } - - /** - * Remove a specific budget line - * - * @access public - * @param integer $budget_id - * @return boolean - */ - public function remove($budget_id) - { - return $this->db->table(self::TABLE)->eq('id', $budget_id)->remove(); - } - - /** - * Validate creation - * - * @access public - * @param array $values Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateCreation(array $values) - { - $v = new Validator($values, array( - new Validators\Required('project_id', t('Field required')), - new Validators\Required('amount', t('Field required')), - )); - - return array( - $v->execute(), - $v->getErrors() - ); - } -}
\ No newline at end of file diff --git a/app/Model/Config.php b/app/Model/Config.php index 6fa98f93..8e51da24 100644 --- a/app/Model/Config.php +++ b/app/Model/Config.php @@ -75,6 +75,7 @@ class Config extends Base { // Sorted by value $languages = array( + 'id_ID' => 'Bahasa Indonesia', 'cs_CZ' => 'Čeština', 'da_DK' => 'Dansk', 'de_DE' => 'Deutsch', @@ -135,6 +136,7 @@ class Config extends Base 'zh_CN' => 'zh-cn', 'ja_JP' => 'ja', 'th_TH' => 'th', + 'id_ID' => 'id' ); $lang = $this->getCurrentLanguage(); diff --git a/app/Model/File.php b/app/Model/File.php index f884e460..7adab42b 100644 --- a/app/Model/File.php +++ b/app/Model/File.php @@ -3,6 +3,8 @@ namespace Model; use Event\FileEvent; +use Core\Tool; +use Core\ObjectStorage\ObjectStorageException; /** * File model @@ -47,14 +49,17 @@ class File extends Base */ public function remove($file_id) { - $file = $this->getbyId($file_id); + try { - if (! empty($file)) { - @unlink(FILES_DIR.$file['path']); - return $this->db->table(self::TABLE)->eq('id', $file_id)->remove(); - } + $file = $this->getbyId($file_id); + $this->objectStorage->remove($file['path']); - return false; + return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove(); + } + catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } } /** @@ -66,11 +71,11 @@ class File extends Base */ public function removeAll($task_id) { - $files = $this->getAll($task_id); + $file_ids = $this->db->table(self::TABLE)->eq('task_id', $task_id)->asc('id')->findAllByColumn('id'); $results = array(); - foreach ($files as $file) { - $results[] = $this->remove($file['id']); + foreach ($file_ids as $file_id) { + $results[] = $this->remove($file_id); } return ! in_array(false, $results, true); @@ -196,6 +201,30 @@ class File extends Base } /** + * Return the image mimetype based on the file extension + * + * @access public + * @param $filename + * @return string + */ + public function getImageMimeType($filename) + { + $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + + switch ($extension) { + case 'jpeg': + case 'jpg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + default: + return 'image/jpeg'; + } + } + + /** * Generate the path for a new filename * * @access public @@ -210,6 +239,18 @@ class File extends Base } /** + * Generate the path for a thumbnails + * + * @access public + * @param string $key Storage key + * @return string + */ + public function getThumbnailPath($key) + { + return 'thumbnails'.DIRECTORY_SEPARATOR.$key; + } + + /** * Handle file upload * * @access public @@ -218,11 +259,13 @@ class File extends Base * @param string $form_name File form name * @return bool */ - public function upload($project_id, $task_id, $form_name) + public function uploadFiles($project_id, $task_id, $form_name) { - $results = array(); + try { - if (! empty($_FILES[$form_name])) { + if (empty($_FILES[$form_name])) { + return false; + } foreach ($_FILES[$form_name]['error'] as $key => $error) { @@ -232,22 +275,27 @@ class File extends Base $uploaded_filename = $_FILES[$form_name]['tmp_name'][$key]; $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); - @mkdir(FILES_DIR.dirname($destination_filename), 0755, true); + if ($this->isImage($original_filename)) { + $this->generateThumbnailFromFile($uploaded_filename, $destination_filename); + } - if (@move_uploaded_file($uploaded_filename, FILES_DIR.$destination_filename)) { + $this->objectStorage->moveUploadedFile($uploaded_filename, $destination_filename); - $results[] = $this->create( - $task_id, - $original_filename, - $destination_filename, - $_FILES[$form_name]['size'][$key] - ); - } + $this->create( + $task_id, + $original_filename, + $destination_filename, + $_FILES[$form_name]['size'][$key] + ); } } - } - return ! in_array(false, $results, true); + return true; + } + catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } } /** @@ -261,129 +309,77 @@ class File extends Base */ public function uploadScreenshot($project_id, $task_id, $blob) { - $data = base64_decode($blob); - - if (empty($data)) { - return false; - } - $original_filename = e('Screenshot taken %s', dt('%B %e, %Y at %k:%M %p', time())).'.png'; - $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); - - @mkdir(FILES_DIR.dirname($destination_filename), 0755, true); - @file_put_contents(FILES_DIR.$destination_filename, $data); - - return $this->create( - $task_id, - $original_filename, - $destination_filename, - strlen($data) - ); + return $this->uploadContent($project_id, $task_id, $original_filename, $blob); } /** * Handle file upload (base64 encoded content) * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $filename Filename - * @param string $blob Base64 encoded image + * @param integer $project_id Project id + * @param integer $task_id Task id + * @param string $original_filename Filename + * @param string $blob Base64 encoded file * @return bool|integer */ - public function uploadContent($project_id, $task_id, $filename, $blob) + public function uploadContent($project_id, $task_id, $original_filename, $blob) { - $data = base64_decode($blob); + try { - if (empty($data)) { - return false; - } + $data = base64_decode($blob); - $destination_filename = $this->generatePath($project_id, $task_id, $filename); + if (empty($data)) { + return false; + } + + $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); + $this->objectStorage->put($destination_filename, $data); - @mkdir(FILES_DIR.dirname($destination_filename), 0755, true); - @file_put_contents(FILES_DIR.$destination_filename, $data); + if ($this->isImage($original_filename)) { + $this->generateThumbnailFromData($destination_filename, $data); + } - return $this->create( - $task_id, - $filename, - $destination_filename, - strlen($data) - ); + return $this->create( + $task_id, + $original_filename, + $destination_filename, + strlen($data) + ); + } + catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } } /** - * Generate a jpeg thumbnail from an image (output directly the image) + * Generate thumbnail from a blob * * @access public - * @param string $filename Source image - * @param integer $resize_width Desired image width - * @param integer $resize_height Desired image height + * @param string $destination_filename + * @param string $data */ - public function generateThumbnail($filename, $resize_width, $resize_height) + public function generateThumbnailFromData($destination_filename, &$data) { - $metadata = getimagesize($filename); - $src_width = $metadata[0]; - $src_height = $metadata[1]; - $dst_y = 0; - $dst_x = 0; - - if (empty($metadata['mime'])) { - return; - } - - if ($resize_width == 0 && $resize_height == 0) { - $resize_width = 100; - $resize_height = 100; - } - - if ($resize_width > 0 && $resize_height == 0) { - $dst_width = $resize_width; - $dst_height = floor($src_height * ($resize_width / $src_width)); - $dst_image = imagecreatetruecolor($dst_width, $dst_height); - } - elseif ($resize_width == 0 && $resize_height > 0) { - $dst_width = floor($src_width * ($resize_height / $src_height)); - $dst_height = $resize_height; - $dst_image = imagecreatetruecolor($dst_width, $dst_height); - } - else { - - $src_ratio = $src_width / $src_height; - $resize_ratio = $resize_width / $resize_height; - - if ($src_ratio <= $resize_ratio) { - $dst_width = $resize_width; - $dst_height = floor($src_height * ($resize_width / $src_width)); - - $dst_y = ($dst_height - $resize_height) / 2 * (-1); - } - else { - $dst_width = floor($src_width * ($resize_height / $src_height)); - $dst_height = $resize_height; - - $dst_x = ($dst_width - $resize_width) / 2 * (-1); - } + $temp_filename = tempnam(sys_get_temp_dir(), 'datafile'); - $dst_image = imagecreatetruecolor($resize_width, $resize_height); - } - - switch ($metadata['mime']) { - case 'image/jpeg': - case 'image/jpg': - $src_image = imagecreatefromjpeg($filename); - break; - case 'image/png': - $src_image = imagecreatefrompng($filename); - break; - case 'image/gif': - $src_image = imagecreatefromgif($filename); - break; - default: - return; - } + file_put_contents($temp_filename, $data); + $this->generateThumbnailFromFile($temp_filename, $destination_filename); + unlink($temp_filename); + } - imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, 0, 0, $dst_width, $dst_height, $src_width, $src_height); - imagejpeg($dst_image); + /** + * Generate thumbnail from a blob + * + * @access public + * @param string $uploaded_filename + * @param string $destination_filename + */ + public function generateThumbnailFromFile($uploaded_filename, $destination_filename) + { + $thumbnail_filename = tempnam(sys_get_temp_dir(), 'thumbnail'); + Tool::generateThumbnail($uploaded_filename, $thumbnail_filename); + $this->objectStorage->moveFile($thumbnail_filename, $this->getThumbnailPath($destination_filename)); } } diff --git a/app/Model/HourlyRate.php b/app/Model/HourlyRate.php deleted file mode 100644 index 1550bdae..00000000 --- a/app/Model/HourlyRate.php +++ /dev/null @@ -1,121 +0,0 @@ -<?php - -namespace Model; - -use SimpleValidator\Validator; -use SimpleValidator\Validators; - -/** - * Hourly Rate - * - * @package model - * @author Frederic Guillot - */ -class HourlyRate extends Base -{ - /** - * SQL table name - * - * @var string - */ - const TABLE = 'hourly_rates'; - - /** - * Get all user rates for a given project - * - * @access public - * @param integer $project_id - * @return array - */ - public function getAllByProject($project_id) - { - $members = $this->projectPermission->getMembers($project_id); - - if (empty($members)) { - return array(); - } - - return $this->db->table(self::TABLE)->in('user_id', array_keys($members))->desc('date_effective')->findAll(); - } - - /** - * Get all rates for a given user - * - * @access public - * @param integer $user_id User id - * @return array - */ - public function getAllByUser($user_id) - { - return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findAll(); - } - - /** - * Get current rate for a given user - * - * @access public - * @param integer $user_id User id - * @return float - */ - public function getCurrentRate($user_id) - { - return $this->db->table(self::TABLE)->eq('user_id', $user_id)->desc('date_effective')->findOneColumn('rate') ?: 0; - } - - /** - * Add a new rate in the database - * - * @access public - * @param integer $user_id User id - * @param float $rate Hourly rate - * @param string $currency Currency code - * @param string $date ISO8601 date format - * @return boolean|integer - */ - public function create($user_id, $rate, $currency, $date) - { - $values = array( - 'user_id' => $user_id, - 'rate' => $rate, - 'currency' => $currency, - 'date_effective' => $this->dateParser->removeTimeFromTimestamp($this->dateParser->getTimestamp($date)), - ); - - return $this->persist(self::TABLE, $values); - } - - /** - * Remove a specific rate - * - * @access public - * @param integer $rate_id - * @return boolean - */ - public function remove($rate_id) - { - return $this->db->table(self::TABLE)->eq('id', $rate_id)->remove(); - } - - /** - * Validate creation - * - * @access public - * @param array $values Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateCreation(array $values) - { - $v = new Validator($values, array( - new Validators\Required('user_id', t('Field required')), - new Validators\Required('rate', t('Field required')), - new Validators\Numeric('rate', t('This value must be numeric')), - new Validators\Required('date_effective', t('Field required')), - new Validators\Required('currency', t('Field required')), - )); - - return array( - $v->execute(), - $v->getErrors() - ); - } -} diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php index d8a44aff..24508c91 100644 --- a/app/Model/Subtask.php +++ b/app/Model/Subtask.php @@ -49,6 +49,7 @@ class Subtask extends Base */ const EVENT_UPDATE = 'subtask.update'; const EVENT_CREATE = 'subtask.create'; + const EVENT_DELETE = 'subtask.delete'; /** * Get available status @@ -174,6 +175,23 @@ class Subtask extends Base } /** + * Prepare data before insert + * + * @access public + * @param array $values Form values + */ + public function prepareCreation(array &$values) + { + $this->prepare($values); + + $values['position'] = $this->getLastPosition($values['task_id']) + 1; + $values['status'] = isset($values['status']) ? $values['status'] : self::STATUS_TODO; + $values['time_estimated'] = isset($values['time_estimated']) ? $values['time_estimated'] : 0; + $values['time_spent'] = isset($values['time_spent']) ? $values['time_spent'] : 0; + $values['user_id'] = isset($values['user_id']) ? $values['user_id'] : 0; + } + + /** * Get the position of the last column for a given project * * @access public @@ -198,9 +216,7 @@ class Subtask extends Base */ public function create(array $values) { - $this->prepare($values); - $values['position'] = $this->getLastPosition($values['task_id']) + 1; - + $this->prepareCreation($values); $subtask_id = $this->persist(self::TABLE, $values); if ($subtask_id) { @@ -223,14 +239,13 @@ class Subtask extends Base public function update(array $values) { $this->prepare($values); + $subtask = $this->getById($values['id']); $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); if ($result) { - - $this->container['dispatcher']->dispatch( - self::EVENT_UPDATE, - new SubtaskEvent($values) - ); + $event = $subtask; + $event['changes'] = array_diff_assoc($values, $subtask); + $this->container['dispatcher']->dispatch(self::EVENT_UPDATE, new SubtaskEvent($event)); } return $result; @@ -302,7 +317,6 @@ class Subtask extends Base $positions = array_flip($subtasks); if (isset($subtasks[$subtask_id]) && $subtasks[$subtask_id] < count($subtasks)) { - $position = ++$subtasks[$subtask_id]; $subtasks[$positions[$position]]--; @@ -402,7 +416,14 @@ class Subtask extends Base */ public function remove($subtask_id) { - return $this->db->table(self::TABLE)->eq('id', $subtask_id)->remove(); + $subtask = $this->getById($subtask_id); + $result = $this->db->table(self::TABLE)->eq('id', $subtask_id)->remove(); + + if ($result) { + $this->container['dispatcher']->dispatch(self::EVENT_DELETE, new SubtaskEvent($subtask)); + } + + return $result; } /** diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php index 997031e8..56998769 100644 --- a/app/Model/SubtaskTimeTracking.php +++ b/app/Model/SubtaskTimeTracking.php @@ -339,20 +339,7 @@ class SubtaskTimeTracking extends Base */ public function updateTaskTimeTracking($task_id) { - $result = $this->calculateSubtaskTime($task_id); - $values = array(); - - if ($result['total_spent'] > 0) { - $values['time_spent'] = $result['total_spent']; - } - - if ($result['total_estimated'] > 0) { - $values['time_estimated'] = $result['total_estimated']; - } - - if (empty($values)) { - return true; - } + $values = $this->calculateSubtaskTime($task_id); return $this->db ->table(Task::TABLE) @@ -373,8 +360,8 @@ class SubtaskTimeTracking extends Base ->table(Subtask::TABLE) ->eq('task_id', $task_id) ->columns( - 'SUM(time_spent) AS total_spent', - 'SUM(time_estimated) AS total_estimated' + 'SUM(time_spent) AS time_spent', + 'SUM(time_estimated) AS time_estimated' ) ->findOne(); } diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php index 3b78a406..06e879a4 100644 --- a/app/Model/Swimlane.php +++ b/app/Model/Swimlane.php @@ -160,7 +160,7 @@ class Swimlane extends Base public function getSwimlanes($project_id) { $swimlanes = $this->db->table(self::TABLE) - ->columns('id', 'name') + ->columns('id', 'name', 'description') ->eq('project_id', $project_id) ->eq('is_active', self::ACTIVE) ->orderBy('position', 'asc') @@ -216,32 +216,30 @@ class Swimlane extends Base * Add a new swimlane * * @access public - * @param integer $project_id - * @param string $name + * @param array $values Form values * @return integer|boolean */ - public function create($project_id, $name) + public function create($values) { - return $this->persist(self::TABLE, array( - 'project_id' => $project_id, - 'name' => $name, - 'position' => $this->getLastPosition($project_id), - )); + if (! $this->project->exists($values['project_id'])) { + return 0; + } + $values['position'] = $this->getLastPosition($values['project_id']); + return $this->persist(self::TABLE, $values); } /** - * Rename a swimlane + * Update a swimlane * * @access public - * @param integer $swimlane_id Swimlane id - * @param string $name Swimlane name + * @param array $values Form values * @return bool */ - public function rename($swimlane_id, $name) + public function update(array $values) { return $this->db->table(self::TABLE) - ->eq('id', $swimlane_id) - ->update(array('name' => $name)); + ->eq('id', $values['id']) + ->update($values); } /** diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index b1ac0ab9..e5dff0d5 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,23 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 85; +const VERSION = 87; + +function version_87($pdo) +{ + $pdo->exec(" + CREATE TABLE plugin_schema_versions ( + plugin VARCHAR(80) NOT NULL, + version INT NOT NULL DEFAULT 0, + PRIMARY KEY(plugin) + ) ENGINE=InnoDB CHARSET=utf8 + "); +} + +function version_86($pdo) +{ + $pdo->exec("ALTER TABLE swimlanes ADD COLUMN description TEXT"); +} function version_85($pdo) { @@ -306,19 +322,6 @@ function version_53($pdo) $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent FLOAT DEFAULT 0"); } -function version_52($pdo) -{ - $pdo->exec('CREATE TABLE budget_lines ( - `id` INT NOT NULL AUTO_INCREMENT, - `project_id` INT NOT NULL, - `amount` FLOAT NOT NULL, - `date` VARCHAR(10) NOT NULL, - `comment` TEXT, - FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, - PRIMARY KEY(id) - ) ENGINE=InnoDB CHARSET=utf8'); -} - function version_51($pdo) { $pdo->exec('CREATE TABLE timetable_day ( @@ -365,19 +368,6 @@ function version_51($pdo) ) ENGINE=InnoDB CHARSET=utf8'); } -function version_50($pdo) -{ - $pdo->exec("CREATE TABLE hourly_rates ( - id INT NOT NULL AUTO_INCREMENT, - user_id INT NOT NULL, - rate FLOAT DEFAULT 0, - date_effective INTEGER NOT NULL, - currency CHAR(3) NOT NULL, - FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE, - PRIMARY KEY(id) - ) ENGINE=InnoDB CHARSET=utf8"); -} - function version_49($pdo) { $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 9477b416..e7422e8c 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,22 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 65; +const VERSION = 67; + +function version_67($pdo) +{ + $pdo->exec(" + CREATE TABLE plugin_schema_versions ( + plugin VARCHAR(80) NOT NULL PRIMARY KEY, + version INTEGER NOT NULL DEFAULT 0 + ) + "); +} + +function version_66($pdo) +{ + $pdo->exec("ALTER TABLE swimlanes ADD COLUMN description TEXT"); +} function version_65($pdo) { @@ -300,18 +315,6 @@ function version_34($pdo) $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0"); } -function version_33($pdo) -{ - $pdo->exec('CREATE TABLE budget_lines ( - "id" SERIAL PRIMARY KEY, - "project_id" INTEGER NOT NULL, - "amount" REAL NOT NULL, - "date" VARCHAR(10) NOT NULL, - "comment" TEXT, - FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE - )'); -} - function version_32($pdo) { $pdo->exec('CREATE TABLE timetable_day ( @@ -354,18 +357,6 @@ function version_32($pdo) )'); } -function version_31($pdo) -{ - $pdo->exec("CREATE TABLE hourly_rates ( - id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL, - rate REAL DEFAULT 0, - date_effective INTEGER NOT NULL, - currency CHAR(3) NOT NULL, - FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE - )"); -} - function version_30($pdo) { $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index b4e4b948..b76e902a 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,22 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 81; +const VERSION = 83; + +function version_83($pdo) +{ + $pdo->exec(" + CREATE TABLE plugin_schema_versions ( + plugin TEXT NOT NULL PRIMARY KEY, + version INTEGER NOT NULL DEFAULT 0 + ) + "); +} + +function version_82($pdo) +{ + $pdo->exec("ALTER TABLE swimlanes ADD COLUMN description TEXT"); +} function version_81($pdo) { @@ -277,18 +292,6 @@ function version_52($pdo) $pdo->exec("ALTER TABLE subtask_time_tracking ADD COLUMN time_spent REAL DEFAULT 0"); } -function version_51($pdo) -{ - $pdo->exec('CREATE TABLE budget_lines ( - "id" INTEGER PRIMARY KEY, - "project_id" INTEGER NOT NULL, - "amount" REAL NOT NULL, - "date" TEXT NOT NULL, - "comment" TEXT, - FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE - )'); -} - function version_50($pdo) { $pdo->exec('CREATE TABLE timetable_day ( @@ -331,18 +334,6 @@ function version_50($pdo) )'); } -function version_49($pdo) -{ - $pdo->exec("CREATE TABLE hourly_rates ( - id INTEGER PRIMARY KEY, - user_id INTEGER NOT NULL, - rate REAL DEFAULT 0, - date_effective INTEGER NOT NULL, - currency TEXT NOT NULL, - FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE - )"); -} - function version_48($pdo) { $pdo->exec('ALTER TABLE subtasks ADD COLUMN position INTEGER DEFAULT 1'); diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index ef7aa575..a5677948 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -2,13 +2,16 @@ namespace ServiceProvider; +use Core\ObjectStorage\FileStorage; use Core\Paginator; use Core\OAuth2; +use Core\Tool; use Model\Config; use Model\Project; use Model\Webhook; use Pimple\Container; use Pimple\ServiceProviderInterface; +use League\HTMLToMarkdown\HtmlConverter; class ClassProvider implements ServiceProviderInterface { @@ -18,7 +21,6 @@ class ClassProvider implements ServiceProviderInterface 'Action', 'Authentication', 'Board', - 'Budget', 'Category', 'Color', 'Comment', @@ -26,7 +28,6 @@ class ClassProvider implements ServiceProviderInterface 'Currency', 'DateParser', 'File', - 'HourlyRate', 'LastLogin', 'Link', 'Notification', @@ -93,17 +94,7 @@ class ClassProvider implements ServiceProviderInterface public function register(Container $container) { - foreach ($this->classes as $namespace => $classes) { - - foreach ($classes as $name) { - - $class = '\\'.$namespace.'\\'.$name; - - $container[lcfirst($name)] = function ($c) use ($class) { - return new $class($c); - }; - } - } + Tool::buildDIC($container, $this->classes); $container['paginator'] = $container->factory(function ($c) { return new Paginator($c); @@ -112,5 +103,13 @@ class ClassProvider implements ServiceProviderInterface $container['oauth'] = $container->factory(function ($c) { return new OAuth2($c); }); + + $container['htmlConverter'] = function($c) { + return new HtmlConverter(array('strip_tags' => true)); + }; + + $container['objectStorage'] = function($c) { + return new FileStorage(FILES_DIR); + }; } } diff --git a/app/Subscriber/SubtaskTimeTrackingSubscriber.php b/app/Subscriber/SubtaskTimeTrackingSubscriber.php index e45b2c93..2d3b5f99 100644 --- a/app/Subscriber/SubtaskTimeTrackingSubscriber.php +++ b/app/Subscriber/SubtaskTimeTrackingSubscriber.php @@ -12,6 +12,7 @@ class SubtaskTimeTrackingSubscriber extends \Core\Base implements EventSubscribe { return array( Subtask::EVENT_CREATE => array('updateTaskTime', 0), + Subtask::EVENT_DELETE => array('updateTaskTime', 0), Subtask::EVENT_UPDATE => array( array('logStartEnd', 10), array('updateTaskTime', 0), diff --git a/app/Template/app/sidebar.php b/app/Template/app/sidebar.php index 2d966009..f4a455f8 100644 --- a/app/Template/app/sidebar.php +++ b/app/Template/app/sidebar.php @@ -19,6 +19,7 @@ <li <?= $this->app->getRouterAction() === 'activity' ? 'class="active"' : '' ?>> <?= $this->url->link(t('My activity stream'), 'app', 'activity', array('user_id' => $user['id'])) ?> </li> + <?= $this->hook->render('dashboard:sidebar') ?> </ul> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> diff --git a/app/Template/board/table_swimlane.php b/app/Template/board/table_swimlane.php index be401633..1caa920d 100644 --- a/app/Template/board/table_swimlane.php +++ b/app/Template/board/table_swimlane.php @@ -7,6 +7,20 @@ <i class="fa fa-minus-circle hide-icon-swimlane-<?= $swimlane['id'] ?>"></i> <i class="fa fa-plus-circle show-icon-swimlane-<?= $swimlane['id'] ?>" style="display: none"></i> </a> + + <?php if (! empty($swimlane['description'])): ?> + <span + title="<?= t('Description') ?>" + class="tooltip" + data-href="<?= $this->url->href('board', 'swimlane', array('swimlane_id' => $swimlane['id'], 'project_id' => $project['id'])) ?>"> + <i class="fa fa-info-circle"></i> + </span> + <?php endif ?> + + <span title="<?= t('Task count') ?>" class="board-column-header-task-count swimlane-task-count-<?= $swimlane['id'] ?>"> + (<?= $swimlane['nb_tasks'] ?>) + </span> + <span class="board-swimlane-toggle-title show-icon-swimlane-<?= $swimlane['id'] ?>"><?= $this->e($swimlane['name']) ?></span> <?php endif ?> </th> @@ -62,10 +76,6 @@ <?php if (! $hide_swimlane): ?> <th class="board-swimlane-title"> <?= $this->e($swimlane['name']) ?> - - <div title="<?= t('Task count') ?>" class="board-column-header-task-count"> - (<span><?= $swimlane['nb_tasks'] ?></span>) - </div> </th> <?php endif ?> diff --git a/app/Template/budget/breakdown.php b/app/Template/budget/breakdown.php deleted file mode 100644 index 92561188..00000000 --- a/app/Template/budget/breakdown.php +++ /dev/null @@ -1,30 +0,0 @@ -<div class="page-header"> - <h2><?= t('Cost breakdown') ?></h2> -</div> - -<?php if ($paginator->isEmpty()): ?> - <p class="alert"><?= t('There is nothing to show.') ?></p> -<?php else: ?> - <table class="table-fixed"> - <tr> - <th class="column-20"><?= $paginator->order(t('Task'), 'task_title') ?></th> - <th class="column-25"><?= $paginator->order(t('Subtask'), 'subtask_title') ?></th> - <th class="column-20"><?= $paginator->order(t('User'), 'username') ?></th> - <th class="column-10"><?= t('Cost') ?></th> - <th class="column-10"><?= $paginator->order(t('Time spent'), \Model\SubtaskTimeTracking::TABLE.'.time_spent') ?></th> - <th class="column-15"><?= $paginator->order(t('Date'), 'start') ?></th> - </tr> - <?php foreach ($paginator->getCollection() as $record): ?> - <tr> - <td><?= $this->url->link($this->e($record['task_title']), 'task', 'show', array('project_id' => $project['id'], 'task_id' => $record['task_id'])) ?></td> - <td><?= $this->url->link($this->e($record['subtask_title']), 'task', 'show', array('project_id' => $project['id'], 'task_id' => $record['task_id'])) ?></td> - <td><?= $this->url->link($this->e($record['name'] ?: $record['username']), 'user', 'show', array('user_id' => $record['user_id'])) ?></td> - <td><?= n($record['cost']) ?></td> - <td><?= n($record['time_spent']).' '.t('hours') ?></td> - <td><?= dt('%B %e, %Y', $record['start']) ?></td> - </tr> - <?php endforeach ?> - </table> - - <?= $paginator ?> -<?php endif ?>
\ No newline at end of file diff --git a/app/Template/budget/create.php b/app/Template/budget/create.php deleted file mode 100644 index a563796d..00000000 --- a/app/Template/budget/create.php +++ /dev/null @@ -1,47 +0,0 @@ -<div class="page-header"> - <h2><?= t('Budget lines') ?></h2> -</div> - -<?php if (! empty($lines)): ?> -<table class="table-fixed table-stripped"> - <tr> - <th class="column-20"><?= t('Budget line') ?></th> - <th class="column-20"><?= t('Date') ?></th> - <th><?= t('Comment') ?></th> - <th><?= t('Action') ?></th> - </tr> - <?php foreach ($lines as $line): ?> - <tr> - <td><?= n($line['amount']) ?></td> - <td><?= dt('%B %e, %Y', strtotime($line['date'])) ?></td> - <td><?= $this->e($line['comment']) ?></td> - <td> - <?= $this->url->link(t('Remove'), 'budget', 'confirm', array('project_id' => $project['id'], 'budget_id' => $line['id'])) ?> - </td> - </tr> - <?php endforeach ?> -</table> - -<h3><?= t('New budget line') ?></h3> -<?php endif ?> - -<form method="post" action="<?= $this->url->href('budget', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off"> - - <?= $this->form->csrf() ?> - - <?= $this->form->hidden('id', $values) ?> - <?= $this->form->hidden('project_id', $values) ?> - - <?= $this->form->label(t('Amount'), 'amount') ?> - <?= $this->form->text('amount', $values, $errors, array('required'), 'form-numeric') ?> - - <?= $this->form->label(t('Date'), 'date') ?> - <?= $this->form->text('date', $values, $errors, array('required'), 'form-date') ?> - - <?= $this->form->label(t('Comment'), 'comment') ?> - <?= $this->form->text('comment', $values, $errors) ?> - - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - </div> -</form>
\ No newline at end of file diff --git a/app/Template/budget/index.php b/app/Template/budget/index.php deleted file mode 100644 index 51ef3d87..00000000 --- a/app/Template/budget/index.php +++ /dev/null @@ -1,34 +0,0 @@ -<div class="page-header"> - <h2><?= t('Budget overview') ?></h2> -</div> - -<?php if (! empty($daily_budget)): ?> -<div id="budget-chart"> - <div id="chart" - data-date-format="<?= e('%%Y-%%m-%%d') ?>" - data-metrics='<?= json_encode($daily_budget, JSON_HEX_APOS) ?>' - data-labels='<?= json_encode(array('in' => t('Budget line'), 'out' => t('Expenses'), 'left' => t('Remaining'), 'value' => t('Amount'), 'date' => t('Date'), 'type' => t('Type')), JSON_HEX_APOS) ?>'></div> -</div> -<hr/> -<table class="table-fixed table-stripped"> - <tr> - <th><?= t('Date') ?></td> - <th><?= t('Budget line') ?></td> - <th><?= t('Expenses') ?></td> - <th><?= t('Remaining') ?></td> - </tr> - <?php foreach ($daily_budget as $line): ?> - <tr> - <td><?= dt('%B %e, %Y', strtotime($line['date'])) ?></td> - <td><?= n($line['in']) ?></td> - <td><?= n($line['out']) ?></td> - <td><?= n($line['left']) ?></td> - </tr> - <?php endforeach ?> -</table> -<?php else: ?> - <p class="alert"><?= t('There is not enough data to show something.') ?></p> -<?php endif ?> - -<?= $this->asset->js('assets/js/vendor/d3.v3.min.js') ?> -<?= $this->asset->js('assets/js/vendor/c3.min.js') ?>
\ No newline at end of file diff --git a/app/Template/budget/remove.php b/app/Template/budget/remove.php deleted file mode 100644 index a5b906a1..00000000 --- a/app/Template/budget/remove.php +++ /dev/null @@ -1,13 +0,0 @@ -<div class="page-header"> - <h2><?= t('Remove budget line') ?></h2> -</div> - -<div class="confirm"> - <p class="alert alert-info"><?= t('Do you really want to remove this budget line?') ?></p> - - <div class="form-actions"> - <?= $this->url->link(t('Yes'), 'budget', 'remove', array('project_id' => $project['id'], 'budget_id' => $budget_id), true, 'btn btn-red') ?> - <?= t('or') ?> - <?= $this->url->link(t('cancel'), 'budget', 'create', array('project_id' => $project['id'])) ?> - </div> -</div>
\ No newline at end of file diff --git a/app/Template/budget/sidebar.php b/app/Template/budget/sidebar.php deleted file mode 100644 index 8477c052..00000000 --- a/app/Template/budget/sidebar.php +++ /dev/null @@ -1,16 +0,0 @@ -<div class="sidebar"> - <h2><?= t('Budget') ?></h2> - <ul> - <li <?= $this->app->getRouterAction() === 'index' ? 'class="active"' : '' ?>> - <?= $this->url->link(t('Budget overview'), 'budget', 'index', array('project_id' => $project['id'])) ?> - </li> - <li <?= $this->app->getRouterAction() === 'create' ? 'class="active"' : '' ?>> - <?= $this->url->link(t('Budget lines'), 'budget', 'create', array('project_id' => $project['id'])) ?> - </li> - <li <?= $this->app->getRouterAction() === 'breakdown' ? 'class="active"' : '' ?>> - <?= $this->url->link(t('Cost breakdown'), 'budget', 'breakdown', array('project_id' => $project['id'])) ?> - </li> - </ul> - <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> - <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> -</div>
\ No newline at end of file diff --git a/app/Template/config/sidebar.php b/app/Template/config/sidebar.php index 3617979a..083da283 100644 --- a/app/Template/config/sidebar.php +++ b/app/Template/config/sidebar.php @@ -34,6 +34,7 @@ <li> <?= $this->url->link(t('Documentation'), 'doc', 'show') ?> </li> + <?= $this->hook->render('config:sidebar') ?> </ul> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> diff --git a/app/Template/currency/index.php b/app/Template/currency/index.php index f72c5700..1c78c47a 100644 --- a/app/Template/currency/index.php +++ b/app/Template/currency/index.php @@ -52,5 +52,3 @@ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> </div> </form> - -<p class="alert alert-info"><?= t('Currency rates are used to calculate project budget.') ?></p> diff --git a/app/Template/export/sidebar.php b/app/Template/export/sidebar.php index f204d29d..7e39a5af 100644 --- a/app/Template/export/sidebar.php +++ b/app/Template/export/sidebar.php @@ -13,6 +13,7 @@ <li <?= $this->app->getRouterAction() === 'summary' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Daily project summary'), 'export', 'summary', array('project_id' => $project['id'])) ?> </li> + <?= $this->hook->render('export:sidebar') ?> </ul> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> diff --git a/app/Template/file/show.php b/app/Template/file/show.php index b1a0a813..a390c9fb 100644 --- a/app/Template/file/show.php +++ b/app/Template/file/show.php @@ -11,7 +11,7 @@ <li> <?php if (function_exists('imagecreatetruecolor')): ?> <div class="img_container"> - <img src="<?= $this->url->href('file', 'thumbnail', array('width' => 250, 'height' => 100, 'file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> + <img src="<?= $this->url->href('file', 'thumbnail', array('file_id' => $file['id'], 'project_id' => $task['project_id'], 'task_id' => $file['task_id'])) ?>" alt="<?= $this->e($file['name']) ?>"/> </div> <?php endif ?> <p> diff --git a/app/Template/gantt/task_creation.php b/app/Template/gantt/task_creation.php index d0d14c1e..7997e231 100644 --- a/app/Template/gantt/task_creation.php +++ b/app/Template/gantt/task_creation.php @@ -12,7 +12,6 @@ <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large') ?> <?= $this->form->label(t('Description'), 'description') ?> - <div class="form-tabs"> <div class="write-area"> <?= $this->form->textarea('description', $values, $errors, array('placeholder="'.t('Leave a description').'"', 'tabindex="2"')) ?> @@ -29,6 +28,8 @@ </li> </ul> </div> + + <?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?> </div> <div class="form-column"> @@ -43,17 +44,14 @@ <?= $this->form->select('swimlane_id', $swimlanes_list, $values, $errors, array('tabindex="5"')) ?><br/> <?php endif ?> - <?= $this->form->label(t('Color'), 'color_id') ?> - <?= $this->form->select('color_id', $colors_list, $values, $errors, array('tabindex="7"')) ?><br/> - <?= $this->form->label(t('Complexity'), 'score') ?> - <?= $this->form->number('score', $values, $errors, array('tabindex="8"')) ?><br/> + <?= $this->form->number('score', $values, $errors, array('tabindex="6"')) ?><br/> <?= $this->form->label(t('Start Date'), 'date_started') ?> - <?= $this->form->text('date_started', $values, $errors, array('placeholder="'.$this->text->in($date_format, $date_formats).'"', 'tabindex="9"'), 'form-date') ?> + <?= $this->form->text('date_started', $values, $errors, array('placeholder="'.$this->text->in($date_format, $date_formats).'"', 'tabindex="7"'), 'form-date') ?> <?= $this->form->label(t('Due Date'), 'date_due') ?> - <?= $this->form->text('date_due', $values, $errors, array('placeholder="'.$this->text->in($date_format, $date_formats).'"', 'tabindex="10"'), 'form-date') ?><br/> + <?= $this->form->text('date_due', $values, $errors, array('placeholder="'.$this->text->in($date_format, $date_formats).'"', 'tabindex="8"'), 'form-date') ?><br/> <div class="form-help"><?= t('Others formats accepted: %s and %s', date('Y-m-d'), date('Y_m_d')) ?></div> </div> diff --git a/app/Template/header.php b/app/Template/header.php new file mode 100644 index 00000000..0bcfdbbc --- /dev/null +++ b/app/Template/header.php @@ -0,0 +1,33 @@ +<header> + <nav> + <h1><?= $this->url->link('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->e($title) ?> + <?php if (! empty($description)): ?> + <span class="tooltip" title='<?= $this->e($this->text->markdown($description)) ?>'> + <i class="fa fa-info-circle"></i> + </span> + <?php endif ?> + </h1> + <ul> + <?php if (isset($board_selector) && ! empty($board_selector)): ?> + <li> + <select id="board-selector" + class="chosen-select select-auto-redirect" + tabindex="-1" + data-notfound="<?= t('No results match:') ?>" + data-placeholder="<?= t('Display another project') ?>" + data-redirect-regex="PROJECT_ID" + data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>"> + <option value=""></option> + <?php foreach($board_selector as $board_id => $board_name): ?> + <option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option> + <?php endforeach ?> + </select> + </li> + <?php endif ?> + <li> + <?= $this->url->link(t('Logout'), 'auth', 'logout') ?> + <span class="username hide-tablet">(<?= $this->user->getProfileLink() ?>)</span> + </li> + </ul> + </nav> +</header>
\ No newline at end of file diff --git a/app/Template/hourlyrate/index.php b/app/Template/hourlyrate/index.php deleted file mode 100644 index af305d07..00000000 --- a/app/Template/hourlyrate/index.php +++ /dev/null @@ -1,46 +0,0 @@ -<div class="page-header"> - <h2><?= t('Hourly rates') ?></h2> -</div> - -<?php if (! empty($rates)): ?> - -<table> - <tr> - <th><?= t('Hourly rate') ?></th> - <th><?= t('Currency') ?></th> - <th><?= t('Effective date') ?></th> - <th><?= t('Action') ?></th> - </tr> - <?php foreach ($rates as $rate): ?> - <tr> - <td><?= n($rate['rate']) ?></td> - <td><?= $rate['currency'] ?></td> - <td><?= dt('%b %e, %Y', $rate['date_effective']) ?></td> - <td> - <?= $this->url->link(t('Remove'), 'hourlyrate', 'confirm', array('user_id' => $user['id'], 'rate_id' => $rate['id'])) ?> - </td> - </tr> - <?php endforeach ?> -</table> - -<h3><?= t('Add new rate') ?></h3> -<?php endif ?> - -<form method="post" action="<?= $this->url->href('hourlyrate', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off"> - - <?= $this->form->hidden('user_id', $values) ?> - <?= $this->form->csrf() ?> - - <?= $this->form->label(t('Hourly rate'), 'rate') ?> - <?= $this->form->text('rate', $values, $errors, array('required'), 'form-numeric') ?> - - <?= $this->form->label(t('Currency'), 'currency') ?> - <?= $this->form->select('currency', $currencies_list, $values, $errors, array('required')) ?> - - <?= $this->form->label(t('Effective date'), 'date_effective') ?> - <?= $this->form->text('date_effective', $values, $errors, array('required'), 'form-date') ?> - - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - </div> -</form> diff --git a/app/Template/hourlyrate/remove.php b/app/Template/hourlyrate/remove.php deleted file mode 100644 index 121436e4..00000000 --- a/app/Template/hourlyrate/remove.php +++ /dev/null @@ -1,13 +0,0 @@ -<div class="page-header"> - <h2><?= t('Remove hourly rate') ?></h2> -</div> - -<div class="confirm"> - <p class="alert alert-info"><?= t('Do you really want to remove this hourly rate?') ?></p> - - <div class="form-actions"> - <?= $this->url->link(t('Yes'), 'hourlyrate', 'remove', array('user_id' => $user['id'], 'rate_id' => $rate_id), true, 'btn btn-red') ?> - <?= t('or') ?> - <?= $this->url->link(t('cancel'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?> - </div> -</div>
\ No newline at end of file diff --git a/app/Template/layout.php b/app/Template/layout.php index 3e883fbf..934fb62c 100644 --- a/app/Template/layout.php +++ b/app/Template/layout.php @@ -28,52 +28,29 @@ <link rel="apple-touch-icon" sizes="144x144" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad-retina.png"> <title><?= isset($title) ? $this->e($title) : 'Kanboard' ?></title> + + <?= $this->hook->render('layout:head') ?> </head> <body data-status-url="<?= $this->url->href('app', 'status') ?>" data-login-url="<?= $this->url->href('auth', 'login') ?>" + data-markdown-preview-url="<?= $this->url->href('app', 'preview') ?>" data-timezone="<?= $this->app->getTimezone() ?>" data-js-lang="<?= $this->app->jsLang() ?>"> <?php if (isset($no_layout) && $no_layout): ?> <?= $content_for_layout ?> <?php else: ?> - <header> - <nav> - <h1><?= $this->url->link('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->e($title) ?> - <?php if (! empty($description)): ?> - <span class="tooltip" title='<?= $this->e($this->text->markdown($description)) ?>'> - <i class="fa fa-info-circle"></i> - </span> - <?php endif ?> - </h1> - <ul> - <?php if (isset($board_selector) && ! empty($board_selector)): ?> - <li> - <select id="board-selector" - class="chosen-select select-auto-redirect" - tabindex="-1" - data-notfound="<?= t('No results match:') ?>" - data-placeholder="<?= t('Display another project') ?>" - data-redirect-regex="PROJECT_ID" - data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>"> - <option value=""></option> - <?php foreach($board_selector as $board_id => $board_name): ?> - <option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option> - <?php endforeach ?> - </select> - </li> - <?php endif ?> - <li> - <?= $this->url->link(t('Logout'), 'auth', 'logout') ?> - <span class="username hide-tablet">(<?= $this->user->getProfileLink() ?>)</span> - </li> - </ul> - </nav> - </header> + <?= $this->hook->render('layout:top') ?> + <?= $this->render('header', array( + 'title' => $title, + 'description' => isset($description) ? $description : '', + 'board_selector' => $board_selector, + )) ?> <section class="page"> <?= $this->app->flashMessage() ?> <?= $content_for_layout ?> </section> + <?= $this->hook->render('layout:bottom') ?> <?php endif ?> </body> </html> diff --git a/app/Template/project/dropdown.php b/app/Template/project/dropdown.php index 0a53cc05..0f1e1f6b 100644 --- a/app/Template/project/dropdown.php +++ b/app/Template/project/dropdown.php @@ -9,21 +9,19 @@ </li> <?php endif ?> +<?= $this->hook->render('project:dropdown', array('project' => $project)) ?> + <?php if ($this->user->isProjectManagementAllowed($project['id'])): ?> -<li> - <i class="fa fa-line-chart fa-fw"></i> - <?= $this->url->link(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?> -</li> -<li> - <i class="fa fa-pie-chart fa-fw"></i> - <?= $this->url->link(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?> -</li> -<li> - <i class="fa fa-download fa-fw"></i> - <?= $this->url->link(t('Exports'), 'export', 'tasks', array('project_id' => $project['id'])) ?> -</li> -<li> - <i class="fa fa-cog fa-fw"></i> - <?= $this->url->link(t('Settings'), 'project', 'show', array('project_id' => $project['id'])) ?> -</li> + <li> + <i class="fa fa-line-chart fa-fw"></i> + <?= $this->url->link(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?> + </li> + <li> + <i class="fa fa-download fa-fw"></i> + <?= $this->url->link(t('Exports'), 'export', 'tasks', array('project_id' => $project['id'])) ?> + </li> + <li> + <i class="fa fa-cog fa-fw"></i> + <?= $this->url->link(t('Settings'), 'project', 'show', array('project_id' => $project['id'])) ?> + </li> <?php endif ?> diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php index 7b5d976f..84bbb6b1 100644 --- a/app/Template/project/sidebar.php +++ b/app/Template/project/sidebar.php @@ -48,6 +48,8 @@ </li> <?php endif ?> <?php endif ?> + + <?= $this->hook->render('project:sidebar') ?> </ul> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> diff --git a/app/Template/project_user/sidebar.php b/app/Template/project_user/sidebar.php index 8cc3f41b..98219a87 100644 --- a/app/Template/project_user/sidebar.php +++ b/app/Template/project_user/sidebar.php @@ -24,5 +24,7 @@ <li <?= $this->app->getRouterAction() === 'closed' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Closed tasks'), 'projectuser', 'closed', $filter) ?> </li> + + <?= $this->hook->render('project-user:sidebar') ?> </ul> </div>
\ No newline at end of file diff --git a/app/Template/swimlane/edit.php b/app/Template/swimlane/edit.php index 1788fed2..dfc5cf0b 100644 --- a/app/Template/swimlane/edit.php +++ b/app/Template/swimlane/edit.php @@ -12,6 +12,27 @@ <?= $this->form->label(t('Name'), 'name') ?> <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?> + <?= $this->form->label(t('Description'), 'description') ?> + + <div class="form-tabs"> + + <div class="write-area"> + <?= $this->form->textarea('description', $values, $errors) ?> + </div> + <div class="preview-area"> + <div class="markdown"></div> + </div> + <ul class="form-tabs-nav"> + <li class="form-tab form-tab-selected"> + <i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a> + </li> + <li class="form-tab"> + <a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a> + </li> + </ul> + </div> + <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div> + <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> diff --git a/app/Template/swimlane/index.php b/app/Template/swimlane/index.php index daee6af5..797d2ca2 100644 --- a/app/Template/swimlane/index.php +++ b/app/Template/swimlane/index.php @@ -14,7 +14,27 @@ <?= $this->form->hidden('project_id', $values) ?> <?= $this->form->label(t('Name'), 'name') ?> - <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?> + <?= $this->form->text('name', $values, $errors, array('required', 'maxlength="50"')) ?> + + <?= $this->form->label(t('Description'), 'description') ?> + + <div class="form-tabs"> + <div class="write-area"> + <?= $this->form->textarea('description', $values, $errors) ?> + </div> + <div class="preview-area"> + <div class="markdown"></div> + </div> + <ul class="form-tabs-nav"> + <li class="form-tab form-tab-selected"> + <i class="fa fa-pencil-square-o fa-fw"></i><a id="markdown-write" href="#"><?= t('Write') ?></a> + </li> + <li class="form-tab"> + <a id="markdown-preview" href="#"><i class="fa fa-eye fa-fw"></i><?= t('Preview') ?></a> + </li> + </ul> + </div> + <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div> <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php index f38572a3..b708e633 100644 --- a/app/Template/swimlane/table.php +++ b/app/Template/swimlane/table.php @@ -25,7 +25,7 @@ </li> <?php endif ?> <li> - <?= $this->url->link(t('Rename'), 'swimlane', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?> + <?= $this->url->link(t('Edit'), 'swimlane', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?> </li> <li> <?php if ($swimlane['is_active']): ?> diff --git a/app/Template/task/color_picker.php b/app/Template/task/color_picker.php new file mode 100644 index 00000000..a849b9ce --- /dev/null +++ b/app/Template/task/color_picker.php @@ -0,0 +1,11 @@ +<div class="color-picker"> +<?php foreach ($colors_list as $color_id => $color_name): ?> + <div + data-color-id="<?= $color_id ?>" + class="color-square color-<?= $color_id ?> <?= isset($values['color_id']) && $values['color_id'] === $color_id ? 'color-square-selected' : '' ?>" + title="<?= $this->e($color_name) ?>"> + </div> +<?php endforeach ?> +</div> + +<?= $this->form->hidden('color_id', $values) ?>
\ No newline at end of file diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php index 1f06ab8c..cf0e9f76 100644 --- a/app/Template/task/sidebar.php +++ b/app/Template/task/sidebar.php @@ -18,6 +18,8 @@ <?= $this->url->link(t('Time tracking'), 'task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <?php endif ?> + + <?= $this->hook->render('task:sidebar:information') ?> </ul> <h2><?= t('Actions') ?></h2> <ul> @@ -66,6 +68,8 @@ <?= $this->url->link(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> </li> <?php endif ?> + + <?= $this->hook->render('task:sidebar:actions') ?> </ul> <div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div> <div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div> diff --git a/app/Template/task_creation/form.php b/app/Template/task_creation/form.php index 8a29896e..325ca1c8 100644 --- a/app/Template/task_creation/form.php +++ b/app/Template/task_creation/form.php @@ -10,8 +10,7 @@ </div> <?php endif ?> -<section id="task-section"> -<form method="post" action="<?= $this->url->href('taskcreation', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off"> +<form id="task-form" method="post" action="<?= $this->url->href('taskcreation', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off"> <?= $this->form->csrf() ?> @@ -38,7 +37,7 @@ </ul> </div> - <div class="form-help"><?= $this->url->doc(t('Write your text in Markdown'), 'syntax-guide') ?></div> + <?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?> <?php if (! isset($duplicate)): ?> <?= $this->form->checkbox('another_task', t('Create another task'), 1, isset($values['another_task']) && $values['another_task'] == 1) ?> @@ -62,9 +61,6 @@ <?= $this->form->label(t('Column'), 'column_id') ?> <?= $this->form->select('column_id', $columns_list, $values, $errors, array('tabindex="6"')) ?><br/> - <?= $this->form->label(t('Color'), 'color_id') ?> - <?= $this->form->select('color_id', $colors_list, $values, $errors, array('tabindex="7"')) ?><br/> - <?= $this->form->label(t('Complexity'), 'score') ?> <?= $this->form->number('score', $values, $errors, array('tabindex="8"')) ?><br/> @@ -80,5 +76,4 @@ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue" tabindex="11"/> <?= t('or') ?> <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?> </div> -</form> -</section> +</form>
\ No newline at end of file diff --git a/app/Template/task_modification/edit_task.php b/app/Template/task_modification/edit_task.php index fe4696d6..f4d7449a 100644 --- a/app/Template/task_modification/edit_task.php +++ b/app/Template/task_modification/edit_task.php @@ -1,8 +1,7 @@ <div class="page-header"> <h2><?= t('Edit a task') ?></h2> </div> -<section id="task-section"> -<form method="post" action="<?= $this->url->href('taskmodification', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => $ajax)) ?>" autocomplete="off"> +<form id="task-form" method="post" action="<?= $this->url->href('taskmodification', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off"> <?= $this->form->csrf() ?> @@ -12,7 +11,6 @@ <?= $this->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"')) ?><br/> <?= $this->form->label(t('Description'), 'description') ?> - <div class="form-tabs"> <div class="write-area"> <?= $this->form->textarea('description', $values, $errors, array('placeholder="'.t('Leave a description').'"', 'tabindex="2"')) ?> @@ -30,6 +28,7 @@ </ul> </div> + <?= $this->render('task/color_picker', array('colors_list' => $colors_list, 'values' => $values)) ?> </div> <div class="form-column"> @@ -42,9 +41,6 @@ <?= $this->form->label(t('Category'), 'category_id') ?> <?= $this->form->select('category_id', $categories_list, $values, $errors, array('tabindex="4"')) ?><br/> - <?= $this->form->label(t('Color'), 'color_id') ?> - <?= $this->form->select('color_id', $colors_list, $values, $errors, array('tabindex="5"')) ?><br/> - <?= $this->form->label(t('Complexity'), 'score') ?> <?= $this->form->number('score', $values, $errors, array('tabindex="6"')) ?><br/> @@ -62,5 +58,4 @@ <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?> <?php endif ?> </div> -</form> -</section> +</form>
\ No newline at end of file diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php index cd1c85c1..80fe8684 100644 --- a/app/Template/user/sidebar.php +++ b/app/Template/user/sidebar.php @@ -20,6 +20,8 @@ <?= $this->url->link(t('Persistent connections'), 'user', 'sessions', array('user_id' => $user['id'])) ?> </li> <?php endif ?> + + <?= $this->hook->render('user:sidebar:information') ?> </ul> <h2><?= t('Actions') ?></h2> @@ -60,14 +62,13 @@ <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'authentication' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?> </li> - <li <?= $this->app->getRouterController() === 'hourlyrate' ? 'class="active"' : '' ?>> - <?= $this->url->link(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?> - </li> <li <?= $this->app->getRouterController() === 'timetable' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?> </li> <?php endif ?> + <?= $this->hook->render('user:sidebar:actions', array('user' => $user)) ?> + <?php if ($this->user->isAdmin() && ! $this->user->isCurrentUser($user['id'])): ?> <li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'remove' ? 'class="active"' : '' ?>> <?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?> diff --git a/app/common.php b/app/common.php index 1f1c7273..ea38ab36 100644 --- a/app/common.php +++ b/app/common.php @@ -30,120 +30,8 @@ $container->register(new ServiceProvider\ClassProvider); $container->register(new ServiceProvider\EventDispatcherProvider); if (ENABLE_URL_REWRITE) { - - // Dashboard - $container['router']->addRoute('dashboard', 'app', 'index'); - $container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id')); - $container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id')); - $container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id')); - $container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id')); - $container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id')); - $container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id')); - - // Search routes - $container['router']->addRoute('search', 'search', 'index'); - $container['router']->addRoute('search/:search', 'search', 'index', array('search')); - - // Project routes - $container['router']->addRoute('projects', 'project', 'index'); - $container['router']->addRoute('project/create', 'project', 'create'); - $container['router']->addRoute('project/create/:private', 'project', 'create', array('private')); - $container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id')); - $container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id')); - $container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id')); - $container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id')); - $container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id')); - $container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id')); - $container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id')); - $container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id')); - $container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id')); - $container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id')); - - // Action routes - $container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id')); - $container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id')); - - // Column routes - $container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id')); - $container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id')); - $container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id')); - $container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction')); - - // Swimlane routes - $container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id')); - $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id')); - - // Category routes - $container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id')); - $container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id')); - $container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id')); - - // Task routes - $container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id')); - $container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id')); - $container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token')); - - $container['router']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove', array('project_id', 'task_id')); - - $container['router']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence', array('project_id', 'task_id')); - - $container['router']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close', array('task_id', 'project_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open', array('task_id', 'project_id')); - - $container['router']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate', array('task_id', 'project_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy', array('task_id', 'project_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy', array('task_id', 'project_id', 'dst_project_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move', array('task_id', 'project_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move', array('task_id', 'project_id', 'dst_project_id')); - - // Board routes - $container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id')); - $container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id')); - $container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token')); - - // Calendar routes - $container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id')); - $container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id')); - - // Listing routes - $container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id')); - $container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id')); - - // Gantt routes - $container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id')); - $container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting')); - - // Subtask routes - $container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm', array('project_id', 'task_id', 'subtask_id')); - $container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit', array('project_id', 'task_id', 'subtask_id')); - - // Feed routes - $container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token')); - $container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token')); - - // Ical routes - $container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token')); - $container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token')); - - // Auth routes - $container['router']->addRoute('oauth/google', 'oauth', 'google'); - $container['router']->addRoute('oauth/github', 'oauth', 'github'); - $container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab'); - $container['router']->addRoute('login', 'auth', 'login'); - $container['router']->addRoute('logout', 'auth', 'logout'); + require __DIR__.'/routes.php'; } + +$plugin = new Core\PluginLoader($container); +$plugin->scan(); diff --git a/app/constants.php b/app/constants.php index cf515932..f25bd903 100644 --- a/app/constants.php +++ b/app/constants.php @@ -34,8 +34,11 @@ defined('LDAP_USER_PATTERN') or define('LDAP_USER_PATTERN', ''); defined('LDAP_ACCOUNT_FULLNAME') or define('LDAP_ACCOUNT_FULLNAME', 'displayname'); defined('LDAP_ACCOUNT_EMAIL') or define('LDAP_ACCOUNT_EMAIL', 'mail'); defined('LDAP_ACCOUNT_ID') or define('LDAP_ACCOUNT_ID', ''); -defined('LDAP_USERNAME_CASE_SENSITIVE') or define('LDAP_USERNAME_CASE_SENSITIVE', false); +defined('LDAP_ACCOUNT_MEMBEROF') or define('LDAP_ACCOUNT_MEMBEROF', 'memberof'); defined('LDAP_ACCOUNT_CREATION') or define('LDAP_ACCOUNT_CREATION', true); +defined('LDAP_GROUP_ADMIN_DN') or define('LDAP_GROUP_ADMIN_DN', ''); +defined('LDAP_GROUP_PROJECT_ADMIN_DN') or define('LDAP_GROUP_PROJECT_ADMIN_DN', ''); +defined('LDAP_USERNAME_CASE_SENSITIVE') or define('LDAP_USERNAME_CASE_SENSITIVE', false); // Google authentication defined('GOOGLE_AUTH') or define('GOOGLE_AUTH', false); diff --git a/app/routes.php b/app/routes.php new file mode 100644 index 00000000..159e8f6e --- /dev/null +++ b/app/routes.php @@ -0,0 +1,117 @@ +<?php + +// Dashboard +$container['router']->addRoute('dashboard', 'app', 'index'); +$container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id')); +$container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id')); +$container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id')); +$container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id')); +$container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id')); +$container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id')); + +// Search routes +$container['router']->addRoute('search', 'search', 'index'); +$container['router']->addRoute('search/:search', 'search', 'index', array('search')); + +// Project routes +$container['router']->addRoute('projects', 'project', 'index'); +$container['router']->addRoute('project/create', 'project', 'create'); +$container['router']->addRoute('project/create/:private', 'project', 'create', array('private')); +$container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id')); +$container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id')); +$container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id')); +$container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id')); +$container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id')); +$container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id')); +$container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id')); +$container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id')); +$container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id')); +$container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id')); + +// Action routes +$container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id')); +$container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id')); + +// Column routes +$container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id')); +$container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id')); +$container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id')); +$container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction')); + +// Swimlane routes +$container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id')); +$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id')); + +// Category routes +$container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id')); +$container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id')); +$container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id')); + +// Task routes +$container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id')); +$container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id')); +$container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token')); + +$container['router']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove', array('project_id', 'task_id')); + +$container['router']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence', array('project_id', 'task_id')); + +$container['router']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close', array('task_id', 'project_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open', array('task_id', 'project_id')); + +$container['router']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate', array('task_id', 'project_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy', array('task_id', 'project_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy', array('task_id', 'project_id', 'dst_project_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move', array('task_id', 'project_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move', array('task_id', 'project_id', 'dst_project_id')); + +// Board routes +$container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id')); +$container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id')); +$container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token')); + +// Calendar routes +$container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id')); +$container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id')); + +// Listing routes +$container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id')); +$container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id')); + +// Gantt routes +$container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id')); +$container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting')); + +// Subtask routes +$container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm', array('project_id', 'task_id', 'subtask_id')); +$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit', array('project_id', 'task_id', 'subtask_id')); + +// Feed routes +$container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token')); +$container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token')); + +// Ical routes +$container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token')); +$container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token')); + +// Auth routes +$container['router']->addRoute('oauth/google', 'oauth', 'google'); +$container['router']->addRoute('oauth/github', 'oauth', 'github'); +$container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab'); +$container['router']->addRoute('login', 'auth', 'login'); +$container['router']->addRoute('logout', 'auth', 'logout'); |
