summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--app/Api/App.php2
-rw-r--r--app/Controller/Config.php6
-rw-r--r--app/Controller/Currency.php1
-rw-r--r--app/Controller/Doc.php4
-rw-r--r--app/Controller/User.php14
-rw-r--r--app/Core/Base.php2
-rw-r--r--app/Core/Ldap/User.php15
-rw-r--r--app/Formatter/TaskCalendarFormatter.php2
-rw-r--r--app/Helper/AppHelper.php4
-rw-r--r--app/Model/Config.php170
-rw-r--r--app/Model/Language.php178
-rw-r--r--app/Model/Timezone.php56
-rw-r--r--app/Model/UserNotification.php2
-rw-r--r--app/ServiceProvider/ClassProvider.php2
-rw-r--r--app/Subscriber/BootstrapSubscriber.php4
-rw-r--r--app/User/LdapUserProvider.php22
-rw-r--r--app/constants.php1
-rw-r--r--config.default.php4
-rw-r--r--doc/config.markdown4
-rw-r--r--doc/ldap-parameters.markdown1
-rw-r--r--doc/plugin-registration.markdown2
-rw-r--r--doc/translations.markdown2
-rw-r--r--tests/integration.mysql.xml5
-rw-r--r--tests/units/Model/ConfigTest.php60
-rw-r--r--tests/units/Model/LanguageTest.php58
-rw-r--r--tests/units/Model/ProjectTest.php4
-rw-r--r--tests/units/Model/TimezoneTest.php32
28 files changed, 400 insertions, 258 deletions
diff --git a/ChangeLog b/ChangeLog
index 55435654..d5a51c25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,7 @@ New features:
* Added automated action to change task color based on the priority
* Added support for LDAP Posix Groups (OpenLDAP with memberUid)
* Added support for LDAP user photo attribute (Avatar image)
+* Added support for language LDAP attribute
* Search in activity stream
* Search in comments
* Search by task creator
diff --git a/app/Api/App.php b/app/Api/App.php
index 635f1ce2..1c4737c0 100644
--- a/app/Api/App.php
+++ b/app/Api/App.php
@@ -12,7 +12,7 @@ class App extends \Kanboard\Core\Base
{
public function getTimezone()
{
- return $this->config->get('application_timezone');
+ return $this->timezone->getCurrentTimezone();
}
public function getVersion()
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index a1b8c2af..021534cf 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -42,7 +42,7 @@ class Config extends Base
}
if ($this->config->save($values)) {
- $this->config->reload();
+ $this->language->loadCurrentLanguage();
$this->flash->success(t('Settings saved successfully.'));
} else {
$this->flash->failure(t('Unable to save your settings.'));
@@ -90,8 +90,8 @@ class Config extends Base
$this->common('application');
$this->response->html($this->helper->layout->config('config/application', array(
- 'languages' => $this->config->getLanguages(),
- 'timezones' => $this->config->getTimezones(),
+ 'languages' => $this->language->getLanguages(),
+ 'timezones' => $this->timezone->getTimezones(),
'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()),
'datetime_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateTimeFormats()),
'time_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getTimeFormats()),
diff --git a/app/Controller/Currency.php b/app/Controller/Currency.php
index ecaa9834..3e0de905 100644
--- a/app/Controller/Currency.php
+++ b/app/Controller/Currency.php
@@ -59,7 +59,6 @@ class Currency extends Base
$values = $this->request->getValues();
if ($this->config->save($values)) {
- $this->config->reload();
$this->flash->success(t('Settings saved successfully.'));
} else {
$this->flash->failure(t('Unable to save your settings.'));
diff --git a/app/Controller/Doc.php b/app/Controller/Doc.php
index 00b9e585..219ef8ad 100644
--- a/app/Controller/Doc.php
+++ b/app/Controller/Doc.php
@@ -20,7 +20,7 @@ class Doc extends Base
$page = 'index';
}
- if ($this->config->getCurrentLanguage() === 'fr_FR') {
+ if ($this->language->getCurrentLanguage() === 'fr_FR') {
$filename = __DIR__.'/../../doc/fr/' . $page . '.markdown';
} else {
$filename = __DIR__ . '/../../doc/' . $page . '.markdown';
@@ -83,7 +83,7 @@ class Doc extends Base
*/
public function replaceImageUrl(array $matches)
{
- if ($this->config->getCurrentLanguage() === 'fr_FR') {
+ if ($this->language->getCurrentLanguage() === 'fr_FR') {
return '('.$this->helper->url->base().'doc/fr/'.$matches[1].')';
}
diff --git a/app/Controller/User.php b/app/Controller/User.php
index f7d7d2e0..4caed1e6 100644
--- a/app/Controller/User.php
+++ b/app/Controller/User.php
@@ -67,8 +67,8 @@ class User extends Base
$is_remote = $this->request->getIntegerParam('remote') == 1 || (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1);
$this->response->html($this->helper->layout->app($is_remote ? 'user/create_remote' : 'user/create_local', array(
- 'timezones' => $this->config->getTimezones(true),
- 'languages' => $this->config->getLanguages(true),
+ 'timezones' => $this->timezone->getTimezones(true),
+ 'languages' => $this->language->getLanguages(true),
'roles' => $this->role->getApplicationRoles(),
'projects' => $this->project->getList(),
'errors' => $errors,
@@ -121,8 +121,8 @@ class User extends Base
$user = $this->getUser();
$this->response->html($this->helper->layout->user('user/show', array(
'user' => $user,
- 'timezones' => $this->config->getTimezones(true),
- 'languages' => $this->config->getLanguages(true),
+ 'timezones' => $this->timezone->getTimezones(true),
+ 'languages' => $this->language->getLanguages(true),
)));
}
@@ -247,7 +247,7 @@ class User extends Base
$this->response->html($this->helper->layout->user('user/integrations', array(
'user' => $user,
- 'values' => $this->userMetadata->getall($user['id']),
+ 'values' => $this->userMetadata->getAll($user['id']),
)));
}
@@ -365,8 +365,8 @@ class User extends Base
'values' => $values,
'errors' => $errors,
'user' => $user,
- 'timezones' => $this->config->getTimezones(true),
- 'languages' => $this->config->getLanguages(true),
+ 'timezones' => $this->timezone->getTimezones(true),
+ 'languages' => $this->language->getLanguages(true),
'roles' => $this->role->getApplicationRoles(),
)));
}
diff --git a/app/Core/Base.php b/app/Core/Base.php
index c065ea2a..39a8ccd6 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -65,6 +65,7 @@ use Pimple\Container;
* @property \Kanboard\Model\ProjectFile $projectFile
* @property \Kanboard\Model\Group $group
* @property \Kanboard\Model\GroupMember $groupMember
+ * @property \Kanboard\Model\Language $language
* @property \Kanboard\Model\LastLogin $lastLogin
* @property \Kanboard\Model\Link $link
* @property \Kanboard\Model\Notification $notification
@@ -95,6 +96,7 @@ use Pimple\Container;
* @property \Kanboard\Model\TaskPosition $taskPosition
* @property \Kanboard\Model\TaskStatus $taskStatus
* @property \Kanboard\Model\TaskMetadata $taskMetadata
+ * @property \Kanboard\Model\Timezone $timezone
* @property \Kanboard\Model\Transition $transition
* @property \Kanboard\Model\User $user
* @property \Kanboard\Model\UserLocking $userLocking
diff --git a/app/Core/Ldap/User.php b/app/Core/Ldap/User.php
index d0036ea7..c54aa1ac 100644
--- a/app/Core/Ldap/User.php
+++ b/app/Core/Ldap/User.php
@@ -146,7 +146,8 @@ class User
$entry->getFirstValue($this->getAttributeEmail()),
$this->getRole($groupIds),
$groupIds,
- $entry->getFirstValue($this->getAttributePhoto())
+ $entry->getFirstValue($this->getAttributePhoto()),
+ $entry->getFirstValue($this->getAttributeLanguage())
);
}
@@ -166,6 +167,7 @@ class User
$this->getAttributeEmail(),
$this->getAttributeGroup(),
$this->getAttributePhoto(),
+ $this->getAttributeLanguage(),
)));
}
@@ -237,6 +239,17 @@ class User
}
/**
+ * Get LDAP language attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getAttributeLanguage()
+ {
+ return strtolower(LDAP_USER_ATTRIBUTE_LANGUAGE);
+ }
+
+ /**
* Get LDAP Group User filter
*
* @access public
diff --git a/app/Formatter/TaskCalendarFormatter.php b/app/Formatter/TaskCalendarFormatter.php
index 60b9a062..ca0d5c05 100644
--- a/app/Formatter/TaskCalendarFormatter.php
+++ b/app/Formatter/TaskCalendarFormatter.php
@@ -44,7 +44,7 @@ class TaskCalendarFormatter extends BaseTaskCalendarFormatter implements Formatt
foreach ($this->query->findAll() as $task) {
$events[] = array(
- 'timezoneParam' => $this->config->getCurrentTimezone(),
+ 'timezoneParam' => $this->timezone->getCurrentTimezone(),
'id' => $task['id'],
'title' => t('#%d', $task['id']).' '.$task['title'],
'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
diff --git a/app/Helper/AppHelper.php b/app/Helper/AppHelper.php
index e6f6412d..1f497929 100644
--- a/app/Helper/AppHelper.php
+++ b/app/Helper/AppHelper.php
@@ -90,7 +90,7 @@ class AppHelper extends Base
*/
public function jsLang()
{
- return $this->config->getJsLanguageCode();
+ return $this->language->getJsLanguageCode();
}
/**
@@ -101,7 +101,7 @@ class AppHelper extends Base
*/
public function getTimezone()
{
- return $this->config->getCurrentTimezone();
+ return $this->timezone->getCurrentTimezone();
}
/**
diff --git a/app/Model/Config.php b/app/Model/Config.php
index 0c363fb0..1b14efa1 100644
--- a/app/Model/Config.php
+++ b/app/Model/Config.php
@@ -2,7 +2,6 @@
namespace Kanboard\Model;
-use Kanboard\Core\Translator;
use Kanboard\Core\Security\Token;
/**
@@ -14,162 +13,7 @@ use Kanboard\Core\Security\Token;
class Config extends Setting
{
/**
- * Get available timezones
- *
- * @access public
- * @param boolean $prepend Prepend a default value
- * @return array
- */
- public function getTimezones($prepend = false)
- {
- $timezones = timezone_identifiers_list();
- $listing = array_combine(array_values($timezones), $timezones);
-
- if ($prepend) {
- return array('' => t('Application default')) + $listing;
- }
-
- return $listing;
- }
-
- /**
- * Get current timezone
- *
- * @access public
- * @return string
- */
- public function getCurrentTimezone()
- {
- if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['timezone'])) {
- return $this->sessionStorage->user['timezone'];
- }
-
- return $this->get('application_timezone', 'UTC');
- }
-
- /**
- * Set timezone
- *
- * @access public
- */
- public function setupTimezone()
- {
- date_default_timezone_set($this->getCurrentTimezone());
- }
-
- /**
- * Get available languages
- *
- * @access public
- * @param boolean $prepend Prepend a default value
- * @return array
- */
- public function getLanguages($prepend = false)
- {
- // Sorted by value
- $languages = array(
- 'id_ID' => 'Bahasa Indonesia',
- 'bs_BA' => 'Bosanski',
- 'cs_CZ' => 'Čeština',
- 'da_DK' => 'Dansk',
- 'de_DE' => 'Deutsch',
- 'en_US' => 'English',
- 'es_ES' => 'Español',
- 'fr_FR' => 'Français',
- 'el_GR' => 'Grec',
- 'it_IT' => 'Italiano',
- 'hu_HU' => 'Magyar',
- 'my_MY' => 'Melayu',
- 'nl_NL' => 'Nederlands',
- 'nb_NO' => 'Norsk',
- 'pl_PL' => 'Polski',
- 'pt_PT' => 'Português',
- 'pt_BR' => 'Português (Brasil)',
- 'ru_RU' => 'Русский',
- 'sr_Latn_RS' => 'Srpski',
- 'fi_FI' => 'Suomi',
- 'sv_SE' => 'Svenska',
- 'tr_TR' => 'Türkçe',
- 'ko_KR' => '한국어',
- 'zh_CN' => '中文(简体)',
- 'ja_JP' => '日本語',
- 'th_TH' => 'ไทย',
- );
-
- if ($prepend) {
- return array('' => t('Application default')) + $languages;
- }
-
- return $languages;
- }
-
- /**
- * Get javascript language code
- *
- * @access public
- * @return string
- */
- public function getJsLanguageCode()
- {
- $languages = array(
- 'cs_CZ' => 'cs',
- 'da_DK' => 'da',
- 'de_DE' => 'de',
- 'en_US' => 'en',
- 'es_ES' => 'es',
- 'fr_FR' => 'fr',
- 'it_IT' => 'it',
- 'hu_HU' => 'hu',
- 'nl_NL' => 'nl',
- 'nb_NO' => 'nb',
- 'pl_PL' => 'pl',
- 'pt_PT' => 'pt',
- 'pt_BR' => 'pt-br',
- 'ru_RU' => 'ru',
- 'sr_Latn_RS' => 'sr',
- 'fi_FI' => 'fi',
- 'sv_SE' => 'sv',
- 'tr_TR' => 'tr',
- 'ko_KR' => 'ko',
- 'zh_CN' => 'zh-cn',
- 'ja_JP' => 'ja',
- 'th_TH' => 'th',
- 'id_ID' => 'id',
- 'el_GR' => 'el',
- );
-
- $lang = $this->getCurrentLanguage();
-
- return isset($languages[$lang]) ? $languages[$lang] : 'en';
- }
-
- /**
- * Get current language
- *
- * @access public
- * @return string
- */
- public function getCurrentLanguage()
- {
- if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['language'])) {
- return $this->sessionStorage->user['language'];
- }
-
- return $this->get('application_language', 'en_US');
- }
-
- /**
- * Load translations
- *
- * @access public
- */
- public function setupTranslations()
- {
- Translator::load($this->getCurrentLanguage());
- }
-
- /**
- * Get a config variable from the session or the database
+ * Get a config variable with in-memory caching
*
* @access public
* @param string $name Parameter name
@@ -183,16 +27,6 @@ class Config extends Setting
}
/**
- * Reload settings in the session and the translations
- *
- * @access public
- */
- public function reload()
- {
- $this->setupTranslations();
- }
-
- /**
* Optimize the Sqlite database
*
* @access public
@@ -200,7 +34,7 @@ class Config extends Setting
*/
public function optimizeDatabase()
{
- return $this->db->getconnection()->exec('VACUUM');
+ return $this->db->getConnection()->exec('VACUUM');
}
/**
diff --git a/app/Model/Language.php b/app/Model/Language.php
new file mode 100644
index 00000000..441771e0
--- /dev/null
+++ b/app/Model/Language.php
@@ -0,0 +1,178 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Translator;
+
+/**
+ * Class Language
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class Language extends Base
+{
+ /**
+ * Get all language codes
+ *
+ * @static
+ * @access public
+ * @return string[]
+ */
+ public static function getCodes()
+ {
+ return array(
+ 'id_ID',
+ 'bs_BA',
+ 'cs_CZ',
+ 'da_DK',
+ 'de_DE',
+ 'en_US',
+ 'es_ES',
+ 'fr_FR',
+ 'el_GR',
+ 'it_IT',
+ 'hu_HU',
+ 'my_MY',
+ 'nl_NL',
+ 'nb_NO',
+ 'pl_PL',
+ 'pt_PT',
+ 'pt_BR',
+ 'ru_RU',
+ 'sr_Latn_RS',
+ 'fi_FI',
+ 'sv_SE',
+ 'tr_TR',
+ 'ko_KR',
+ 'zh_CN',
+ 'ja_JP',
+ 'th_TH',
+ );
+ }
+
+ /**
+ * Find language code
+ *
+ * @static
+ * @access public
+ * @param string $code
+ * @return string
+ */
+ public static function findCode($code)
+ {
+ $code = str_replace('-', '_', $code);
+ return in_array($code, self::getCodes()) ? $code : '';
+ }
+
+ /**
+ * Get available languages
+ *
+ * @access public
+ * @param boolean $prepend Prepend a default value
+ * @return array
+ */
+ public function getLanguages($prepend = false)
+ {
+ // Sorted by value
+ $languages = array(
+ 'id_ID' => 'Bahasa Indonesia',
+ 'bs_BA' => 'Bosanski',
+ 'cs_CZ' => 'Čeština',
+ 'da_DK' => 'Dansk',
+ 'de_DE' => 'Deutsch',
+ 'en_US' => 'English',
+ 'es_ES' => 'Español',
+ 'fr_FR' => 'Français',
+ 'el_GR' => 'Grec',
+ 'it_IT' => 'Italiano',
+ 'hu_HU' => 'Magyar',
+ 'my_MY' => 'Melayu',
+ 'nl_NL' => 'Nederlands',
+ 'nb_NO' => 'Norsk',
+ 'pl_PL' => 'Polski',
+ 'pt_PT' => 'Português',
+ 'pt_BR' => 'Português (Brasil)',
+ 'ru_RU' => 'Русский',
+ 'sr_Latn_RS' => 'Srpski',
+ 'fi_FI' => 'Suomi',
+ 'sv_SE' => 'Svenska',
+ 'tr_TR' => 'Türkçe',
+ 'ko_KR' => '한국어',
+ 'zh_CN' => '中文(简体)',
+ 'ja_JP' => '日本語',
+ 'th_TH' => 'ไทย',
+ );
+
+ if ($prepend) {
+ return array('' => t('Application default')) + $languages;
+ }
+
+ return $languages;
+ }
+
+ /**
+ * Get javascript language code
+ *
+ * @access public
+ * @return string
+ */
+ public function getJsLanguageCode()
+ {
+ $languages = array(
+ 'cs_CZ' => 'cs',
+ 'da_DK' => 'da',
+ 'de_DE' => 'de',
+ 'en_US' => 'en',
+ 'es_ES' => 'es',
+ 'fr_FR' => 'fr',
+ 'it_IT' => 'it',
+ 'hu_HU' => 'hu',
+ 'nl_NL' => 'nl',
+ 'nb_NO' => 'nb',
+ 'pl_PL' => 'pl',
+ 'pt_PT' => 'pt',
+ 'pt_BR' => 'pt-br',
+ 'ru_RU' => 'ru',
+ 'sr_Latn_RS' => 'sr',
+ 'fi_FI' => 'fi',
+ 'sv_SE' => 'sv',
+ 'tr_TR' => 'tr',
+ 'ko_KR' => 'ko',
+ 'zh_CN' => 'zh-cn',
+ 'ja_JP' => 'ja',
+ 'th_TH' => 'th',
+ 'id_ID' => 'id',
+ 'el_GR' => 'el',
+ );
+
+ $lang = $this->getCurrentLanguage();
+
+ return isset($languages[$lang]) ? $languages[$lang] : 'en';
+ }
+
+ /**
+ * Get current language
+ *
+ * @access public
+ * @return string
+ */
+ public function getCurrentLanguage()
+ {
+ if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['language'])) {
+ return $this->sessionStorage->user['language'];
+ }
+
+ return $this->config->get('application_language', 'en_US');
+ }
+
+ /**
+ * Load translations for the current language
+ *
+ * @access public
+ */
+ public function loadCurrentLanguage()
+ {
+ Translator::load($this->getCurrentLanguage());
+ }
+}
diff --git a/app/Model/Timezone.php b/app/Model/Timezone.php
new file mode 100644
index 00000000..c6b33736
--- /dev/null
+++ b/app/Model/Timezone.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Kanboard\Model;
+
+/**
+ * Class Timezone
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class Timezone extends Base
+{
+ /**
+ * Get available timezones
+ *
+ * @access public
+ * @param boolean $prepend Prepend a default value
+ * @return array
+ */
+ public function getTimezones($prepend = false)
+ {
+ $timezones = timezone_identifiers_list();
+ $listing = array_combine(array_values($timezones), $timezones);
+
+ if ($prepend) {
+ return array('' => t('Application default')) + $listing;
+ }
+
+ return $listing;
+ }
+
+ /**
+ * Get current timezone
+ *
+ * @access public
+ * @return string
+ */
+ public function getCurrentTimezone()
+ {
+ if ($this->userSession->isLogged() && ! empty($this->sessionStorage->user['timezone'])) {
+ return $this->sessionStorage->user['timezone'];
+ }
+
+ return $this->config->get('application_timezone', 'UTC');
+ }
+
+ /**
+ * Set timezone
+ *
+ * @access public
+ */
+ public function setCurrentTimezone()
+ {
+ date_default_timezone_set($this->getCurrentTimezone());
+ }
+}
diff --git a/app/Model/UserNotification.php b/app/Model/UserNotification.php
index 7795da2e..fcd1761b 100644
--- a/app/Model/UserNotification.php
+++ b/app/Model/UserNotification.php
@@ -54,7 +54,7 @@ class UserNotification extends Base
}
// Restore locales
- $this->config->setupTranslations();
+ $this->language->loadCurrentLanguage();
}
/**
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 54e2ad78..31e3a20b 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -35,6 +35,7 @@ class ClassProvider implements ServiceProviderInterface
'CustomFilter',
'Group',
'GroupMember',
+ 'Language',
'LastLogin',
'Link',
'Notification',
@@ -66,6 +67,7 @@ class ClassProvider implements ServiceProviderInterface
'TaskPosition',
'TaskStatus',
'TaskMetadata',
+ 'Timezone',
'Transition',
'User',
'UserLocking',
diff --git a/app/Subscriber/BootstrapSubscriber.php b/app/Subscriber/BootstrapSubscriber.php
index ef0215f3..7e341601 100644
--- a/app/Subscriber/BootstrapSubscriber.php
+++ b/app/Subscriber/BootstrapSubscriber.php
@@ -16,8 +16,8 @@ class BootstrapSubscriber extends BaseSubscriber implements EventSubscriberInter
public function execute()
{
$this->logger->debug('Subscriber executed: '.__METHOD__);
- $this->config->setupTranslations();
- $this->config->setupTimezone();
+ $this->language->loadCurrentLanguage();
+ $this->timezone->setCurrentTimezone();
$this->actionManager->attachEvents();
if ($this->userSession->isLogged()) {
diff --git a/app/User/LdapUserProvider.php b/app/User/LdapUserProvider.php
index 3e2dcd2b..74cf4cd5 100644
--- a/app/User/LdapUserProvider.php
+++ b/app/User/LdapUserProvider.php
@@ -3,6 +3,7 @@
namespace Kanboard\User;
use Kanboard\Core\User\UserProviderInterface;
+use Kanboard\Model\Language;
/**
* LDAP User Provider
@@ -69,6 +70,14 @@ class LdapUserProvider implements UserProviderInterface
protected $photo = '';
/**
+ * User language
+ *
+ * @access protected
+ * @var string
+ */
+ protected $language = '';
+
+ /**
* Constructor
*
* @access public
@@ -80,7 +89,7 @@ class LdapUserProvider implements UserProviderInterface
* @param string[] $groupIds
* @param string $photo
*/
- public function __construct($dn, $username, $name, $email, $role, array $groupIds, $photo = '')
+ public function __construct($dn, $username, $name, $email, $role, array $groupIds, $photo = '', $language = '')
{
$this->dn = $dn;
$this->username = $username;
@@ -89,6 +98,7 @@ class LdapUserProvider implements UserProviderInterface
$this->role = $role;
$this->groupIds = $groupIds;
$this->photo = $photo;
+ $this->language = $language;
}
/**
@@ -198,9 +208,13 @@ class LdapUserProvider implements UserProviderInterface
*/
public function getExtraAttributes()
{
- return array(
- 'is_ldap_user' => 1,
- );
+ $attributes = array('is_ldap_user' => 1);
+
+ if (! empty($this->language)) {
+ $attributes['language'] = Language::findCode($this->language);
+ }
+
+ return $attributes;
}
/**
diff --git a/app/constants.php b/app/constants.php
index 6f30af7f..5e1e886f 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -65,6 +65,7 @@ defined('LDAP_USER_ATTRIBUTE_FULLNAME') or define('LDAP_USER_ATTRIBUTE_FULLNAME'
defined('LDAP_USER_ATTRIBUTE_EMAIL') or define('LDAP_USER_ATTRIBUTE_EMAIL', 'mail');
defined('LDAP_USER_ATTRIBUTE_GROUPS') or define('LDAP_USER_ATTRIBUTE_GROUPS', 'memberof');
defined('LDAP_USER_ATTRIBUTE_PHOTO') or define('LDAP_USER_ATTRIBUTE_PHOTO', '');
+defined('LDAP_USER_ATTRIBUTE_LANGUAGE') or define('LDAP_USER_ATTRIBUTE_LANGUAGE', '');
defined('LDAP_USER_CREATION') or define('LDAP_USER_CREATION', true);
defined('LDAP_GROUP_ADMIN_DN') or define('LDAP_GROUP_ADMIN_DN', '');
diff --git a/config.default.php b/config.default.php
index abc928a9..e3f8932c 100644
--- a/config.default.php
+++ b/config.default.php
@@ -120,6 +120,10 @@ define('LDAP_USER_ATTRIBUTE_GROUPS', 'memberof');
// LDAP attribute for user avatar image: thumbnailPhoto or jpegPhoto
define('LDAP_USER_ATTRIBUTE_PHOTO', '');
+// LDAP attribute for user language, example: 'preferredlanguage'
+// Put an empty string to disable language sync
+define('LDAP_USER_ATTRIBUTE_LANGUAGE', '');
+
// Allow automatic LDAP user creation
define('LDAP_USER_CREATION', true);
diff --git a/doc/config.markdown b/doc/config.markdown
index a8df887f..0e3c3198 100644
--- a/doc/config.markdown
+++ b/doc/config.markdown
@@ -152,6 +152,10 @@ define('LDAP_USER_ATTRIBUTE_GROUPS', 'memberof');
// LDAP attribute for user avatar image: thumbnailPhoto or jpegPhoto
define('LDAP_USER_ATTRIBUTE_PHOTO', '');
+// LDAP attribute for user language, example: 'preferredlanguage'
+// Put an empty string to disable language sync
+define('LDAP_USER_ATTRIBUTE_LANGUAGE', '');
+
// Allow automatic LDAP user creation
define('LDAP_USER_CREATION', true);
diff --git a/doc/ldap-parameters.markdown b/doc/ldap-parameters.markdown
index c18c2b06..80decc67 100644
--- a/doc/ldap-parameters.markdown
+++ b/doc/ldap-parameters.markdown
@@ -21,6 +21,7 @@ Here is the list of available LDAP parameters:
| `LDAP_USER_ATTRIBUTE_EMAIL` | mail | LDAP attribute for user email |
| `LDAP_USER_ATTRIBUTE_GROUPS` | memberof | LDAP attribute to find groups in user profile |
| `LDAP_USER_ATTRIBUTE_PHOTO` | Empty | LDAP attribute to find user photo (jpegPhoto or thumbnailPhoto |
+| `LDAP_USER_ATTRIBUTE_LANGUAGE` | Empty | LDAP attribute for user language (preferredlanguage), the accepted language format is "fr-FR" |
| `LDAP_USER_CREATION` | true | Enable automatic LDAP user creation |
| `LDAP_GROUP_ADMIN_DN` | Empty | LDAP DN for administrators (Example: "CN=Kanboard-Admins,CN=Users,DC=kanboard,DC=local") |
| `LDAP_GROUP_MANAGER_DN` | Empty | LDAP DN for managers (Example: "CN=Kanboard Managers,CN=Users,DC=kanboard,DC=local") |
diff --git a/doc/plugin-registration.markdown b/doc/plugin-registration.markdown
index f212fc2e..03b3c841 100644
--- a/doc/plugin-registration.markdown
+++ b/doc/plugin-registration.markdown
@@ -86,7 +86,7 @@ Plugin can be translated in the same way as the rest of the application. You mus
```php
$this->on('app.bootstrap', function($container) {
- Translator::load($container['config']->getCurrentLanguage(), __DIR__.'/Locale');
+ Translator::load($container['language']->getCurrentLanguage(), __DIR__.'/Locale');
});
```
diff --git a/doc/translations.markdown b/doc/translations.markdown
index 00707e1c..074d9ae3 100644
--- a/doc/translations.markdown
+++ b/doc/translations.markdown
@@ -16,7 +16,7 @@ How to translate Kanboard to a new language?
1. Make a new directory: `app/Locale/xx_XX` for example `app/Locale/fr_CA` for French Canadian
2. Create a new file for the translation: `app/Locale/xx_XX/translations.php`
3. Use the content of the French locales and replace the values
-4. Inside the file `app/Model/Config.php`, add a new entry for your translation inside the function `getLanguages()`
+4. Update the file `app/Model/Language.php`
5. Check with your local installation of Kanboard if everything is OK
6. Send a [pull-request with Github](https://help.github.com/articles/using-pull-requests/)
diff --git a/tests/integration.mysql.xml b/tests/integration.mysql.xml
index 30769371..9d87f77e 100644
--- a/tests/integration.mysql.xml
+++ b/tests/integration.mysql.xml
@@ -13,5 +13,8 @@
<const name="DB_USERNAME" value="root" />
<const name="DB_PASSWORD" value="" />
<const name="DB_PORT" value="" />
+ <const name="DB_SSL_KEY" value="" />
+ <const name="DB_SSL_CA" value="" />
+ <const name="DB_SSL_CERT" value="" />
</php>
-</phpunit> \ No newline at end of file
+</phpunit>
diff --git a/tests/units/Model/ConfigTest.php b/tests/units/Model/ConfigTest.php
index 6ccdbef9..ad74ad50 100644
--- a/tests/units/Model/ConfigTest.php
+++ b/tests/units/Model/ConfigTest.php
@@ -6,66 +6,6 @@ use Kanboard\Model\Config;
class ConfigTest extends Base
{
- public function testGetTimezones()
- {
- $configModel = new Config($this->container);
- $this->assertNotEmpty($configModel->getTimezones());
- $this->assertArrayHasKey('Europe/Paris', $configModel->getTimezones());
- $this->assertContains('Europe/Paris', $configModel->getTimezones());
- $this->assertArrayNotHasKey('', $configModel->getTimezones());
-
- $this->assertArrayHasKey('', $configModel->getTimezones(true));
- $this->assertContains('Application default', $configModel->getTimezones(true));
- }
-
- public function testGetLanguages()
- {
- $configModel = new Config($this->container);
- $this->assertNotEmpty($configModel->getLanguages());
- $this->assertArrayHasKey('fr_FR', $configModel->getLanguages());
- $this->assertContains('Français', $configModel->getLanguages());
- $this->assertArrayNotHasKey('', $configModel->getLanguages());
-
- $this->assertArrayHasKey('', $configModel->getLanguages(true));
- $this->assertContains('Application default', $configModel->getLanguages(true));
- }
-
- public function testGetJsLanguage()
- {
- $configModel = new Config($this->container);
- $this->assertEquals('en', $configModel->getJsLanguageCode());
-
- $this->container['sessionStorage']->user = array('language' => 'fr_FR');
- $this->assertEquals('fr', $configModel->getJsLanguageCode());
-
- $this->container['sessionStorage']->user = array('language' => 'xx_XX');
- $this->assertEquals('en', $configModel->getJsLanguageCode());
- }
-
- public function testGetCurrentLanguage()
- {
- $configModel = new Config($this->container);
- $this->assertEquals('en_US', $configModel->getCurrentLanguage());
-
- $this->container['sessionStorage']->user = array('language' => 'fr_FR');
- $this->assertEquals('fr_FR', $configModel->getCurrentLanguage());
-
- $this->container['sessionStorage']->user = array('language' => 'xx_XX');
- $this->assertEquals('xx_XX', $configModel->getCurrentLanguage());
- }
-
- public function testGetCurrentTimezone()
- {
- $configModel = new Config($this->container);
- $this->assertEquals('UTC', $configModel->getCurrentTimezone());
-
- $this->container['sessionStorage']->user = array('timezone' => 'Europe/Paris');
- $this->assertEquals('Europe/Paris', $configModel->getCurrentTimezone());
-
- $this->container['sessionStorage']->user = array('timezone' => 'Something');
- $this->assertEquals('Something', $configModel->getCurrentTimezone());
- }
-
public function testRegenerateToken()
{
$configModel = new Config($this->container);
diff --git a/tests/units/Model/LanguageTest.php b/tests/units/Model/LanguageTest.php
new file mode 100644
index 00000000..dff98a83
--- /dev/null
+++ b/tests/units/Model/LanguageTest.php
@@ -0,0 +1,58 @@
+<?php
+
+use Kanboard\Model\Language;
+
+require_once __DIR__.'/../Base.php';
+
+class LanguageTest extends Base
+{
+ public function testGetCodes()
+ {
+ $codes = Language::getCodes();
+ $this->assertContains('fr_FR', $codes);
+ $this->assertContains('en_US', $codes);
+ }
+
+ public function testFindCode()
+ {
+ $this->assertSame('', Language::findCode('xx-XX'));
+ $this->assertSame('fr_FR', Language::findCode('fr-FR'));
+ $this->assertSame('en_US', Language::findCode('en-US'));
+ }
+
+ public function testGetJsLanguage()
+ {
+ $languageModel = new Language($this->container);
+ $this->assertEquals('en', $languageModel->getJsLanguageCode());
+
+ $this->container['sessionStorage']->user = array('language' => 'fr_FR');
+ $this->assertEquals('fr', $languageModel->getJsLanguageCode());
+
+ $this->container['sessionStorage']->user = array('language' => 'xx_XX');
+ $this->assertEquals('en', $languageModel->getJsLanguageCode());
+ }
+
+ public function testGetCurrentLanguage()
+ {
+ $languageModel = new Language($this->container);
+ $this->assertEquals('en_US', $languageModel->getCurrentLanguage());
+
+ $this->container['sessionStorage']->user = array('language' => 'fr_FR');
+ $this->assertEquals('fr_FR', $languageModel->getCurrentLanguage());
+
+ $this->container['sessionStorage']->user = array('language' => 'xx_XX');
+ $this->assertEquals('xx_XX', $languageModel->getCurrentLanguage());
+ }
+
+ public function testGetLanguages()
+ {
+ $languageModel = new Language($this->container);
+ $this->assertNotEmpty($languageModel->getLanguages());
+ $this->assertArrayHasKey('fr_FR', $languageModel->getLanguages());
+ $this->assertContains('Français', $languageModel->getLanguages());
+ $this->assertArrayNotHasKey('', $languageModel->getLanguages());
+
+ $this->assertArrayHasKey('', $languageModel->getLanguages(true));
+ $this->assertContains('Application default', $languageModel->getLanguages(true));
+ }
+}
diff --git a/tests/units/Model/ProjectTest.php b/tests/units/Model/ProjectTest.php
index b3dcd2e5..6c50744b 100644
--- a/tests/units/Model/ProjectTest.php
+++ b/tests/units/Model/ProjectTest.php
@@ -15,10 +15,10 @@ class ProjectTest extends Base
{
public function testCreationForAllLanguages()
{
- $c = new Config($this->container);
$p = new Project($this->container);
- foreach ($c->getLanguages() as $locale => $language) {
+ foreach ($this->container['language']->getLanguages() as $locale => $language) {
+ Translator::unload();
Translator::load($locale);
$this->assertNotFalse($p->create(array('name' => 'UnitTest '.$locale)), 'Unable to create project with '.$locale.':'.$language);
}
diff --git a/tests/units/Model/TimezoneTest.php b/tests/units/Model/TimezoneTest.php
new file mode 100644
index 00000000..ac2cd6a1
--- /dev/null
+++ b/tests/units/Model/TimezoneTest.php
@@ -0,0 +1,32 @@
+<?php
+
+require_once __DIR__.'/../Base.php';
+
+use Kanboard\Model\Timezone;
+
+class TimezoneTest extends Base
+{
+ public function testGetTimezones()
+ {
+ $timezoneModel = new Timezone($this->container);
+ $this->assertNotEmpty($timezoneModel->getTimezones());
+ $this->assertArrayHasKey('Europe/Paris', $timezoneModel->getTimezones());
+ $this->assertContains('Europe/Paris', $timezoneModel->getTimezones());
+ $this->assertArrayNotHasKey('', $timezoneModel->getTimezones());
+
+ $this->assertArrayHasKey('', $timezoneModel->getTimezones(true));
+ $this->assertContains('Application default', $timezoneModel->getTimezones(true));
+ }
+
+ public function testGetCurrentTimezone()
+ {
+ $timezoneModel = new Timezone($this->container);
+ $this->assertEquals('UTC', $timezoneModel->getCurrentTimezone());
+
+ $this->container['sessionStorage']->user = array('timezone' => 'Europe/Paris');
+ $this->assertEquals('Europe/Paris', $timezoneModel->getCurrentTimezone());
+
+ $this->container['sessionStorage']->user = array('timezone' => 'Something');
+ $this->assertEquals('Something', $timezoneModel->getCurrentTimezone());
+ }
+}