diff --git a/.htaccess b/DOCS/htaccess similarity index 100% rename from .htaccess rename to DOCS/htaccess diff --git a/DOCS/readme.txt b/DOCS/readme.txt index a93519f..72b76c0 100644 --- a/DOCS/readme.txt +++ b/DOCS/readme.txt @@ -1,29 +1,32 @@ +TaskFreak! Time Tracking +------------------------ +version : 0.4 + + Requirements ------------ -- apache with mod_rewrite +- apache (tested) or any other webserver (not tested) - PHP 5.3.x - mySQL 4.1 or later Setup ----- -1) Set up your virtual host (read further below if using a subfolder instead) -2) create a mySQL database -3) create tables and data with taskfreak_time.sql -4) open app/config/db.php and change database settings +1) create a mySQL database +2) create tables and data with taskfreak_time.sql +3) open app/config/db.php and change database settings You can stop here and have a look. login is "admin" with no password -Subfolder setup ---------------- -If not using a virtual host, you need to change the APP_WWW_URI constant -in app/config/core.php +Enabling clean URLS +------------------- +If using apache with mod_rewrite, you should enable clean URLs -eg. if running under yourdomain.tld/taskfreak -define('APP_WWW_URI', '/taskfreak/'); -don't forget the trailing slash +1) copy the file htaccess from the DOCS folder to the application root folder +2) change its name from htaccess to .htaccess +3) open app/config/core.php, and change APP_URL_REWRITE to true Single user @@ -34,11 +37,15 @@ Search for APP_SETUP_USER_MODEL and set it up to false : define('APP_SETUP_USER_MODEL',false); [/code] +More options +------------ If you feel like playing so more, open app/config/app.php and look into it +To change the application language have a look at DOCS/translation.txt + Known bugs ---------- -- javascript calendar (jdpicker) closes when changing month or year +- some errors might occur on dates depending on your time zone - order by start, stop, or spent doesn't really make sense - very buggy under IE8, and simply unusable with older versions of IE diff --git a/DOCS/release.txt b/DOCS/release.txt index b665d64..35fd667 100644 --- a/DOCS/release.txt +++ b/DOCS/release.txt @@ -1,3 +1,20 @@ +TaskFreak! Time Tracking +------------------------ + +Version 0.4 : 2010-06-11 +------------------------ +Added multi language support +Added french translation +Added non apache (mod_rewrite) support (needs testing) +Improved UI by adding more icons +Improved user menu (drop down menu) +Fixed checkbox bug (checked tasks didn't change status) +Fixed date shortcut on quick task entry +Fixed javascript calendar bug when changing month or year +Fixed changing password bug +Fixed logging with password bug +Other minor bug fixes + Version 0.3 : 2010-05-30 ------------------------ Fixed subfolder installation (virtual host no longer required) diff --git a/DOCS/taskfreak_timer.sql b/DOCS/taskfreak_timer.sql index ec5e916..5869fe2 100644 --- a/DOCS/taskfreak_timer.sql +++ b/DOCS/taskfreak_timer.sql @@ -1,67 +1,23 @@ --- phpMyAdmin SQL Dump --- version 3.3.1 --- http://www.phpmyadmin.net --- --- Host: localhost --- Generation Time: May 30, 2010 at 04:05 PM --- Server version: 5.0.67 --- PHP Version: 5.3.0 - -SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; - --- --- Database: `taskfreak_timer` --- - --- -------------------------------------------------------- - --- --- Table structure for table `acl` --- - -DROP TABLE IF EXISTS `acl`; -CREATE TABLE `acl` ( +CREATE TABLE IF NOT EXISTS `acl` ( `id` mediumint(8) unsigned NOT NULL auto_increment, `name` varchar(127) NOT NULL, `section` varchar(63) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; - --- --- Dumping data for table `acl` --- +) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `acl` VALUES(1, 'task_see_all', 'general'); INSERT INTO `acl` VALUES(2, 'admin_user', 'general'); --- -------------------------------------------------------- - --- --- Table structure for table `acl_user` --- - -DROP TABLE IF EXISTS `acl_user`; -CREATE TABLE `acl_user` ( +CREATE TABLE IF NOT EXISTS `acl_user` ( `user_id` mediumint(8) unsigned NOT NULL, `acl_id` mediumint(8) unsigned NOT NULL, PRIMARY KEY (`user_id`,`acl_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; --- --- Dumping data for table `acl_user` --- - INSERT INTO `acl_user` VALUES(1, 1); INSERT INTO `acl_user` VALUES(1, 2); --- -------------------------------------------------------- - --- --- Table structure for table `member` --- - -DROP TABLE IF EXISTS `member`; -CREATE TABLE `member` ( +CREATE TABLE IF NOT EXISTS `member` ( `id` int(10) unsigned NOT NULL auto_increment, `nickname` varchar(30) NOT NULL, `email` varchar(255) NOT NULL, @@ -81,23 +37,12 @@ CREATE TABLE `member` ( `activation` varchar(16) NOT NULL, `enabled` tinyint(1) unsigned NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; +) ENGINE=MyISAM DEFAULT CHARSET=utf8; --- --- Dumping data for table `member` --- +INSERT INTO `member` VALUES(1, 'Administrator', '', 'admin', '', '12345678', 0, 'Asia/Bangkok', 0, '2010-06-11 01:30:00', '0000-00-00', '0000-00-00 00:00:00', '127.0.0.1', '0000-00-00 00:00:00', 0, 0, '', 1); +INSERT INTO `member` VALUES(2, 'Emilie', '', 'emilie', '', '12345678', 0, 'Europe/Paris', 0, '2010-06-11 01:31:00', '0000-00-00', '0000-00-00 00:00:00', '127.0.0.1', '0000-00-00 00:00:00', 0, 0, '', 1); -INSERT INTO `member` VALUES(1, 'Administrator', '', 'admin', '', '12345678', 0, 'Asia/Bangkok', 0, '2010-05-21 01:43:21', '0000-00-00', '2010-05-30 13:57:18', '127.0.0.1', '0000-00-00 00:00:00', 1, 0, '', 1); -INSERT INTO `member` VALUES(2, 'Emilie', '', 'emilie', '', '12345678', 0, 'Europe/Paris', 0, '2010-05-21 01:44:17', '0000-00-00', '0000-00-00 00:00:00', '127.0.0.1', '0000-00-00 00:00:00', 0, 0, '', 1); - --- -------------------------------------------------------- - --- --- Table structure for table `task` --- - -DROP TABLE IF EXISTS `task`; -CREATE TABLE `task` ( +CREATE TABLE IF NOT EXISTS `task` ( `id` int(10) unsigned NOT NULL auto_increment, `title` varchar(255) NOT NULL, `note` text NOT NULL, @@ -109,23 +54,12 @@ CREATE TABLE `task` ( `member_id` mediumint(8) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `member_id` (`member_id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; +) ENGINE=MyISAM DEFAULT CHARSET=utf8; --- --- Dumping data for table `task` --- +INSERT INTO `task` VALUES(1, 'taskfreak : README first about this beta version', 'Please keep in mind that this is a beta version. There are quite a few known bugs, a handful of unknown bugs.\r\n\r\nHere''s what you can do so far :\r\n- create, edit and archive tasks\r\n- start and stop task timers\r\n- report time spent on a task\r\n- edit your own profile\r\n- see other''s tasks (task manager only)\r\n- create and edit users (user admin only)\r\n\r\nMake sure you read the README file under the DOCS/ folder. There''s a few setup tips in there.', 5, '9999-00-00', '2010-06-11', 0, 0, 1); +INSERT INTO `task` VALUES(2, 'taskfreak : quick notes about TT 0.4', 'Here''s the list of known bugs at release time :\r\n- some errors might occur on dates depending on your time zone\r\n- order by start, stop, or spent doesn''t really make sense\r\n- very buggy under IE8, and simply unusable with older versions of IE\r\n\r\nPlease report found bugs here :\r\nhttp://forum.taskfreak.com/index.php?board=7.0', 4, '9999-00-00', '9999-00-00', 0, 0, 1); -INSERT INTO `task` VALUES(1, 'taskfreak : README first about this beta version', 'Please keep in mind that this is a beta version. There are quite a few known bugs, a handful of unknown bugs.\r\n\r\nHere''s what you can do so far :\r\n- create, edit and archive tasks\r\n- start and stop task timers\r\n- report time spent on a task\r\n- edit your own profile\r\n- see other''s tasks (task manager only)\r\n- create and edit users (user admin only)\r\n\r\nMake sure you read the README file under the DOCS/ folder. There''s a few setup tips in there.', 5, '9999-00-00', '2010-05-30', 0, 0, 1); -INSERT INTO `task` VALUES(2, 'taskfreak : quick notes about TT 0.3', 'Here''s the list of known bugs at release time :\r\n- javascript calendar (jdpicker) closes when changing month or year\r\n- order by start, stop, or spent doesn''t really make sense\r\n- very buggy under IE8, and simply unusable with older versions of IE\r\n\r\nPlease report found bugs here :\r\nhttp://forum.taskfreak.com/index.php?board=7.0', 4, '9999-00-00', '9999-00-00', 0, 0, 1); - --- -------------------------------------------------------- - --- --- Table structure for table `timer` --- - -DROP TABLE IF EXISTS `timer`; -CREATE TABLE `timer` ( +CREATE TABLE IF NOT EXISTS `timer` ( `task_id` int(10) unsigned NOT NULL, `start` datetime NOT NULL, `stop` datetime NOT NULL, @@ -134,7 +68,3 @@ CREATE TABLE `timer` ( KEY `task_id` (`task_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; --- --- Dumping data for table `timer` --- - diff --git a/DOCS/translation.txt b/DOCS/translation.txt new file mode 100644 index 0000000..361a0b7 --- /dev/null +++ b/DOCS/translation.txt @@ -0,0 +1,46 @@ +TaskFreak! Time Tracking +------------------------ + +How to change the default language ? +------------------------------------ + +In app/config/app.php, go to the end of the file and modify its settings : + +For english : +[code] +$GLOBALS['config']['lang'] = array( + 'default' => 'en', + 'user' => 'en', + 'specialchars' => 2 +); +[/code] + +For french : +[code] +$GLOBALS['config']['lang'] = array( + 'default' => 'fr', + 'user' => 'fr', + 'specialchars' => 2 +); +[/code] + +Note : don't bother modifying the specialchars setting + + +How can I translate this app to my language ? +--------------------------------------------- + +There's 5 files you need to look : +- lib/lang/en/config.php +- lib/lang/en/common.php +- app/lang/en/freak.php +- app/lang/en/help_multi_creation.php +- app/lang/en/help_timer_creation.php + +1) Copy folder lib/lang/en to lib/lang/XX where XX is your language code +2) Copy folder app/lang/en to app/lang/XX where XX is your language code +3) Open all copied files and start translating +4) Change the application settings (read instructions above) and test it all + +Then, please send them to taskfreak@gmail.com so your translation can be +included in the next TaskFreak! release \ No newline at end of file diff --git a/README b/README index d1f4ffa..c6d883a 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ TaskFreak! Time Tracking ------------------------ -version : 0.3 -released : 2010-05-30 +version : 0.4 +released : 2010-06-11 status : beta ------------------------ diff --git a/app/config/app.php b/app/config/app.php index c8c1b55..83e0fff 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -3,8 +3,8 @@ // ---- LOG and DEBUGGING ----------------------------------------------------- $GLOBALS['config']['log_front'] = 0; -$GLOBALS['config']['log_debug'] = 1; -$GLOBALS['config']['log_message'] = 1; +$GLOBALS['config']['log_debug'] = 0; +$GLOBALS['config']['log_message'] = 0; $GLOBALS['config']['log_warn'] = 0; $GLOBALS['config']['log_error'] = 1; $GLOBALS['config']['log_core'] = 0; @@ -26,14 +26,6 @@ $GLOBALS['config']['pages'] = array( 'Archives' => 'task/archives' ); -// ---- LANGUAGE DEFAULTS ----------------------------------------------------- - -$GLOBALS['config']['lang'] = array( - 'default' => 'en', - 'user' => 'en', - 'specialchars' => 2 -); - // ---- DATE / TIME FORMATS --------------------------------------------------- // date/time timezone and formats defaults @@ -58,20 +50,20 @@ $GLOBALS['config']['task'] = array( $GLOBALS['config']['task']['priority'] = array( 'options' => array( - 1 => '1) urgent', - 2 => '2) important', - 3 => '3) quickly', - 4 => '4) pretty soon', - 5 => '5) normal', - 6 => '6) after', - 7 => '7) later', - 8 => '8) anytime', - 9 => '9) whatever' + 1 => 'urgent', + 2 => 'important', + 3 => 'quickly', + 4 => 'soon', + 5 => 'normal', + 6 => 'after', + 7 => 'later', + 8 => 'anytime', + 9 => 'whenever' ), 'default' => 5 ); -$GLOBALS['config']['task']['pagination'] = array('15'=>15,'25'=>25,'50'=>50,'all'=>0); +$GLOBALS['config']['task']['pagination'] = array(15=>15,30=>30,50=>50,'all'=>0); $GLOBALS['config']['task']['pagination_default'] = 15; // ---- DEFAULT Javascript ---------------------------------------------------- @@ -88,6 +80,13 @@ $GLOBALS['config']['skin'] = 'default'; // ---- LANGUAGE -------------------------------------------------------------- -$GLOBALS['config']['lang']['default'] = 'en'; -$GLOBALS['config']['lang']['user'] = 'en'; -$GLOBALS['config']['lang']['specialchars'] = 2; +$GLOBALS['config']['lang'] = array( + 'default' => 'en', + 'user' => 'en', + 'specialchars' => 2 +); + +$GLOBALS['config']['lang']['files'] = array( + 'common.php' => APP_INCLUDE_PATH.'lib/lang/', + 'freak.php' => APP_INCLUDE_PATH.'app/lang/' +); diff --git a/app/config/core.php b/app/config/core.php index 414b8e2..dbad8da 100644 --- a/app/config/core.php +++ b/app/config/core.php @@ -3,8 +3,6 @@ error_reporting(E_ALL); // --- APPLICATION SETUP ------------------------------------------------------ -$GLOBALS['config'] = array(); - // connect to database (see /app/config/db.php for settings) define('APP_SETUP_DATABASE', true); @@ -15,7 +13,7 @@ define('APP_SETUP_GLOBAL_SETTINGS', false); define('APP_SETUP_USER_SETTINGS', false); // use translation helper -define('APP_SETUP_TRANSLATOR', false); +define('APP_SETUP_TRANSLATOR', true); // use (trans-sessions) messaging helper define('APP_SETUP_MESSAGING', true); @@ -23,6 +21,8 @@ define('APP_SETUP_MESSAGING', true); // use navi helper define('APP_SETUP_NAVI', true); +$GLOBALS['config'] = array(); + // --- USER AUTHENTICATION SETUP ---------------------------------------------- // model class used for app users @@ -45,7 +45,7 @@ $GLOBALS['config']['auth'] = array( // allow auto login (true or false) 'password_recover' => true, // allow password recovery (true or false) - 'register' => 2 + 'register' => 0 // register mode // 0: no registration, 1: account created directly (no validation) // 2: user validation (from email), 3: admin validate account @@ -62,23 +62,30 @@ define('APP_CONFIG_PATH',APP_CORE_PATH.'config/'); define('APP_MODEL_PATH',APP_CORE_PATH.'model/'); define('APP_CONTROLLER_PATH',APP_CORE_PATH.'controller/'); define('APP_VIEW_PATH',APP_CORE_PATH.'view/'); +define('APP_CACHE_PATH',APP_ROOT_PATH.'cache/'); define('APP_INCLUDE_PATH', APP_ROOT_PATH); -define('APP_CACHE_PATH',APP_INCLUDE_PATH.'cache/'); define('APP_LIB_PATH',APP_INCLUDE_PATH.'lib/'); define('APP_CLASS_PATH',APP_LIB_PATH.'class/'); define('APP_HELPER_PATH',APP_LIB_PATH.'helper/'); +define('APP_LANGUAGE_PATH',APP_LIB_PATH.'lang/'); define('APP_ASSET_PATH',APP_ROOT_PATH.'asset/'); -define('APP_LANGUAGE_PATH',APP_ASSET_PATH.'lang/'); define('APP_PLUGIN_PATH',APP_ROOT_PATH.'plugin/'); define('APP_SKIN_PATH',APP_ROOT_PATH.'skin/'); // ---- APPLICATION URLs ------------------------------------------------------ -define('APP_URL_REWRITE', true); -define('APP_WWW_URI', '/'); -// define('APP_WWW_URI', '/taskfreak/'); +define('APP_URL_REWRITE', false); + +$uri = trim(substr(APP_WWW_PATH,strlen($_SERVER['DOCUMENT_ROOT'])),'/'); +if (empty($uri)) { + $uri = '/'; +} else { + $uri = '/'.$uri.'/'; +} +define('APP_WWW_URI', $uri); +unset($uri); define('APP_WWW_URL','http://'.$_SERVER['SERVER_NAME'].APP_WWW_URI); @@ -87,7 +94,7 @@ define('APP_WWW_URL','http://'.$_SERVER['SERVER_NAME'].APP_WWW_URI); define('APP_USER_ID_LENGTH',8); // length of user ID define('APP_USER_SANITIZE','/^[a-z0-9_-]+$/i'); define('APP_USER_NAME_MIN',4); // minimum length for username -define('APP_USER_NAME_MAX',15); // maximum length for username +define('APP_USER_NAME_MAX',16); // maximum length for username define('APP_USER_PASS_MIN',4); // minimum length for password define('APP_USER_PASS_MAX',16); // maximum length for password define('APP_PASSWORD_SANITIZE','/^[a-z0-9%!@#&*+:;,<>\.\?\|\{\}\(\)\[\]\$_-]+$/i'); diff --git a/app/config/path.php b/app/config/path.php index 4528da3..8b896da 100644 --- a/app/config/path.php +++ b/app/config/path.php @@ -33,4 +33,9 @@ $GLOBALS['config']['path']['css'] = array( $GLOBALS['config']['path']['js'] = array( $GLOBALS['config']['skin'].'/js/', 'asset/js/' +); + +$GLOBALS['config']['path']['lang'] = array( + 'lib/lang/', + 'app/lang/' ); \ No newline at end of file diff --git a/app/controller/admin.php b/app/controller/admin.php index c4e4621..4566173 100644 --- a/app/controller/admin.php +++ b/app/controller/admin.php @@ -4,7 +4,7 @@ * * @package taskfreak_tt * @author Stan Ozier - * @version 0.3 + * @version 0.4 * @copyright GNU General Public License (GPL) version 3 */ @@ -26,7 +26,7 @@ class Admin extends AppController { $this->page->clean('js'); } else { $this->page->add('css',array('form.css','freak.css','list.css','tracker.css','colorbox.css')); - // $this->page->add('js',array('jquery.form.min.js','jquery.colorbox-min.js')); + $this->_addJsSettings(); $this->page->add('js','freak.js'); } } @@ -42,17 +42,17 @@ class Admin extends AppController { $this->limit = $this->fc->sessionVariable('userlimit'); $this->search = $this->fc->sessionVariable('search'); - $title = 'All users'; + $title = TR::get('ui','all_users'); $filter = ''; switch ($this->filter) { case '1': - $title = 'Task managers'; + $title = TR::get('ui','task_managers'); $filter = "actags LIKE '%task_see_all%'"; $this->limit = 0; break; case '2': - $title = 'User managers'; + $title = TR::get('ui','user_admins'); $filter = "actags LIKE '%admin_user%'"; $this->limit = 0; break; @@ -101,9 +101,11 @@ class Admin extends AppController { if ($this->fc->chkReqVar('pass1') && $this->fc->chkReqVar('pass2')) { if ($this->data->setPassword($this->fc->getReqVar('pass1'), $this->fc->getReqVar('pass2'))) { // save it all + error_log('setting new password : '.$this->fc->getReqVar('pass1')); $this->data->ignore(); } else { // do not save password + error_log('can not save password'); $this->data->ignore('password,salt'); } } @@ -113,10 +115,11 @@ class Admin extends AppController { $myself = ($this->data->getUid() == $this->fc->user->getUid()); if ($this->data->save(!$myself)) { if ($myself) { - // editing own profile need to relogin + // editing own profile need to reset session + error_log('updating session'); $this->data->updateSessionVariables(); } - $this->fc->autoRedirect('user saved'); + $this->fc->autoRedirect('saved'); } } return true; @@ -133,18 +136,18 @@ class Admin extends AppController { $db->query('DELETE FROM '.$this->data->dbTable('acl_user').' WHERE user_id='.$this->data->getUid()); // delete this user's tasks $db->query('DELETE FROM '.$this->data->dbTable('task').' WHERE member_id='.$this->data->getUid()); - $this->fc->redirect(APP_WWW_URI.'admin','user deleted'); + $this->fc->redirect($this->fc->getUrl('admin'),'deleted'); } } - $this->fc->redirect(APP_WWW_URI.'admin','user deleted'); + $this->fc->redirect($this->fc->getUrl('admin'),'deleted'); } public function switchAction() { if (!$this->fc->user->checkAcl('task_see_all')) { - $this->fc->redirect(APP_WWW_URI,'access_denied'); + $this->fc->redirect(APP_WWW_URI,'[error]access_denied'); } if ($id = $this->fc->getReqVar('id')) { @@ -156,7 +159,7 @@ class Admin extends AppController { $this->fc->setSessionVariable('switch_id', $id); $this->fc->setSessionVariable('switch_name', $obj->get('nickname')); } - $this->fc->redirect(APP_WWW_URI,'switched to '.$obj->get('nickname')); + $this->fc->redirect(APP_WWW_URI,'[ui]switched'); } $this->switch_id = $this->fc->getSessionVariable('switch_id'); @@ -202,4 +205,18 @@ class Admin extends AppController { return true; } + protected function _addJsSettings() { + $js = "var RELOAD_URI='".APP_WWW_URI."task/main/ajax/1'; var URLMODREWRITE=true; "; + + if (!APP_URL_REWRITE) { + $js = "var RELOAD_URI='".APP_WWW_URI."?c=task&a=main&ajax=1'; var URLMODREWRITE=false; "; + } + + // translations + $js .= "var LANGRUNNING='".TR::html('task','running')."'; "; + $js .= "var LANGCONFIRM='".TR::html('data','delete_confirm')."'; "; + + $this->page->add('jsCode', $js); + } + } diff --git a/app/controller/login.php b/app/controller/login.php index e3cb402..cb0c8be 100644 --- a/app/controller/login.php +++ b/app/controller/login.php @@ -25,7 +25,7 @@ class Login extends AppController { */ public function mainAction() { $this->fc->user->addHelper('html_form'); - $this->page->set('title','TaskFreak! Login'); + $this->page->set('title','TaskFreak! '.TR::get('security','login')); $this->page->add('css',array('form.css','freak.css','login.css')); $this->page->add('js','form.js'); $this->setView('login/login'); diff --git a/app/controller/task.php b/app/controller/task.php index 8569692..ed674b7 100644 --- a/app/controller/task.php +++ b/app/controller/task.php @@ -4,7 +4,7 @@ * * @package taskfreak_tt * @author Stan Ozier - * @version 0.3 + * @version 0.4 * @copyright GNU General Public License (GPL) version 3 */ @@ -38,45 +38,46 @@ class Task extends AppController { } else { $this->page->add('css',array('form.css','freak.css','list.css','tracker.css','colorbox.css')); // $this->page->add('js',array('jquery.form.min.js','jquery.colorbox-min.js')); + $this->_addJsSettings(); $this->page->add('js','freak.js'); } } public function mainAction() { $this->filter = $this->fc->sessionVariable('filter'); - $title = 'Todo'; + $title = 'todo'; $filter = 'status=0 AND archived=0'; $this->actions = array(); switch ($this->filter) { case '1': - $title = 'Completed'; + $title = 'done'; $filter = 'status=1 AND archived=0'; - $this->actions['open'] = 'Re-open'; - $this->actions['valid'] = 'Validate'; - $this->actions['archive'] = 'Archive'; + $this->actions['open'] = 'reopen'; + $this->actions['valid'] = 'validate'; + $this->actions['archive'] = 'archive'; break; case '2': - $title = 'Valid'; // -TODO- check english term + $title = 'valid'; $filter = 'status=2 AND archived=0'; - $this->actions['open'] = 'Re-open'; - $this->actions['archive'] = 'Archive'; + $this->actions['open'] = 'reopen'; + $this->actions['archive'] = 'archive'; break; case '3': - $title = 'Archives'; + $title = 'archives'; $filter = 'archived=1'; - $this->actions['unarchive'] = 'Unarchive'; + $this->actions['unarchive'] = 'unarchive'; break; default: - $this->actions['report'] = 'Report 1 day'; - $this->actions['close'] = 'Mark as done'; - $this->actions['valid'] = 'Validate'; - $this->actions['archive'] = 'Archive'; + $this->actions['report'] = 'postpone_1_day'; + $this->actions['close'] = 'mark_done'; + $this->actions['valid'] = 'validate'; + $this->actions['archive'] = 'archive'; break; } $this->_taskList($filter); - $this->page->set('title',$title.' | TaskFreak! Time Tracker'); + $this->page->set('title',TR::get('pages',$title).' | TaskFreak! Time Tracker'); if ($this->fc->getReqVar('ajax')) { $this->setView('include/list-'.($this->expand?'expand':'compact')); @@ -91,14 +92,14 @@ class Task extends AppController { // drop if no checkbox have been checked if (!$this->fc->chkReqVar('chk')) { // -TODO- show error - $this->fc->redirect(APP_WWW_URI.'task/main/','please mark at least one task'); + $this->fc->redirect($this->fc->getUrl('task','main'),'[error]none_checked'); } // check action request $action = $this->fc->chkReqVar('report,open,close,valid,archive,unarchive'); // do it then TaskModel::updateManyAtOnce($action, $_POST['chk']); // reload entire page - $this->fc->redirect(APP_WWW_URI.'task/main/'); + $this->fc->redirect($this->fc->getUrl('task','main')); } /** @@ -123,7 +124,7 @@ class Task extends AppController { // now start selected task TimerModel::start($id); $this->current = TaskSummary::loadCurrent(); - $this->jsCode .= "clockstart('$id')"; + $this->jsCode .= "clockstart('$id');$('#drun button').wTip();"; } $this->setView('include/timer'); $this->view(); @@ -159,7 +160,7 @@ class Task extends AppController { $this->jsCode .= "clockreport('$cid');clockstatus('paused');"; } else { // nope, requested task is not running, show error - $this->jsCode = "alert('error trying to pause')"; + $this->jsCode = "alert('".TR::get('error','action_failed')."')"; FC::log_debug('error trying to pause non running task'); } break; @@ -173,7 +174,7 @@ class Task extends AppController { if (TimerModel::stop($id)) { $this->jsCode = "clockstatus();"; } else { - $this->jsCode = "alert('task already stopped');"; + $this->jsCode = "alert('".TR::get('error','action_failed')."');"; } $this->current = false; break; @@ -273,7 +274,7 @@ class Task extends AppController { $this->timer = new TimerModel(); $this->timer->addHelper('html_form'); - $this->page->set('title','Todo details | TaskFreak! Time Tracker'); + $this->page->set('title',TR::get('pages','view_task').' | TaskFreak! Time Tracker'); // $this->page->add('js',array('jquery.dateentry.pack.js','jquery.timeentry.pack.js')); $this->setView('view'); $this->view(); @@ -282,7 +283,7 @@ class Task extends AppController { public function createAction() { $this->_loadTask(); $this->data->addHelper('html_form'); - $this->page->set('title','Create Multiple Todos | TaskFreak! Time Tracker'); + $this->page->set('title',TR::get('pages','create_tasks').' | TaskFreak! Time Tracker'); $this->setView('create'); $this->view(); } @@ -305,14 +306,14 @@ class Task extends AppController { } } } - $this->fc->redirect(APP_WWW_URI.'task/main',$i.' task(s) created !'); + $this->fc->redirect($this->fc->getUrl('task','main'),'created'); // -TODO- show $i } public function editAction() { $this->_loadTask(); $this->data->addHelper('html_form'); - $this->page->set('title',($this->data->getUid()?'Edit':'Create').' Todo | TaskFreak! Time Tracker'); + $this->page->set('title',TR::get('pages',($this->data->getUid()?'edit':'create').'_task').' | TaskFreak! Time Tracker'); $this->setView('edit'); $this->view(); } @@ -342,4 +343,18 @@ class Task extends AppController { return $this->data->getUid(); } + protected function _addJsSettings() { + $js = "var RELOAD_URI='".APP_WWW_URI."task/main/ajax/1'; var URLMODREWRITE=true; "; + + if (!APP_URL_REWRITE) { + $js = "var RELOAD_URI='".APP_WWW_URI."?c=task&a=main&ajax=1'; var URLMODREWRITE=false; "; + } + + // translations + $js .= "var LANGRUNNING='".TR::html('task','running')."'; "; + $js .= "var LANGCONFIRM='".TR::html('data','delete_confirm')."'; "; + + $this->page->add('jsCode', $js); + } + } \ No newline at end of file diff --git a/app/controller/timer.php b/app/controller/timer.php index 414eb3c..74af503 100644 --- a/app/controller/timer.php +++ b/app/controller/timer.php @@ -4,7 +4,7 @@ * * @package taskfreak_tt * @author Stan Ozier - * @version 0.3 + * @version 0.4 * @copyright GNU General Public License (GPL) version 3 */ @@ -79,7 +79,7 @@ class Timer extends AppController { echo ''; - echo '

time added

'; + echo '

'.TR::html('message','time_added').'

'; return false; } @@ -89,7 +89,7 @@ class Timer extends AppController { $start = $this->fc->getReqVar('start'); if (empty($id) || empty($start)) { - $this->fc->redirect(APP_WWW_URI,'ERROR:missing parameters'); + $this->fc->redirect(APP_WWW_URI,'[error]action_failed'); } // delete timer @@ -115,7 +115,7 @@ class Timer extends AppController { echo "reloadList();"; echo ''; } else { - $this->fc->redirect(APP_WWW_URI,'Timer deleted'); + $this->fc->redirect(APP_WWW_URI,'deleted'); } } else { // error deleting @@ -124,7 +124,7 @@ class Timer extends AppController { echo 'alert("can not delete timer");'; echo ''; } else { - $this->fc->redirect(APP_WWW_URI,'Timer NOT deleted'); + $this->fc->redirect(APP_WWW_URI,'[error]action_deleted'); } } diff --git a/app/lang/en/freak.php b/app/lang/en/freak.php new file mode 100644 index 0000000..b928252 --- /dev/null +++ b/app/lang/en/freak.php @@ -0,0 +1,120 @@ + + * @version 0.4 + * @copyright GNU General Public License (GPL) version 3 + */ + +$GLOBALS['lang']['task'] = array( + 'priority' => 'priority', + 'spent' => 'spent', + 'note' => 'note', + 'todo' => 'todo', + 'done' => 'done', + 'valid' => 'valid', + 'archived' => 'archived', + 'running' => 'running', + 'paused' => 'paused' +); + +$GLOBALS['lang']['priority'] = array( + 'urgent' => 'urgent', + 'important' => 'important', + 'high' => 'high', + 'quickly' => 'quickly', + 'pretty_soon' => 'pretty soon', + 'soon' => 'soon', + 'normal' => 'normal', + 'after' => 'after', + 'later' => 'later', + 'low' => 'low', + 'anytime' => 'anytime', + 'whenever' => 'whenever' +); + +$GLOBALS['lang']['ui'] = array( + 'reload' => 'reload', + 'reload_list' => 'reload list', + 'task' => 'task', + 'tasks' => 'tasks', + 'create_single' => 'create single task', + 'create_multi' => 'create multiple task', + 'edit_task' => 'edit task', + 'delete_task' => 'delete task', + 'start_task' => 'start task', + 'mark_archived' => 'mark task as archived', + 'done_confirm' => 'really mark this task as completed ?', + 'compact' => 'compact', + 'expand' => 'expand', + 'select_all' => 'select all', + 'info' => 'info', + 'history' => 'history', + 'history_empty' => 'no time reports yet', + 'report_spent' => 'report time spent', + 'total' => 'total', + 'user_menu' => 'show user menu', + 'admin' => 'admin', + 'settings' => 'settings', + 'all_users' => 'all users', + 'switch' => 'switch', + 'switch_user' => 'see other user\'s tasks', + 'select_user' => 'select user whose tasks you want to see', + 'switched' => 'switched to another user', + 'task_manager' => 'task manager', + 'task_managers' => 'task managers', + 'user_admin' => 'user admin', + 'user_admins' => 'user admins', + 'last_visit' => 'last visit', + 'preferences' => 'my preferences', + 'create_user' => 'create user', + 'edit_user' => 'edit user', + 'delete_user' => 'delete user' +); + +$GLOBALS['lang']['pages'] = array( + 'todo' => 'todo', + 'done' => 'done', + 'valid' => 'valid', + 'archives' => 'archives', + 'edit_task' => 'edit task', + 'create_task' => 'create task', + 'create_tasks' => 'create multiple tasks', + 'view_task' => 'task details' +); + +$arrMess = array( + 'task_created' => 'task created', + 'task_updated' => 'task updated', + '%_task_created' => '% task(s) created', + 'task_deleted' => 'task deleted', + 'time_added' => 'work time reported' +); +// we're adding these translations to the standard messages translations +$GLOBALS['lang']['message'] = $GLOBALS['lang']['message']+$arrMess; + +$arrButton = array( + 'pause' => 'pause', + 'resume' => 'resume', + 'done' => 'done', + 'reopen' => 're-open', + 'postpone_1_day' => 'postpone 1 day', + 'postpone_2_days' => 'postpone 2 days', + 'postpone_1_week' => 'postpone 1 week', + 'postpone_2_weeks' => 'postpone 2 weeks', + 'postpone_1_month' => 'postpone 1 month', + 'postpone_2_months' => 'postpone 2 months', + 'postpone_1_year' => 'postpone 1 year', + 'postpone_2_years' => 'postpone 2 years', + 'mark_done' => 'mark as done', + 'validate' => 'validate', + 'archive' => 'archive', + 'unarchive' => 'unarchive', + 'save_report' => 'save_report', + 'save_task' => 'save task', + 'save_and_start' => 'save and start' +); +// we're adding these translations to the standard button translations +$GLOBALS['lang']['button'] = $GLOBALS['lang']['button']+$arrButton; \ No newline at end of file diff --git a/app/lang/en/help_multi_creation.php b/app/lang/en/help_multi_creation.php new file mode 100644 index 0000000..e612581 --- /dev/null +++ b/app/lang/en/help_multi_creation.php @@ -0,0 +1,19 @@ +

Enter one task per line.

+

Task format

+

Task format : [date] [priority] [label :] task title
+fields within brackets are optional

+

date can be :

+
    +
  • a date in format dd/mm[/yy]
  • +
  • a + followed by number of days in the future
  • +
  • a - means no deadline
  • +
  • nothing means deadline is today
  • +
+

priority is a number between 1 and 9, followed by a )
+« 1) » for urgent tasks, « 5) » for normal priority

+

label is optional

+

Defaults for multiple tasks

+

a line starting by a * sets up defaults

+

Format is : * [date] [label]
+« * +1 taskfreak » or « * 12/04 »

+

reset defaults with a line with « ** »

\ No newline at end of file diff --git a/app/lang/en/help_timer_creation.php b/app/lang/en/help_timer_creation.php new file mode 100644 index 0000000..88a1302 --- /dev/null +++ b/app/lang/en/help_timer_creation.php @@ -0,0 +1,8 @@ +

Enter either :

+
    +
  • A start time only (will calculate time from then until now)
  • +
  • A time spent only (will consider you've just finished the task)
  • +
  • A start time and an stop time
  • +
  • A start time and a time spent
  • +
  • A stop time and a time spent
  • +
\ No newline at end of file diff --git a/app/lang/fr/freak.php b/app/lang/fr/freak.php new file mode 100644 index 0000000..3ba9487 --- /dev/null +++ b/app/lang/fr/freak.php @@ -0,0 +1,120 @@ + + * @version 0.4 + * @copyright GNU General Public License (GPL) version 3 + */ + +$GLOBALS['lang']['task'] = array( + 'priority' => 'priorité', + 'spent' => 'durée', + 'note' => 'note', + 'todo' => 'à faire', + 'done' => 'effectué', + 'valid' => 'validé', + 'archived' => 'archivé', + 'running' => 'en cours', + 'paused' => 'en pause`' +); + +$GLOBALS['lang']['priority'] = array( + 'urgent' => 'urgent', + 'important' => 'important', + 'high' => 'haute', + 'quickly' => 'dès que possible', + 'pretty_soon' => 'rapidement', + 'soon' => 'bientôt', + 'normal' => 'normal', + 'after' => 'après', + 'later' => 'plus tard', + 'low' => 'faible', + 'anytime' => 'bien plus tard', + 'whenever' => 'peu importe' +); + +$GLOBALS['lang']['ui'] = array( + 'reload' => 'recharger', + 'reload_list' => 'recharger la liste', + 'task' => 'tâche', + 'tasks' => 'tâches', + 'create_single' => 'créer une tâche', + 'create_multi' => 'créer plusieurs tâches', + 'edit_task' => 'modifier tâche', + 'delete_task' => 'supprimer tâche', + 'start_task' => 'démarrer la tâche', + 'mark_archived' => 'marquer comme archivé', + 'done_confirm' => 'vraiment marquer comme effectuée?', + 'compact' => 'compacte', + 'expand' => 'étendue', + 'select_all' => 'tout sélectionner', + 'info' => 'info', + 'history' => 'historique', + 'history_empty' => 'aucune durée rapportée', + 'report_spent' => 'rapporter une durée passée', + 'total' => 'total', + 'user_menu' => 'menu utilisateur', + 'admin' => 'administration', + 'settings' => 'paramètres', + 'all_users' => 'tous utilisateurs', + 'switch' => 'changer', + 'switch_user' => 'changer d\'utilisateur', + 'select_user' => 'choisir un utiisateur pour en voir les tâches', + 'switched' => 'changement effectué', + 'task_manager' => 'chef de projet', + 'task_managers' => 'chefs de projet', + 'user_admin' => 'administrateur', + 'user_admins' => 'administrateurs', + 'last_visit' => 'dernière visite', + 'preferences' => 'mes préférences', + 'create_user' => 'créer utilisateur', + 'edit_user' => 'moditier utilisateur', + 'delete_user' => 'supprimer utilisateur' +); + +$GLOBALS['lang']['pages'] = array( + 'todo' => 'tâches à faire', + 'done' => 'tâches effectuées', + 'valid' => 'tâches validées', + 'archives' => 'archives', + 'edit_task' => 'modifier une tâche', + 'create_task' => 'créer une tâche', + 'create_tasks' => 'créer plusieurs tâches', + 'view_task' => 'détails de la tâche' +); + +$arrMess = array( + 'task_created' => 'tâche créée', + 'task_updated' => 'tâche mise à jour', + '%_task_created' => '% tâche(s) crées', + 'task_deleted' => 'tâche supprimée', + 'time_added' => 'temps passé enregistré' +); +// we're adding these translations to the standard messages translations +$GLOBALS['lang']['message'] = $GLOBALS['lang']['message']+$arrMess; + +$arrButton = array( + 'pause' => 'pause', + 'resume' => 'reprendre', + 'done' => 'effectuée', + 'reopen' => 'réouvrir', + 'postpone_1_day' => 'repousser d\'un jour', + 'postpone_2_days' => 'repousser de 2 jours', + 'postpone_1_week' => 'repousser d\'une semaine', + 'postpone_2_weeks' => 'repousser de 2 semaines', + 'postpone_1_month' => 'repousser d\'un mois', + 'postpone_2_months' => 'repousser de 2 mois', + 'postpone_1_year' => 'repousser d\'une année', + 'postpone_2_years' => 'repousser de 2 ans', + 'mark_done' => 'marquer effectuée', + 'validate' => 'valider', + 'archive' => 'archiver', + 'unarchive' => 'réactiver', + 'save_report' => 'rapporter', + 'save_task' => 'enregistrer la tâche', + 'save_and_start' => 'enregistrer et démarrer' +); +// we're adding these translations to the standard button translations +$GLOBALS['lang']['button'] = $GLOBALS['lang']['button']+$arrButton; \ No newline at end of file diff --git a/app/lang/fr/help_multi_creation.php b/app/lang/fr/help_multi_creation.php new file mode 100644 index 0000000..b8cc2a7 --- /dev/null +++ b/app/lang/fr/help_multi_creation.php @@ -0,0 +1,19 @@ +

Saisir une tâche par ligne.

+

Format de la saisie :

+

[date] [priorité] [mot-clé :] titre de la tâche
+les champs entre crochets sont facultatifs

+

date peut être :

+
    +
  • une date au format jj/mm[/aa]
  • +
  • un + suivi du nombre de jours dans le futur
  • +
  • un - signifie pas de date
  • +
  • pas de date signifie aujourd'hui
  • +
+

priorité: un chiffre entre 1 et 9 suivi de )
+« 1) » pour urgent, « 5) » pour normal

+

mot-clé est facultatif

+

Valeurs par défaut pour plusieurs tâches

+

commençer par * indique les valeurs par défaut

+

Le format est : * [date] [mot-clé]
+« * +1 taskfreak » ou « * 12/04 »

+

annuler les valeurs par défaut : « ** » sur une ligne

\ No newline at end of file diff --git a/app/lang/fr/help_timer_creation.php b/app/lang/fr/help_timer_creation.php new file mode 100644 index 0000000..1ad2c10 --- /dev/null +++ b/app/lang/fr/help_timer_creation.php @@ -0,0 +1,8 @@ +

Saisir soit :

+
    +
  • Une heure de début (calcule le temps passé jusqu'à maintenant)
  • +
  • Un temps passé (considère que vous venez juste de terminer)
  • +
  • Une heure de départ et une heure de fin
  • +
  • Une heure de départ et un temps passé
  • +
  • Une heure de fin et un temps passé
  • +
\ No newline at end of file diff --git a/app/model/member.php b/app/model/member.php index 1eb5f8c..7ae2450 100644 --- a/app/model/member.php +++ b/app/model/member.php @@ -4,7 +4,7 @@ * * @package taskfreak_tt * @author Stan Ozier - * @version 0.2 + * @version 0.4 * @copyright GNU General Public License (GPL) version 3 */ @@ -29,10 +29,10 @@ class MemberModel extends UserAclModel { $arr = explode(',', $this->get('actags')); $arrTrans = array(); if (in_array('task_see_all', $arr)) { - $arrTrans[] = 'task manager'; + $arrTrans[] = TR::html('ui','task_manager'); } if (in_array('admin_user', $arr)) { - $arrTrans[] = 'user admin'; + $arrTrans[] = TR::html('ui','user_admin'); } return implode(', ',$arrTrans); } diff --git a/app/model/task.php b/app/model/task.php index fde9d01..c4d800f 100644 --- a/app/model/task.php +++ b/app/model/task.php @@ -4,7 +4,7 @@ * * @package taskfreak_tt * @author Stan Ozier - * @version 0.2 + * @version 0.4 * @copyright GNU General Public License (GPL) version 3 */ @@ -183,15 +183,15 @@ class TaskSummary extends TaskModel { public function htmlPriority() { $arr = $this->getPropertyOptions('priority'); $st = $this->get('priority'); - return $arr['options'][$st]; + return $st.') '.TR::html('priority',$arr['options'][$st]); } public function htmlStatus() { $arr = $this->getPropertyOptions('status'); $str = $this->get('status'); - $str = $arr['options'][$str]; // -TODO- TRANSLATE + $str = TR::html('task',$arr['options'][$str]); if ($this->get('archived')) { - $str .= ' (archived)'; + $str .= ' ('.TR::html('task','archived').')'; } return $str; } @@ -201,7 +201,6 @@ class TaskSummary extends TaskModel { if ($this->isEmpty('begin')) { return '-'; } else { - // -TODO- show in grey return $this->html('begin',APP_DATE); } } else { @@ -237,11 +236,11 @@ class TaskSummary extends TaskModel { case 9999: return '-'; case -1: - return 'yesterday'; + return TR::html('date','yesterday'); case 0: - return 'today'; + return TR::html('date','today'); case 1: - return 'tomorrow'; + return TR::html('date','tomorrow'); default: return $this->html('deadline',APP_DATE); } @@ -313,7 +312,7 @@ class TaskSummary extends TaskModel { if ($stopped) { return '--:--'; } else { - return 'running'; + return TR::html('task','running'); } } $h = floor($spent / 60); diff --git a/app/view/admin/switch.php b/app/view/admin/switch.php index f09c934..bed378c 100644 --- a/app/view/admin/switch.php +++ b/app/view/admin/switch.php @@ -2,7 +2,7 @@ $this->incView('include/page-top', false); ?> -

Select user whose tasks you want to see

+

    data->next()) { @@ -10,7 +10,7 @@ while ($this->data->next()) { if ($this->data->getUid() == $this->switch_id) { echo $this->data->html('nickname'); } else { - echo ''.$this->data->html('nickname').''; + echo ''.$this->data->html('nickname').''; } echo ''; } diff --git a/app/view/admin/user-edit.php b/app/view/admin/user-edit.php index 35c66d0..bd57ade 100644 --- a/app/view/admin/user-edit.php +++ b/app/view/admin/user-edit.php @@ -5,12 +5,12 @@ $this->incView('include/page-top', false); echo '

    '; if ($id = $this->data->getUid()) { if ($id == $this->fc->user->getUid()) { - echo 'My preferences'; + TR::phtml('security','my_account'); } else { - echo 'Edit a user'; + TR::phtml('ui','edit_user'); } } else { - echo 'Create new user'; + TR::phtml('ui','create_user'); } echo '

    '; @@ -20,22 +20,22 @@ echo $this->data->iHidden('id'); ?>
      data->iFieldLabelled('nickname','','','li class="compulsory"'); - echo $this->data->iFieldLabelled('email'); + echo $this->data->iFieldLabelled('nickname',TR::html('form','nick_name'),'','li class="compulsory"'); + echo $this->data->iFieldLabelled('email',TR::html('form','email')); ?>
    1. - + data->iTimeZone('time_zone'); ?>
    2. data->iFieldLabelled('username','','','li class="compulsory"'); + echo $this->data->iFieldLabelled('username',TR::html('form','username'),'','li class="compulsory"'); ?>
    3. - + data->iPass('pass1', false); ?>
    4. - + data->iPass('pass2', false); ?>
    5. data->iHidden('id'); // can only change rights for other users ?>
    6. - +
      • data->checkAcl('task_see_all')) echo ' checked="checked"'; - ?> />
      • + ?> />
      • data->checkAcl('admin_user')) echo ' checked="checked"'; - ?> />
      • + ?> />
    7. - + canDeleteThisUser) { ?> Delete + onclick="return confirm('');" class="button marge delete"> diff --git a/app/view/admin/user-list.php b/app/view/admin/user-list.php index 069f0d7..dd7f556 100644 --- a/app/view/admin/user-list.php +++ b/app/view/admin/user-list.php @@ -5,7 +5,7 @@ $this->incView('include/page-top', false);
      - Create user + @@ -40,7 +40,7 @@ $this->incView('include/page-top', false); if ($this->limit == $val) { echo ' class="active"'; } - echo '>$val)).'>'.$lbl.'
    8. '; + echo '>$val)).'>'.(is_int($lbl)?$lbl:TR::html('data',$lbl)).''; } ?>
@@ -48,9 +48,17 @@ $this->incView('include/page-top', false); if ($this->search) { echo ' class="filled"'; } ?>>

+ + + + - - + +

diff --git a/app/view/view.php b/app/view/view.php index aed85fa..c54a2b0 100644 --- a/app/view/view.php +++ b/app/view/view.php @@ -4,30 +4,30 @@ $this->incView('include/page-top', false);

data->html('title'); ?>

- + - + - + data->isEmpty('note')) { ?> - + - * @since 0.1 - * @copyright GNU Lesser General Public License (LGPL) version 3 - */ - -$GLOBALS['config']['lang']['specialchars'] = 2; \ No newline at end of file diff --git a/asset/lang/en/core.php b/asset/lang/en/core.php deleted file mode 100644 index e69de29..0000000 diff --git a/asset/lang/en/freak.php b/asset/lang/en/freak.php deleted file mode 100644 index e69de29..0000000 diff --git a/lib/class/front.php b/lib/class/front.php index 9fbbd76..231fb03 100644 --- a/lib/class/front.php +++ b/lib/class/front.php @@ -4,7 +4,7 @@ * * @package tzn_core_classes * @author Stan Ozier - * @version 0.3 + * @version 0.4 * @copyright GNU Lesser General Public License (LGPL) version 3 */ @@ -154,6 +154,7 @@ class FrontController extends HelpableSingleton { */ public function loadUserSettings() { // might overload default controller and action + // and language // -TODO- if ($this->user->isLoggedIn()) { $this->setSessionDefault('usertask', $this->user->getUid()); @@ -179,6 +180,8 @@ class FrontController extends HelpableSingleton { */ public function initTranslator() { $this->addHelper('translator'); + $this->loadLangConfig(); + $this->loadLangFilesFromConfig(); } /** diff --git a/lib/class/model.php b/lib/class/model.php index 09d6188..6cbb250 100644 --- a/lib/class/model.php +++ b/lib/class/model.php @@ -4,7 +4,7 @@ * * @package tzn_core_classes * @author Stan Ozier - * @version 0.3 + * @version 0.4 * @copyright GNU Lesser General Public License (LGPL) version 3 */ @@ -692,7 +692,7 @@ class VarDte extends VarAbstract if ($t = self::strToUnix($val)) { return strftime(APP_DATE_SQL, $t); } - $info['error'] = 'model_date_invalid'; + $info['error'] = 'invalid_date'; return false; } @@ -763,7 +763,7 @@ class VarDur extends VarAbstract } return $t; } else { - $info['error'] = 'model_time_invalid'; + $info['error'] = 'invalid_duration'; return false; } } @@ -830,7 +830,7 @@ class VarTim extends VarDur // now make GMT return $t - self::getUserTimeZoneOffset(); } - $info['error'] = 'model_time_invalid'; + $info['error'] = 'invalid_time'; return false; } @@ -886,7 +886,7 @@ class VarDtm extends VarAbstract // return datetime in SQL format return $d.' '.VarDur::workout($t); } - $info['error'] = 'model_datetime_invalid'; + $info['error'] = 'invalid_datetime'; return false; } @@ -983,7 +983,7 @@ class VarStr extends VarAbstract } switch ($GLOBALS['config']['lang']['specialchars']) { case 3: - $val = htmlentities($val); + $val = htmlentities(utf8_decode($val)); break; case 2: $val = htmlspecialchars($val); @@ -1007,20 +1007,19 @@ class VarUsr extends VarAbstract { public static function sanitize($val, &$info) { if (!$val && in_array('compulsory', $info)) { - $info['error'] = 'user_name_invalid'; + $info['error'] = 'username_invalid'; return false; } if ((strlen($val) < APP_USER_NAME_MIN) || (strlen($val) > APP_USER_NAME_MAX)) { - $info['error'] = 'user_name_length'; + $info['error'] = 'username_length'; return false; } else if (preg_match(APP_USER_SANITIZE, $val)) { return $val; } else { - $info['error'] = 'user_name_invalid'; + $info['error'] = 'username_invalid'; return false; } - return $val; } public static function value($val) { @@ -1043,15 +1042,21 @@ class VarPss extends VarAbstract return true; } } - if (preg_match(APP_PASSWORD_SANITIZE, $val)) { + return $val; + } + + public static function checkValid($val, &$info) { + if ((strlen($val) < APP_USER_PASS_MIN) + || (strlen($val) > APP_USER_PASS_MAX)) { + $info['error'] = 'password_length'; + return false; + } else if (preg_match(APP_PASSWORD_SANITIZE, $val)) { return $val; } else { $info['error'] = 'password_invalid'; return false; } - return $val; } - } /** @@ -1144,6 +1149,7 @@ class VarXml extends VarAbstract /** * URL Variable - URL Address * @since 0.1 + * @todo check if URL is valid */ class VarUrl extends VarAbstract { @@ -1176,7 +1182,7 @@ class VarEml extends VarAbstract if (empty($val) || preg_match("/^[a-z0-9]([a-z0-9_\-\.\+]*)@([a-z0-9_\-\.]*)\.([a-z]{2,4})$/i",$val)) { return $val; } else { - $info['error'] = 'model_email_invalid'; // -TODO-TRANSLATE- + $info['error'] = 'invalid_email'; return ''; } } diff --git a/lib/helper/auth.php b/lib/helper/auth.php index bef4511..d031433 100644 --- a/lib/helper/auth.php +++ b/lib/helper/auth.php @@ -4,7 +4,7 @@ * * @package tzn_helpers * @author Stan Ozier - * @version 0.2 + * @version 0.4 * @since 0.1 * @copyright GNU Lesser General Public License (LGPL) version 3 */ @@ -40,7 +40,7 @@ class AuthHelper extends Helper { } if (crypt($password, $salt) != $pass) { // password invalid - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; } @@ -49,7 +49,7 @@ class AuthHelper extends Helper { $sql = "ENCRYPT('$password','$salt')"; if (!self::checkDbPass($sql, $pass)) { // password not OK - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; // error or password mismatch } @@ -58,7 +58,7 @@ class AuthHelper extends Helper { $sql = "ENCODE('$password','$pass')"; if (!self::checkDbPass($sql, $pass)) { // password not OK - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; // error or password mismatch } @@ -70,7 +70,7 @@ class AuthHelper extends Helper { $sql = "MD5('$password')"; if (!self::checkDbPass($sql, $pass)) { // password not OK - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; // error or password mismatch } @@ -86,7 +86,7 @@ class AuthHelper extends Helper { break; } } - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; break; @@ -101,7 +101,7 @@ class AuthHelper extends Helper { { break; } - $this->error = 'user_pass_invalid'; + $this->error = 'password_invalid'; $this->badAccess(); return false; break; @@ -212,7 +212,7 @@ class AuthHelper extends Helper { public function login($username, $password, $activation=false) { $this->error = ''; if ($username == '') { - $this->error = 'user_name_empty'; + $this->error = 'username_required'; return false; } if (APP_AUTH_FIELD == 'username' && (!VarUsr::sanitize($username, $error))) { @@ -225,11 +225,13 @@ class AuthHelper extends Helper { if (!$this->obj->get('enabled')) { if (!$activation || $activation != $activ) { //Account Disabled - $this->error = 'user_disabled'; + $this->error = 'account_disabled'; + } else { + $this->error = 'account_not_active'; } } if (!$this->checkPassword($password)) { - $this->error = 'user_password_invalid'; + $this->error = 'password_invalid'; } else if ($activation && $activation == $activ) { // activate account $this->activateAccount(true); @@ -239,7 +241,7 @@ class AuthHelper extends Helper { return false; } } else { - $this->error = 'user_name_not_found'; + $this->error = 'username_not_found'; return false; } @@ -435,22 +437,20 @@ class AuthHelper extends Helper { if ($this->obj->get('salt') == "") { if (!$this->obj->loadByKey($key,$value)) { // user not found - $this->_error['forgot'] = $key." not found"; + $this->error = $key."_not_found"; return false; } } switch (APP_AUTH_PASSWORD_MODE) { case 1: - $this->generateNewSalt(); - $newpass = StringHelper::genRandom(6,"123456789"); - $this->obj->set('password', crypt($pass1 , $this->obj->get('salt'))); - $this->updatePassword(); - break; case 2: + case 4: + case 5: $this->generateNewSalt(); - $newpass = StringHelper::genRandom(6,"123456789"); - $this->obj->set('password', self::getDbPass("ENCRYPT(\"".$pass1."\",\"".$this->obj->get('salt')."\")")); - $this->updatePassword(); + $newpass = StringHelper::genRandom(6,"123456789"); + $this->obj->setRawPassword($newpass, $this->obj->get('salt')); + $this->updatePassword(); + return $newpass; break; case 3: $strSql = "SELECT DECODE(password, '".$this->obj->get('salt') @@ -458,29 +458,19 @@ class AuthHelper extends Helper { ." WHERE ".$this->obj->dbUid()."='".$this->obj->getUid()."'"; if ($rows = DbConnnector::query($strSql)) { if (!empty($rows[0])) { - $this->obj->password = $rows[0]->pass; - return $this->obj->password; + return $rows[0]->pass; } } - $this->_error['forgot'] = "can not decode?"; - return false; - break; - case 4: - case 5: - $this->generateNewSalt(); - $newpass = StringHelper::genRandom(6,"123456789"); - $this->password = "MD5('$newpass')"; - $this->updatePassword(); break; default: $iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES, MCRYPT_MODE_ECB), MCRYPT_RAND); - $this->password = mcrypt_decrypt (MCRYPT_3DES, $this->obj->get('salt'), + return mcrypt_decrypt (MCRYPT_3DES, $this->obj->get('salt'), $passBin, MCRYPT_MODE_ECB, $iv); - return $this->password; break; } - return $newpass; + $this->error = 'password_recover'; + return false; } public function getLoginCountry() { diff --git a/lib/helper/html_form.php b/lib/helper/html_form.php index 70144ca..7e1417c 100644 --- a/lib/helper/html_form.php +++ b/lib/helper/html_form.php @@ -94,7 +94,6 @@ class HtmlFormHelper extends Helper { /** * returns a field along with LABEL, all wrapped in a LI - * @todo make the wrapper optional * @todo missing types */ public function iFieldLabelled($key, $label='', $type='', $wrap='li') { @@ -144,7 +143,7 @@ class HtmlFormHelper extends Helper { return false; } if (empty($label)) { - $label = str_replace('_',' ',$key); // -TODO- translate + $label = str_replace('_',' ',$key); } return $this->_htmlWrapBegin($wrap) .'' @@ -314,6 +313,30 @@ class HtmlFormHelper extends Helper { return $str.''; } + /** + * generates a select (drop down) + */ + public function iSelectTranslate($key, $section, $options='') { + if (isset($this->obj)) { + $options = $this->obj->getPropertyOptions($key); + } + if (empty($options['options'])) { + FC::log_warn("iRadio $key does not provide options"); + return $key.' (no option)'; + } + $str = ''; + } + /** * generates a time zone drop down list */ diff --git a/lib/helper/translator.php b/lib/helper/translator.php index 743c7d7..bd04bf8 100644 --- a/lib/helper/translator.php +++ b/lib/helper/translator.php @@ -4,7 +4,7 @@ * * @package tzn_helpers * @author Stan Ozier - * @since 0.3 + * @version 0.4 * @copyright GNU Lesser General Public License (LGPL) version 3 */ @@ -12,6 +12,7 @@ * Translator Helper * * translates everything + * @since 0.3 * @todo test it all */ class TranslatorHelper { @@ -22,40 +23,98 @@ class TranslatorHelper { public function __construct() { $this->langDefault = $GLOBALS['config']['lang']['default']; $this->langUser = $GLOBALS['config']['lang']['user']; + $GLOBALS['lang'] = array(); } public function loadLangConfig() { - include_once(APP_LANGUAGE_PATH.$this->langDefault.'/config.php'); - include_once(APP_LANGUAGE_PATH.$this->langUser.'/config.php'); + if (file_exists(APP_LANGUAGE_PATH.$this->langUser.'/config.php')) { + include_once(APP_LANGUAGE_PATH.$this->langUser.'/config.php'); + } else { + include_once(APP_LANGUAGE_PATH.$this->langDefault.'/config.php'); + } + } + + public function loadLangFilesFromConfig() { + foreach($GLOBALS['config']['lang']['files'] as $file => $path) { + $full = $path.$this->langUser.'/'.$file; + if (file_exists($full)) { + include_once($full); + } else { + $full = $path.$this->langDefault.'/'.$file; + if (file_exists($full)) { + include_once($full); + } + } + } } public function loadLangFile($file) { - if (file_exists(APP_LANGUAGE_PATH.$this->langUser.'/'.$file.'.php')) { - include_once(APP_LANGUAGE_PATH.$this->langUser.'/'.$file.'.php'); + // try user language + foreach ($GLOBALS['config']['path']['lang'] as $path) { + if (file_exists(APP_INCLUDE_PATH.$path.$this->langUser.'/'.$file)) { + include_once(APP_INCLUDE_PATH.$path.$this->langUser.'/'.$file); + return true; + } } - if (file_exists(APP_LANGUAGE_PATH.$this->langDefault.'/'.$file.'.php')) { - include_once(APP_LANGUAGE_PATH.$this->langDefault.'/'.$file.'.php'); + // not found ? try default language + foreach ($GLOBALS['config']['path']['lang'] as $path) { + if (file_exists(APP_INCLUDE_PATH.$path.$this->langDefault.'/'.$file)) { + include_once(APP_INCLUDE_PATH.$path.$this->langDefault.'/'.$file); + return true; + } + } + return false; + } + + public static function getRawTranslation($section, $label, $field='') { + if (!array_key_exists($section, $GLOBALS['lang'])) { + FC::log_debug('can not find section '.$section); + return str_replace('_',' ',$label); + } + if (array_key_exists($label, $GLOBALS['lang'][$section])) { + if (is_array($GLOBALS['lang'][$section][$label])) { + return $GLOBALS['lang'][$section][$label][$field]; + } else { + return $GLOBALS['lang'][$section][$label]; + } + } else if (array_key_exists($label, $GLOBALS['lang'][$section])) { + if (is_array($GLOBALS['lang'][$section][$label])) { + return $GLOBALS['lang'][$section][$label][$field]; + } else { + return $GLOBALS['lang'][$section][$label]; + } + } else { + FC::log_debug('really can not find section '.$section); + return str_replace('_',' ',$label); } } - public function getTranslation($label, $section, $field='') { - if (!array_key_exists($section, $GLOBALS['lang'][$this->langDefault])) { - return $label; + public static function getTranslation($section, $label='', $field='') { + if (preg_match('/^\[([a-z_]+)\](.*)$/',$section, $matches)) { + $section = $matches[1]; + $label = $matches[2]; } - if (array_key_exists($label, $GLOBALS['lang'][$this->langUser][$section])) { - if (is_array($GLOBALS['lang'][$this->langUser][$section][$label])) { - return $GLOBALS['lang'][$this->langUser][$section][$label][$field]; - } else { - return $GLOBALS['lang'][$this->langUser][$section][$label]; - } - } else if (array_key_exists($label, $GLOBALS['lang'][$this->langDefault][$section])) { - if (is_array($GLOBALS['lang'][$this->langDefault][$section][$label])) { - return $GLOBALS['lang'][$this->langDefault][$section][$label][$field]; - } else { - return $GLOBALS['lang'][$this->langDefault][$section][$label]; - } - } else { - return $label; + $str = self::getRawTranslation($section, $label, $field); + if ($GLOBALS['config']['lang']['ucfirst']) { + return ucfirst($str); } + return $str; } + +} + +class TR extends TranslatorHelper { + + public static function get($section, $label, $field='') { + return self::getTranslation($section, $label, $field); + } + + public static function html($section, $label, $field='') { + return VarStr::html(self::getTranslation($section, $label, $field)); + } + + public static function phtml($section, $label, $field='') { + echo self::html($section, $label, $field); + } + } \ No newline at end of file diff --git a/lib/lang/en/common.php b/lib/lang/en/common.php new file mode 100644 index 0000000..cc34949 --- /dev/null +++ b/lib/lang/en/common.php @@ -0,0 +1,250 @@ + + * @version 0.4 + * @copyright GNU Lesser General Public License (LGPL) version 3 + */ + +$GLOBALS['lang']['data'] = array( + 'new' => 'new item', + 'read' => 'read this item', + 'view' => 'view details', + 'modify' => 'modify item', + 'delete' => 'delete this item', + 'delete_confirm' => 'really delete this item ?', + 'remove' => 'remove this item', + 'remove_confirm' => 'really remove from the list ?', + 'search' => 'search', + 'next' => 'next', + 'previous' => 'previous', + 'next_page' => 'next page', + 'previous_page' => 'previous page', + 'all' => 'all', + 'more' => 'more', + 'less' => 'less', + 'item_found' => 'item found', + 'items_found' => 'items found', + 'empty' => 'no data available' +); + +$GLOBALS['lang']['message'] = array( + 'saved' => 'data successfully saved', + 'created' => 'data successfully created', + 'updated' => 'data successfully updated', + 'deleted' => 'data successfully deleted', + 'removed' => 'data successfully removed' +); + +$GLOBALS['lang']['error'] = array( + 'db_no_connection' => 'can not connect to database', + 'db_no_database' => 'database not found', + 'db_sql_error' => 'database query error', + 'sql_injection' => 'possible SQL injection intended', + 'search_empty' => 'sorry, no item could be found', + 'not_found' => 'data not found', + 'login_failed' => 'login failed', + 'access_denied' => 'access denied', + 'data_denied' => 'access to data denied', + 'not_found_denied' => 'data not found or access denied', + 'action_failed' => 'requested action could not be performed', + 'form_error' => 'form contains error(s)', + 'compulsory_field' => 'information required', + 'account_disabled' => 'account is disabled', + 'account_expired' => 'account has expired', + 'account_not_found' => 'account does not exist', + 'username_required' => 'please enter your username', + 'username_not_found'=> 'username does not exists', + 'username_invalid' => 'not a valid username (avoid special characters or spaces)', + 'username_length' => 'username must have between '.APP_USER_NAME_MIN.' and '.APP_USER_NAME_MAX.' characters', + 'email_not_found' => 'email does not exists', + 'password_required' => 'password required', + 'password_invalid' => 'invalid password', + 'password_length' => 'password must have between '.APP_USER_PASS_MIN.' and '.APP_USER_PASS_MAX.' characters', + 'password_mismatch' => 'password and verification do not match', + 'password_recover' => 'password can not be recovered', + 'field_length' => 'too short or too long', + 'field_exists' => 'this entry already exists', + 'field_invalid' => 'entry is not valid', + 'field_mismatch' => 'entries do not match', + 'invalid_date' => 'not a valid date', + 'invalid_time' => 'not a valid time', + 'invalid_email' => 'e-mail address is not valid', + 'invalid_duration' => 'not a valid duration', + 'file_wrong_type' => 'wrong file type', + 'file_empty' => 'please select a file', + 'none_checked' => 'please check at least one item' +); + +$GLOBALS['lang']['security'] = array( + 'login' => 'login', + 'logout' => 'logout', + 'sign_in' => 'not a member? Sign in now', + 'my_account' => 'my account', + 'account' => 'account', + 'account_active' => 'account is activated', + 'account_not_active'=> 'account is not activated', + 'account_enabled' => 'account is enabled', + 'visit_count' => 'visits', + 'visit_fail_count' => 'failed login attempts', + 'access_denied' => 'access denied', + 'permission_denied' => 'permission denied', + 'session_expired' => 'your session has expired', + 'login_last_date' => 'Last login date', + 'login_last_address'=> 'Last login address' +); + +$GLOBALS['lang']['form'] = array( + 'compulsory' => 'compulsory', + 'username' => 'username', + 'password' => 'password', + 'password_confirm' => '(verification)', + 'auto_login' => 'remember me on this computer', + 'password_legend' => 'enter a password (and confirm) only if you want to change it.', + 'name' => 'name', + 'category' => 'category', + 'title' => 'title', + 'last_name' => 'last name', + 'middle_name' => 'middle name', + 'first_name' => 'first name', + 'nick_name' => 'nick name', + 'address' => 'address', + 'location' => 'location', + 'city' => 'city', + 'state' => 'state', + 'state_us_only' => 'for US members only', + 'country' => 'country', + 'time_zone' => 'time zone', + 'user_rights' => 'permissions', + 'email' => 'email', + 'subject' => 'subject', + 'body' => 'body', + 'comment' => 'comment', + 'in' => 'in', + 'out' => 'out', + 'from' => 'from', + 'to' => 'to', + 'cc' => 'cc', + 'url' => 'URL', + 'website' => 'website', + 'description' => 'description', + 'user' => 'user', + 'member' => 'member', + 'author' => 'author', + 'status' => 'status', + 'file' => 'file', + 'image' => 'image', + 'thumbnail' => 'thumbnail', + 'document' => 'document', + 'file_legend' => 'please select a file by clicking the \'Browse..\' button', + 'file_name' => 'filename', + 'file_size' => 'file size', + 'file_type' => 'file type', + 'date' => 'date', + 'deadline' => 'deadline', + 'start' => 'start', + 'stop' => 'stop', + 'publish_date' => 'publish', + 'post_date' => 'post', + 'creation_date' => 'date of creation', + 'last_change_date' => 'last update', + 'last_visit_date' => 'last visit', + 'last_visit_addr' => 'from', + 'posted_on' => 'posted on', + 'published on' => 'published on', + 'by' => 'by', + 'action' => 'action' +); + +// buttons +$GLOBALS['lang']['button'] = array( + 'add' => 'add', + 'create' => 'create', + 'edit' => 'edit', + 'submit' => 'submit', + 'login' => 'login', + 'save' => 'save', + 'save_changes' => 'save changes', + 'save_and_add' => 'save and add more', + 'save_and_close' => 'save and close', + 'update' => 'update', + 'cancel' => 'cancel changes', + 'close' => 'close', + 'reset' => 'reset form', + 'delete' => 'delete', + 'remove' => 'remove', + 'start' => 'start', + 'stop' => 'stop', + 'enable' => 'enable', + 'disable' => 'disable', + 'activate' => 'activate', + 'deactivate' => 'deactivate', + 'next_step' => 'next step', + 'previous_step' => 'previous step', + 'back' => 'go back', + 'back_to_list' => 'back to list' +); + +$GLOBALS['lang']['date'] = array( + 'future_pre' => 'in', // eg. "in" 2 days + 'future_app' => '', // ie. when keyword needs to be appended to the date + 'past_pre' => '', // eg. "il y a" 2 jours (french) + 'past_app' => 'ago', // eg. 2 days "ago" + 'yesterday' => 'yesterday', + 'today' => 'today', + 'tomorrow' => 'tomorrow', + 'days' => 'days', + 'day' => 'day', + 'weeks' => 'weeks', + 'week' => 'week', + 'months' => 'months', + 'month' => 'month', + 'years' => 'years', + 'year' => 'year', + 'hour' => 'hour', + 'hours' => 'hours', + 'minute' => 'minute', + 'minutes' => 'minutes', + 'second' => 'second', + 'seconds' => 'seconds', + 'january' => 'january', + 'february' => 'february', + 'march' => 'march', + 'april' => 'april', + 'may' => 'may', + 'june' => 'june', + 'july' => 'july', + 'august' => 'august', + 'september' => 'september', + 'october' => 'october', + 'november' => 'november', + 'december' => 'december', + 'jan' => 'jan', + 'feb' => 'feb', + 'mar' => 'mar', + 'apr' => 'apr', + 'may' => 'may', + 'jun' => 'jun', + 'jul' => 'jul', + 'aug' => 'aug', + 'sep' => 'sep', + 'oct' => 'oct', + 'nov' => 'nov', + 'dec' => 'dec', + 'monday' => 'monday', + 'tuesday' => 'tuesday', + 'wednesday' => 'wednesday', + 'thursday' => 'thursday', + 'friday' => 'friday', + 'saturday' => 'saturday', + 'sunday' => 'sunday', + 'mon' => 'mon', + 'tue' => 'tue', + 'wed' => 'wed', + 'thu' => 'thu', + 'fri' => 'fri', + 'sat' => 'sat', + 'sun' => 'sun' +); \ No newline at end of file diff --git a/lib/lang/en/config.php b/lib/lang/en/config.php new file mode 100644 index 0000000..ce81ec3 --- /dev/null +++ b/lib/lang/en/config.php @@ -0,0 +1,15 @@ + + * @version 0.4 + * @copyright GNU Lesser General Public License (LGPL) version 3 + */ + + +$GLOBALS['config']['lang']['specialchars'] = 2; +$GLOBALS['config']['lang']['ucfirst'] = false; + +setLocale(LC_ALL, 'en_EN.UTF-8', 'en_GB.utf8', 'en_US.utf8', 'en_EN', 'en'); \ No newline at end of file diff --git a/lib/lang/fr/common.php b/lib/lang/fr/common.php new file mode 100644 index 0000000..d2858a4 --- /dev/null +++ b/lib/lang/fr/common.php @@ -0,0 +1,250 @@ + + * @version 0.4 + * @copyright GNU Lesser General Public License (LGPL) version 3 + */ + +$GLOBALS['lang']['data'] = array( + 'new' => 'nouvel élément', + 'read' => 'lire la suite', + 'view' => 'voire les détails', + 'modify' => 'modifier', + 'delete' => 'supprimer', + 'delete_confirm' => 'réellemment supprimer cet élément ?', + 'remove' => 'retirer cet élément', + 'remove_confirm' => 'réellemment retirer cet élément ?', + 'search' => 'chercher', + 'next' => 'suivant', + 'previous' => 'précédent', + 'next_page' => 'page suivante', + 'previous_page' => 'page précédente', + 'all' => 'tous', + 'more' => 'plus', + 'less' => 'moins', + 'item_found' => 'élément trouvé', + 'items_found' => 'éléments trouvés', + 'empty' => 'aucune donnée trouvée' +); + +$GLOBALS['lang']['message'] = array( + 'saved' => 'données enregistrées avec succès', + 'created' => 'données créées avec succès', + 'updated' => 'données mises à jour', + 'deleted' => 'données supprimées avec succès', + 'removed' => 'éléments retirés' +); + +$GLOBALS['lang']['error'] = array( + 'db_no_connection' => 'impossible de se connecter à la base de données', + 'db_no_database' => 'base de données introuvable', + 'db_sql_error' => 'échec de la requete SQL', + 'sql_injection' => 'possibilité SQL injection intended', + 'search_empty' => 'aucun élément trouvé', + 'not_found' => 'données introuvable', + 'login_failed' => 'echec de l\'identification', + 'access_denied' => 'accès interdit', + 'data_denied' => 'accès refusé', + 'not_found_denied' => 'données non trouvées ou accès refusé', + 'action_failed' => 'echec de la commande', + 'form_error' => 'le formulaire content des erreurs', + 'compulsory_field' => 'donnée obilgatoire', + 'account_disabled' => 'compte désactivé', + 'account_expired' => 'le compte a expiré', + 'account_not_found' => 'compte introuvable', + 'username_required' => 'veuillez saisir un nom d\'utilisateur', + 'username_not_found'=> 'nom utilisateur introuvable', + 'username_invalid' => 'nom utilisateur non valide (éviter espaces et caractères spéciaux)', + 'username_length' => 'le nom doit avoir entre '.APP_USER_NAME_MIN.' et '.APP_USER_NAME_MAX.' caractères', + 'email_not_found' => 'courriel introuvable', + 'password_required' => 'mot de passe requis', + 'password_invalid' => 'mauvais mot de passe', + 'password_length' => 'le mot de passe doit avoir entre '.APP_USER_PASS_MIN.' et '.APP_USER_PASS_MAX.' caractères', + 'password_mismatch' => 'le mot de passe ne correspond pas', + 'password_recover' => 'impossible de récuperer le mot de passe', + 'field_length' => 'trop court ou trop long', + 'field_exists' => 'un entrée identique existe déjà', + 'field_invalid' => 'donnée non valide', + 'field_mismatch' => 'les données ne correspondent pas', + 'invalid_date' => 'date non valide', + 'invalid_time' => 'heure non valide', + 'invalid_email' => 'adresse non valide', + 'invalid_duration' => 'durée non valide', + 'file_wrong_type' => 'mauvais type de fichier', + 'file_empty' => 'veuillez sélectionner un fichier', + 'none_checked' => 'veuillez sélectionner au moins un élément' +); + +$GLOBALS['lang']['security'] = array( + 'login' => 'connexion', + 'logout' => 'déconnexion', + 'sign_in' => 'pas encore membre? cliquez ici', + 'my_account' => 'mon compte', + 'account' => 'compte', + 'account_active' => 'compte activé', + 'account_not_active'=> 'compte désactivé', + 'account_enabled' => 'compte activé', + 'visit_count' => 'visites', + 'visit_fail_count' => 'echecs de connexion', + 'access_denied' => 'accès refusé', + 'permission_denied' => 'permission refusée', + 'session_expired' => 'votre session a expiré', + 'login_last_date' => 'date dernière connexion', + 'login_last_address'=> 'adresse dernière connexion' +); + +$GLOBALS['lang']['form'] = array( + 'compulsory' => 'requis', + 'username' => 'utilisateur', + 'password' => 'mot de passe', + 'password_confirm' => '(vérification)', + 'auto_login' => 'm\'identifier automatiquement depuis cet ordinateur', + 'password_legend' => 'saisir un mot de passe uniquement pour en changer.', + 'name' => 'nom', + 'category' => 'catégorie', + 'title' => 'titre', + 'last_name' => 'nom de famille', + 'middle_name' => '', + 'first_name' => 'prénom', + 'nick_name' => 'surnom', + 'address' => 'adresse', + 'location' => 'lieu', + 'city' => 'ville', + 'state' => 'état', + 'state_us_only' => 'pour les USA uniquement', + 'country' => 'pays', + 'time_zone' => 'fuseau horaire', + 'user_rights' => 'permissions', + 'email' => 'courriel', + 'subject' => 'sujet', + 'body' => 'message', + 'comment' => 'commentaire', + 'in' => 'entrant', + 'out' => 'sortant', + 'from' => 'expéditeur', + 'to' => 'destinatire', + 'cc' => 'copie à', + 'url' => 'URL', + 'website' => 'site internet', + 'description' => 'description', + 'user' => 'utilisateur', + 'member' => 'membre', + 'author' => 'auteur', + 'status' => 'état', + 'file' => 'fichier', + 'image' => 'image', + 'thumbnail' => 'aperçu', + 'document' => 'document', + 'file_legend' => 'veuillez choisir un fichier en cliquant sur \'Parcourir...\'', + 'file_name' => 'nom du fichier', + 'file_size' => 'taille du fichier', + 'file_type' => 'type du fichier', + 'date' => 'date', + 'deadline' => 'échéance', + 'start' => 'début', + 'stop' => 'fin', + 'publish_date' => 'publication', + 'post_date' => 'envoi', + 'creation_date' => 'date de création', + 'last_change_date' => 'dernière mise à jour', + 'last_visit_date' => 'dernière visite', + 'last_visit_addr' => 'depuis', + 'posted_on' => 'envoyée le', + 'published on' => 'publiée le', + 'by' => 'par', + 'action' => 'action' +); + +// buttons +$GLOBALS['lang']['button'] = array( + 'add' => 'ajouter', + 'create' => 'créer', + 'edit' => 'modifier', + 'submit' => 'soumettre', + 'login' => 'indentifier', + 'save' => 'enregistrer', + 'save_changes' => 'enregistrer les modifications', + 'save_and_add' => 'enregistrer et créer à nouveau', + 'save_and_close' => 'enregistrer et fermer', + 'update' => 'mettre à jour', + 'cancel' => 'annuler', + 'close' => 'fermer', + 'reset' => 'réinitialiser', + 'delete' => 'supprimer', + 'remove' => 'retirer', + 'start' => 'démarrer', + 'stop' => 'arrêter', + 'enable' => 'activer', + 'disable' => 'désactiver', + 'activate' => 'activer', + 'deactivate' => 'désactiver', + 'next_step' => 'étape suivante', + 'previous_step' => 'étape précédente', + 'back' => 'revenir', + 'back_to_list' => 'revenir en arrière' +); + +$GLOBALS['lang']['date'] = array( + 'future_pre' => 'dans', // eg. "in" 2 days + 'future_app' => '', // ie. when keyword needs to be appended to the date + 'past_pre' => 'il y a', // eg. "il y a" 2 jours (french) + 'past_app' => '', // eg. 2 days "ago" + 'yesterday' => 'hier', + 'today' => 'aujourd\'hui', + 'tomorrow' => 'demain', + 'days' => 'jours', + 'day' => 'jour', + 'weeks' => 'semaines', + 'week' => 'semaine', + 'months' => 'mois', + 'month' => 'mois', + 'years' => 'années', + 'year' => 'année', + 'hour' => 'heure', + 'hours' => 'heures', + 'minute' => 'minute', + 'minutes' => 'minutes', + 'second' => 'seconde', + 'seconds' => 'secondes', + 'january' => 'janvier', + 'february' => 'février', + 'march' => 'mars', + 'april' => 'avril', + 'may' => 'mai', + 'june' => 'juin', + 'july' => 'juillet', + 'august' => 'août', + 'september' => 'septembre', + 'october' => 'octobre', + 'november' => 'novembre', + 'december' => 'décembre', + 'jan' => 'jan', + 'feb' => 'fev', + 'mar' => 'mar', + 'apr' => 'avr', + 'may' => 'mai', + 'jun' => 'juin', + 'jul' => 'juil', + 'aug' => 'aout', + 'sep' => 'sep', + 'oct' => 'oct', + 'nov' => 'nov', + 'dec' => 'dec', + 'monday' => 'lundi', + 'tuesday' => 'mardi', + 'wednesday' => 'mercredi', + 'thursday' => 'jeudi', + 'friday' => 'vendredi', + 'saturday' => 'samedi', + 'sunday' => 'dimanche', + 'mon' => 'lun', + 'tue' => 'mar', + 'wed' => 'mer', + 'thu' => 'jeu', + 'fri' => 'ven', + 'sat' => 'sam', + 'sun' => 'dim' +); \ No newline at end of file diff --git a/lib/lang/fr/config.php b/lib/lang/fr/config.php new file mode 100644 index 0000000..93514c9 --- /dev/null +++ b/lib/lang/fr/config.php @@ -0,0 +1,15 @@ + + * @version 0.4 + * @copyright GNU Lesser General Public License (LGPL) version 3 + */ + + +$GLOBALS['config']['lang']['specialchars'] = 3; +$GLOBALS['config']['lang']['ucfirst'] = false; + +setLocale(LC_ALL, 'fr_FR.UTF-8', 'fr_FR', 'fr'); \ No newline at end of file diff --git a/lib/model/user.php b/lib/model/user.php index d31cf72..97e3924 100644 --- a/lib/model/user.php +++ b/lib/model/user.php @@ -4,7 +4,7 @@ * * @package tzn_models * @author Stan Ozier - * @version 0.2 + * @version 0.4 * @since 0.1 * @copyright GNU Lesser General Public License (LGPL) version 3 */ @@ -86,38 +86,18 @@ abstract class UserModel extends Model { 'abcdefghijklmnopqrstuvwxyz' .'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')); if ($pass1) { - if ((strlen($pass1) >= APP_USER_PASS_MIN) - && (strlen($pass1) <= APP_USER_PASS_MAX)) + $arr = explode(',',$this->_properties[$key]); + $class = array_shift($arr); + if (VarPss::checkValid($pass1, $arr)) { - $salt = $this->get('salt'); + $this->setRawPassword($pass1, $this->get('salt')); - switch (APP_AUTH_PASSWORD_MODE) { - case 1: - $this->set('password',crypt($pass1 , $salt)); - break; - case 2: - $this->set('password',AuthHelper::getDbPass("ENCRYPT('$pass1','$salt')")); - break; - case 3: - $this->set('password',AuthHelper::getDbPass("ENCODE('$pass1','$salt')")); - break; - case 4: - case 5: - $this->set('password',AuthHelper::getDbPass("MD5('$pass1')")); - break; - default: - $iv = mcrypt_create_iv (mcrypt_get_iv_size(MCRYPT_3DES - , MCRYPT_MODE_ECB), MCRYPT_RAND); - $crypttext = mcrypt_encrypt(APP_AUTH_PASSWORD_MODE, $salt - , $pass1, MCRYPT_MODE_ECB, $iv); - $this->set('password',bin2hex($crypttext)); - } } else { $this->_error['password'] = 'user_pass_length'; return false; } } else { - $this->set('password',''); + $this->data['password'] = ''; } return true; } else { @@ -129,6 +109,31 @@ abstract class UserModel extends Model { } } + public function setRawPassword($pass, $salt) { + switch (APP_AUTH_PASSWORD_MODE) { + case 1: + $this->data['password'] = crypt($pass , $salt); + break; + case 2: + $this->data['password'] = AuthHelper::getDbPass("ENCRYPT('$pass','$salt')"); + break; + case 3: + $this->data['password'] = AuthHelper::getDbPass("ENCODE('$pass','$salt')"); + break; + case 4: + case 5: + $this->data['password'] = AuthHelper::getDbPass("MD5('$pass')"); + break; + default: + $iv = mcrypt_create_iv (mcrypt_get_iv_size(MCRYPT_3DES + , MCRYPT_MODE_ECB), MCRYPT_RAND); + $crypttext = mcrypt_encrypt(APP_AUTH_PASSWORD_MODE, $salt + , $pass, MCRYPT_MODE_ECB, $iv); + $this->data['password'] = bin2hex($crypttext); + break; + } + } + public function setupTimeZone() { if (!$this->isEmpty('time_zone')) { try { diff --git a/skin/default/css/freak.css b/skin/default/css/freak.css index 1a2538f..094ed76 100644 --- a/skin/default/css/freak.css +++ b/skin/default/css/freak.css @@ -113,31 +113,64 @@ img.frgt { text-align: right; width: 150px; } -#dtop ul { - padding: 12px 0 0 0; - height: 28px; -} -#dtop ul li { - float: left; - list-style: none; - margin-right: 8px; - padding: 0 0 8px 10px; - height: 20px; -} -#dtop ul li.active { - background: url(../img/top-tab.png) no-repeat left 0; -} -#dtop ul li a { - display: block; - color: #fff; +#dtop #duser p a { text-decoration: none; - padding: 6px 10px 0 0; } -#dtop ul li a:hover { +#dtop #duser p a:hover { + color: #fff; } -#dtop ul li.active a { +#dtop #duser p a small { + color: #9cf; +} +#dtop #duser p a:hover small { + color: #cce3ff; +} +#dtop #duser ul { + top: 20px; + background-color: #ccc; + border: 1px solid #999; + margin: 0; + padding: 0; + position: absolute; + right: 5px; + min-width: 150px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -webkit-border-top-right-radius: 0; + -moz-border-radius-topright: 0; + border-radius: 5px 0 5px 5px; +} +#dtop #duser ul#dmenu { + display: none; +} +#dtop #duser ul li { + font-size: 11px; + list-style: none; + padding: 0; + text-align: left; +} +#dtop #duser ul li a { + color: #333; + display: block; + text-decoration: none; + padding: 2px 4px; +} +#dtop #duser ul li:first-child a { + -webkit-border-top-left-radius: 5px; + -moz-border-radius-topleft: 5px; + border-radius: 5px 0 0 0; +} +#dtop #duser ul li:last-child a { + -webkit-border-bottom-left-radius: 5px; + -webkit-border-bottom-right-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -moz-border-radius-bottomright: 5px; + border-radius: 0 0 5px 5px; +} +#dtop #duser ul li a:hover { + background-color: #fff; color: #000; - background: url(../img/top-tab.png) no-repeat right 0; } /* search form */ form#search p { diff --git a/skin/default/css/tracker.css b/skin/default/css/tracker.css index a0ec4a9..b50c7de 100644 --- a/skin/default/css/tracker.css +++ b/skin/default/css/tracker.css @@ -3,9 +3,9 @@ position: absolute; top: 0; left: 50%; - margin-left: -250px; + margin-left: -220px; padding: 6px 10px; - width: 500px; + width: 440px; color: #036; background-color: transparent; z-index: 10; @@ -40,7 +40,7 @@ } #drun p input { color: #036; - width: 300px; + width: 340px; border: 0; padding: 2px 5px 3px; background-color: #39c; @@ -66,9 +66,15 @@ float: right; } #drun button { - opacity: 0.5; - -moz-opacity: 0.5; - filter: alpha(opacity=50); + opacity: 0.85; + -moz-opacity: 0.85; + filter: alpha(opacity=85); + background: url(../img/buttons.png) no-repeat 0 0; + width: 34px; + height: 22px; + text-indent: -9999px; + overflow: hidden; + border: 0 none; } #drun button:hover, #drun button:focus { opacity: 1; @@ -76,6 +82,24 @@ filter: alpha(opacity=100); outline: 0 none; } +#drun button#b_save { + +} +#drun button#b_start { + background-position: -40px 0; +} +#drun button#b_resume { + background-position: -80px 0; +} +#drun button#b_pause { + background-position: -120px 0; +} +#drun button#b_stop { + background-position: -160px 0; +} +#drun button#b_close { + background-position: -200px 0; +} #timerstatus.loading { background: url(../img/barloader.gif) no-repeat center center; } diff --git a/skin/default/img/buttons.png b/skin/default/img/buttons.png new file mode 100644 index 0000000..091dbdf Binary files /dev/null and b/skin/default/img/buttons.png differ
deadline data->htmlDeadline(); ?>
priority data->htmlPriority(); ?>
status data->htmlStatus(); ?>
note data->html('note'); ?>