diff options
Diffstat (limited to 'inc')
67 files changed, 1227 insertions, 645 deletions
diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php index 13be479cc..080fb4778 100644 --- a/inc/PassHash.class.php +++ b/inc/PassHash.class.php @@ -4,7 +4,7 @@ * * This class implements various mechanisms used to hash passwords * - * @author Andreas Gohr <andi@splitbrain.org> + * @author Andreas Gohr <andi@splitbrain.org> * @license LGPL2 */ class PassHash { @@ -58,6 +58,12 @@ class PassHash { } elseif(substr($hash, 0, 6) == '{SMD5}') { $method = 'lsmd5'; $salt = substr(base64_decode(substr($hash, 6)), 16); + } elseif(preg_match('/^:B:(.+?):.{32}$/', $hash, $m)) { + $method = 'mediawiki'; + $salt = $m[1]; + } elseif(preg_match('/^\$6\$(.+?)\$/', $hash, $m)) { + $method = 'sha512'; + $salt = $m[1]; } elseif($len == 32) { $method = 'md5'; } elseif($len == 40) { @@ -101,14 +107,18 @@ class PassHash { * Initialize the passed variable with a salt if needed. * * If $salt is not null, the value is kept, but the lenght restriction is - * applied. + * applied (unless, $cut is false). * * @param string &$salt The salt, pass null if you want one generated - * @param int $len The length of the salt + * @param int $len The length of the salt + * @param bool $cut Apply length restriction to existing salt? */ - public function init_salt(&$salt, $len = 32) { - if(is_null($salt)) $salt = $this->gen_salt($len); - if(strlen($salt) > $len) $salt = substr($salt, 0, $len); + public function init_salt(&$salt, $len = 32, $cut = true) { + if(is_null($salt)) { + $salt = $this->gen_salt($len); + $cut = true; // for new hashes we alway apply length restriction + } + if(strlen($salt) > $len && $cut) $salt = substr($salt, 0, $len); } // Password hashing methods follow below @@ -263,7 +273,7 @@ class PassHash { * * This method was used by old MySQL systems * - * @link http://www.php.net/mysql + * @link http://www.php.net/mysql * @author <soren at byu dot edu> * @param string $clear The clear text to hash * @return string Hashed password @@ -327,9 +337,9 @@ class PassHash { * an exception. * * @link http://www.openwall.com/phpass/ - * @param string $clear The clear text to hash - * @param string $salt The salt to use, null for random - * @param string $magic The hash identifier (P or H) + * @param string $clear The clear text to hash + * @param string $salt The salt to use, null for random + * @param string $magic The hash identifier (P or H) * @param int $compute The iteration count for new passwords * @throws Exception * @return string Hashed password @@ -430,8 +440,8 @@ class PassHash { * will break. When no salt is given, the iteration count can be set * through the $compute variable. * - * @param string $clear The clear text to hash - * @param string $salt The salt to use, null for random + * @param string $clear The clear text to hash + * @param string $salt The salt to use, null for random * @param int $compute The iteration count (between 4 and 31) * @throws Exception * @return string Hashed password @@ -450,4 +460,38 @@ class PassHash { return crypt($clear, $salt); } + /** + * Password hashing method SHA512 + * + * This is only supported on PHP 5.3.2 or higher and will throw an exception if + * the needed crypt support is not available + * + * @param string $clear The clear text to hash + * @param string $salt The salt to use, null for random + * @return string Hashed password + * @throws Exception + */ + public function hash_sha512($clear, $salt = null) { + if(!defined('CRYPT_SHA512') || CRYPT_SHA512 != 1) { + throw new Exception('This PHP installation has no SHA512 support'); + } + $this->init_salt($salt, 8, false); + return crypt($clear, '$6$'.$salt.'$'); + } + + /** + * Password hashing method 'mediawiki' + * + * Uses salted MD5, this is referred to as Method B in MediaWiki docs. Unsalted md5 + * method 'A' is not supported. + * + * @link http://www.mediawiki.org/wiki/Manual_talk:User_table#user_password_column + * @param string $clear The clear text to hash + * @param string $salt The salt to use, null for random + * @return string Hashed password + */ + public function hash_mediawiki($clear, $salt = null) { + $this->init_salt($salt, 8, false); + return ':B:'.$salt.':'.md5($salt.'-'.md5($clear)); + } } diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php index c04a14f5c..81b211ec8 100644 --- a/inc/RemoteAPICore.php +++ b/inc/RemoteAPICore.php @@ -3,7 +3,7 @@ /** * Increased whenever the API is changed */ -define('DOKU_API_VERSION', 7); +define('DOKU_API_VERSION', 8); class RemoteAPICore { @@ -344,6 +344,8 @@ class RemoteAPICore { for($i=0; $i<$len; $i++) { unset($data[$i]['meta']); + $data[$i]['perms'] = $data[$i]['perm']; + unset($data[$i]['perm']); $data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']); } return $data; @@ -654,7 +656,9 @@ class RemoteAPICore { if(count($revisions)>0 && $first==0) { array_unshift($revisions, ''); // include current revision - array_pop($revisions); // remove extra log entry + if ( count($revisions) > $conf['recent'] ){ + array_pop($revisions); // remove extra log entry + } } if(count($revisions) > $conf['recent']) { diff --git a/inc/Tar.class.php b/inc/Tar.class.php index 59e14c705..20f397395 100644 --- a/inc/Tar.class.php +++ b/inc/Tar.class.php @@ -17,7 +17,7 @@ * * $tar = new Tar(); * $tar->open('myfile.tgz'); - * $tar->extract(/tmp); + * $tar->extract('/tmp'); * * To create a new TAR archive directly on the filesystem (low memory requirements), create() it, * add*() files and close() it: @@ -81,7 +81,7 @@ class Tar { $this->fh = @fopen($this->file, 'rb'); } - if(!$this->fh) throw(new TarIOException('Could not open file for reading: '.$this->file)); + if(!$this->fh) throw new TarIOException('Could not open file for reading: '.$this->file); $this->closed = false; } @@ -107,9 +107,9 @@ class Tar { * Reopen the file with open() again if you want to do additional operations */ public function contents() { - if($this->closed || !$this->file) throw(new TarIOException('Can not read from a closed archive')); + if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive'); - $result = Array(); + $result = array(); while($read = $this->readbytes(512)) { $header = $this->parseHeader($read); if(!is_array($header)) continue; @@ -148,7 +148,7 @@ class Tar { * @return array */ function extract($outdir, $strip = '', $exclude = '', $include = '') { - if($this->closed || !$this->file) throw(new TarIOException('Can not read from a closed archive')); + if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive'); $outdir = rtrim($outdir, '/'); io_mkdir_p($outdir); @@ -207,7 +207,7 @@ class Tar { // is this a file? if(!$header['typeflag']) { $fp = fopen($output, "wb"); - if(!$fp) throw(new TarIOException('Could not open file for writing: '.$output)); + if(!$fp) throw new TarIOException('Could not open file for writing: '.$output); $size = floor($header['size'] / 512); for($i = 0; $i < $size; $i++) { @@ -260,7 +260,7 @@ class Tar { $this->fh = @fopen($this->file, 'wb'); } - if(!$this->fh) throw(new TarIOException('Could not open file for writing: '.$this->file)); + if(!$this->fh) throw new TarIOException('Could not open file for writing: '.$this->file); } $this->writeaccess = false; $this->closed = false; @@ -275,13 +275,13 @@ class Tar { * @throws TarIOException */ public function addFile($file, $name = '') { - if($this->closed) throw(new TarIOException('Archive has been closed, files can no longer be added')); + if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added'); if(!$name) $name = $file; $name = $this->cleanPath($name); $fp = fopen($file, 'rb'); - if(!$fp) throw(new TarIOException('Could not open file for reading: '.$file)); + if(!$fp) throw new TarIOException('Could not open file for reading: '.$file); // create file header and copy all stat info from the original file clearstatcache(false, $file); @@ -314,7 +314,7 @@ class Tar { * @throws TarIOException */ public function addData($name, $data, $uid = 0, $gid = 0, $perm = 0666, $mtime = 0) { - if($this->closed) throw(new TarIOException('Archive has been closed, files can no longer be added')); + if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added'); $name = $this->cleanPath($name); $len = strlen($data); @@ -401,7 +401,7 @@ class Tar { if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->filetype($file); if(!file_put_contents($file, $this->getArchive($comptype, $complevel))) { - throw(new TarIOException('Could not write to file: '.$file)); + throw new TarIOException('Could not write to file: '.$file); } } @@ -439,14 +439,14 @@ class Tar { } else { $written = @fwrite($this->fh, $data); } - if($written === false) throw(new TarIOException('Failed to write to archive stream')); + if($written === false) throw new TarIOException('Failed to write to archive stream'); return $written; } /** * Skip forward in the open file pointer * - * This is basically a wrapper around seek() (and a workarounf for bzip2) + * This is basically a wrapper around seek() (and a workaround for bzip2) * * @param int $bytes seek to this position */ @@ -494,11 +494,11 @@ class Tar { } // values are needed in octal - $uid = sprintf("%6s ", DecOct($uid)); - $gid = sprintf("%6s ", DecOct($gid)); - $perm = sprintf("%6s ", DecOct($perm)); - $size = sprintf("%11s ", DecOct($size)); - $mtime = sprintf("%11s", DecOct($mtime)); + $uid = sprintf("%6s ", decoct($uid)); + $gid = sprintf("%6s ", decoct($gid)); + $perm = sprintf("%6s ", decoct($perm)); + $size = sprintf("%11s ", decoct($size)); + $mtime = sprintf("%11s", decoct($mtime)); $data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime); $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, ""); @@ -511,7 +511,7 @@ class Tar { $this->writebytes($data_first); - $chks = pack("a8", sprintf("%6s ", DecOct($chks))); + $chks = pack("a8", sprintf("%6s ", decoct($chks))); $this->writebytes($chks.$data_last); } @@ -598,11 +598,11 @@ class Tar { */ protected function compressioncheck($comptype) { if($comptype === Tar::COMPRESS_GZIP && !function_exists('gzopen')) { - throw(new TarIllegalCompressionException('No gzip support available')); + throw new TarIllegalCompressionException('No gzip support available'); } if($comptype === Tar::COMPRESS_BZIP && !function_exists('bzopen')) { - throw(new TarIllegalCompressionException('No bzip2 support available')); + throw new TarIllegalCompressionException('No bzip2 support available'); } } @@ -631,4 +631,4 @@ class TarIOException extends Exception { } class TarIllegalCompressionException extends Exception { -}
\ No newline at end of file +} diff --git a/inc/actions.php b/inc/actions.php index f65b47451..4083b0454 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -711,21 +711,28 @@ function act_subscription($act){ $target = $params['target']; $style = $params['style']; - $data = $params['data']; $action = $params['action']; // Perform action. - if (!subscription_set($_SERVER['REMOTE_USER'], $target, $style, $data)) { + $sub = new Subscription(); + if($action == 'unsubscribe'){ + $ok = $sub->remove($target, $_SERVER['REMOTE_USER'], $style); + }else{ + $ok = $sub->add($target, $_SERVER['REMOTE_USER'], $style); + } + + if($ok) { + msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']), + prettyprint_id($target)), 1); + act_redirect($ID, $act); + } else { throw new Exception(sprintf($lang["subscr_{$action}_error"], hsc($INFO['userinfo']['name']), prettyprint_id($target))); } - msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']), - prettyprint_id($target)), 1); - act_redirect($ID, $act); // Assure that we have valid data if act_redirect somehow fails. - $INFO['subscribed'] = get_info_subscribed(); + $INFO['subscribed'] = $sub->user_subscription(); return 'show'; } @@ -777,8 +784,7 @@ function subscription_handle_post(&$params) { $style = null; } - $data = in_array($style, array('list', 'digest')) ? time() : null; - $params = compact('target', 'style', 'data', 'action'); + $params = compact('target', 'style', 'action'); } //Setup VIM: ex: et ts=2 : diff --git a/inc/auth.php b/inc/auth.php index c68a699fe..c4f1dcf2b 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -780,23 +780,19 @@ function register() { return false; } - // create substitutions for use in notification email - $substitutions = array( - 'NEWUSER' => $login, - 'NEWNAME' => $fullname, - 'NEWEMAIL' => $email, - ); + // send notification about the new user + $subscription = new Subscription(); + $subscription->send_register($login, $fullname, $email); + // are we done? if(!$conf['autopasswd']) { msg($lang['regsuccess2'], 1); - notify('', 'register', '', $login, false, $substitutions); return true; } - // autogenerated password? then send him the password + // autogenerated password? then send password to user if(auth_sendPassword($login, $pass)) { msg($lang['regsuccess'], 1); - notify('', 'register', '', $login, false, $substitutions); return true; } else { msg($lang['regmailfail'], -1); diff --git a/inc/changelog.php b/inc/changelog.php index 688aebfd6..9768fea51 100644 --- a/inc/changelog.php +++ b/inc/changelog.php @@ -258,6 +258,7 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){ } else { $lines = @file($conf['changelog']); } + if(!$lines) return $recent; // we start searching at the end of the list $lines = array_reverse($lines); diff --git a/inc/common.php b/inc/common.php index 3c40a47dc..bc49e76b2 100644 --- a/inc/common.php +++ b/inc/common.php @@ -107,9 +107,11 @@ function pageinfo() { $info['isadmin'] = false; $info['ismanager'] = false; if(isset($_SERVER['REMOTE_USER'])) { + $sub = new Subscription(); + $info['userinfo'] = $USERINFO; $info['perm'] = auth_quickaclcheck($ID); - $info['subscribed'] = get_info_subscribed(); + $info['subscribed'] = $sub->user_subscription(); $info['client'] = $_SERVER['REMOTE_USER']; if($info['perm'] == AUTH_ADMIN) { @@ -320,15 +322,13 @@ function idfilter($id, $ue = true) { if($conf['useslash'] && $conf['userewrite']) { $id = strtr($id, ':', '/'); } elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && - $conf['userewrite'] && - strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') === false + $conf['userewrite'] ) { $id = strtr($id, ':', ';'); } if($ue) { $id = rawurlencode($id); $id = str_replace('%3A', ':', $id); //keep as colon - $id = str_replace('%3B', ';', $id); //keep as semicolon $id = str_replace('%2F', '/', $id); //keep as slash } return $id; @@ -1105,90 +1105,31 @@ function saveOldRevision($id) { * @author Andreas Gohr <andi@splitbrain.org> */ function notify($id, $who, $rev = '', $summary = '', $minor = false, $replace = array()) { - global $lang; global $conf; - global $INFO; - global $DIFF_INLINESTYLES; // decide if there is something to do, eg. whom to mail if($who == 'admin') { if(empty($conf['notify'])) return false; //notify enabled? - $text = rawLocale('mailtext'); - $to = $conf['notify']; - $bcc = ''; + $tpl = 'mailtext'; + $to = $conf['notify']; } elseif($who == 'subscribers') { - if(!$conf['subscribers']) return false; //subscribers enabled? + if(!actionOK('subscribe')) return false; //subscribers enabled? if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return false; //skip minors $data = array('id' => $id, 'addresslist' => '', 'self' => false); trigger_event( 'COMMON_NOTIFY_ADDRESSLIST', $data, - 'subscription_addresslist' + array(new Subscription(), 'notifyaddresses') ); - $bcc = $data['addresslist']; - if(empty($bcc)) return false; - $to = ''; - $text = rawLocale('subscr_single'); - } elseif($who == 'register') { - if(empty($conf['registernotify'])) return false; - $text = rawLocale('registermail'); - $to = $conf['registernotify']; - $bcc = ''; + $to = $data['addresslist']; + if(empty($to)) return false; + $tpl = 'subscr_single'; } else { return false; //just to be safe } - // prepare replacements (keys not set in hrep will be taken from trep) - $trep = array( - 'NEWPAGE' => wl($id, '', true, '&'), - 'PAGE' => $id, - 'SUMMARY' => $summary - ); - $trep = array_merge($trep, $replace); - $hrep = array(); - // prepare content - if($who == 'register') { - $subject = $lang['mail_new_user'].' '.$summary; - } elseif($rev) { - $subject = $lang['mail_changed'].' '.$id; - $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&'); - $old_content = rawWiki($id, $rev); - $new_content = rawWiki($id); - $df = new Diff(explode("\n", $old_content), - explode("\n", $new_content)); - $dformat = new UnifiedDiffFormatter(); - $tdiff = $dformat->format($df); - - $DIFF_INLINESTYLES = true; - $hdf = new Diff(explode("\n", hsc($old_content)), - explode("\n", hsc($new_content))); - $dformat = new InlineDiffFormatter(); - $hdiff = $dformat->format($hdf); - $hdiff = '<table>'.$hdiff.'</table>'; - $DIFF_INLINESTYLES = false; - } else { - $subject = $lang['mail_newpage'].' '.$id; - $trep['OLDPAGE'] = '---'; - $tdiff = rawWiki($id); - $hdiff = nl2br(hsc($tdiff)); - } - $trep['DIFF'] = $tdiff; - $hrep['DIFF'] = $hdiff; - - // send mail - $mail = new Mailer(); - $mail->to($to); - $mail->bcc($bcc); - $mail->subject($subject); - $mail->setBody($text, $trep, $hrep); - if($who == 'subscribers') { - $mail->setHeader( - 'List-Unsubscribe', - '<'.wl($id, array('do'=> 'subscribe'), true, '&').'>', - false - ); - } - return $mail->send(); + $subscription = new Subscription(); + return $subscription->send_diff($to, $tpl, $id, $rev, $summary); } /** diff --git a/inc/html.php b/inc/html.php index f4e6af663..5c1c75cf6 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1390,8 +1390,7 @@ function html_edit(){ $data = array('form' => $form, 'wr' => $wr, 'media_manager' => true, - 'target' => ($INPUT->has('target') && $wr && - $RANGE !== '') ? $INPUT->str('target') : 'section', + 'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section', 'intro_locale' => $include); if ($data['target'] !== 'section') { diff --git a/inc/indexer.php b/inc/indexer.php index 7a62345bf..e518907d7 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -339,6 +339,109 @@ class Doku_Indexer { } /** + * Rename a page in the search index without changing the indexed content. This function doesn't check if the + * old or new name exists in the filesystem. It returns an error if the old page isn't in the page list of the + * indexer and it deletes all previously indexed content of the new page. + * + * @param string $oldpage The old page name + * @param string $newpage The new page name + * @return string|bool If the page was successfully renamed, can be a message in the case of an error + */ + public function renamePage($oldpage, $newpage) { + if (!$this->lock()) return 'locked'; + + $pages = $this->getPages(); + + $id = array_search($oldpage, $pages); + if ($id === false) { + $this->unlock(); + return 'page is not in index'; + } + + $new_id = array_search($newpage, $pages); + if ($new_id !== false) { + // make sure the page is not in the index anymore + if ($this->deletePageNoLock($newpage) !== true) { + return false; + } + + $pages[$new_id] = 'deleted:'.time().rand(0, 9999); + } + + $pages[$id] = $newpage; + + // update index + if (!$this->saveIndex('page', '', $pages)) { + $this->unlock(); + return false; + } + + // reset the pid cache + $this->pidCache = array(); + + $this->unlock(); + return true; + } + + /** + * Renames a meta value in the index. This doesn't change the meta value in the pages, it assumes that all pages + * will be updated. + * + * @param string $key The metadata key of which a value shall be changed + * @param string $oldvalue The old value that shall be renamed + * @param string $newvalue The new value to which the old value shall be renamed, can exist (then values will be merged) + * @return bool|string If renaming the value has been successful, false or error message on error. + */ + public function renameMetaValue($key, $oldvalue, $newvalue) { + if (!$this->lock()) return 'locked'; + + // change the relation references index + $metavalues = $this->getIndex($key, '_w'); + $oldid = array_search($oldvalue, $metavalues); + if ($oldid !== false) { + $newid = array_search($newvalue, $metavalues); + if ($newid !== false) { + // free memory + unset ($metavalues); + + // okay, now we have two entries for the same value. we need to merge them. + $indexline = $this->getIndexKey($key, '_i', $oldid); + if ($indexline != '') { + $newindexline = $this->getIndexKey($key, '_i', $newid); + $pagekeys = $this->getIndex($key, '_p'); + $parts = explode(':', $indexline); + foreach ($parts as $part) { + list($id, $count) = explode('*', $part); + $newindexline = $this->updateTuple($newindexline, $id, $count); + + $keyline = explode(':', $pagekeys[$id]); + // remove old meta value + $keyline = array_diff($keyline, array($oldid)); + // add new meta value when not already present + if (!in_array($newid, $keyline)) { + array_push($keyline, $newid); + } + $pagekeys[$id] = implode(':', $keyline); + } + $this->saveIndex($key, '_p', $pagekeys); + unset($pagekeys); + $this->saveIndexKey($key, '_i', $oldid, ''); + $this->saveIndexKey($key, '_i', $newid, $newindexline); + } + } else { + $metavalues[$oldid] = $newvalue; + if (!$this->saveIndex($key, '_w', $metavalues)) { + $this->unlock(); + return false; + } + } + } + + $this->unlock(); + return true; + } + + /** * Remove a page from the index * * Erases entries in all known indexes. @@ -351,10 +454,26 @@ class Doku_Indexer { if (!$this->lock()) return "locked"; + $result = $this->deletePageNoLock($page); + + $this->unlock(); + + return $result; + } + + /** + * Remove a page from the index without locking the index, only use this function if the index is already locked + * + * Erases entries in all known indexes. + * + * @param string $page a page name + * @return boolean the function completed successfully + * @author Tom N Harris <tnharris@whoopdedo.org> + */ + protected function deletePageNoLock($page) { // load known documents $pid = $this->getPIDNoLock($page); if ($pid === false) { - $this->unlock(); return false; } @@ -380,7 +499,6 @@ class Doku_Indexer { } // Save the reverse index if (!$this->saveIndexKey('pageword', '', $pid, "")) { - $this->unlock(); return false; } @@ -397,7 +515,6 @@ class Doku_Indexer { $this->saveIndexKey($metaname.'_p', '', $pid, ''); } - $this->unlock(); return true; } diff --git a/inc/lang/ar/subscr_single.txt b/inc/lang/ar/subscr_single.txt index 5c62aeaeb..611688415 100644 --- a/inc/lang/ar/subscr_single.txt +++ b/inc/lang/ar/subscr_single.txt @@ -15,7 +15,7 @@ لإلغاء إشعارات الصفحة,لُج الويكي في @DOKUWIKIURL@ ثم زُر -@NEWPAGE@ +@SUBSCRIBE@ وألغ الاشتراك من تغييرات الصفحة و/أو النطاق. -- diff --git a/inc/lang/bg/subscr_single.txt b/inc/lang/bg/subscr_single.txt index 7b26f8e96..a74a21fb8 100644 --- a/inc/lang/bg/subscr_single.txt +++ b/inc/lang/bg/subscr_single.txt @@ -14,7 +14,7 @@ Нова версия: @NEWPAGE@ Ако желаете да прекратите уведомяването за страницата трябва да се впишете на адрес @DOKUWIKIURL@, да посетите -@NEWPAGE@ +@SUBSCRIBE@ и да прекратите абонамента за промени по страницата или именното пространство. -- diff --git a/inc/lang/ca/lang.php b/inc/lang/ca/lang.php index 0fd88ec39..cb2b64686 100644 --- a/inc/lang/ca/lang.php +++ b/inc/lang/ca/lang.php @@ -5,6 +5,7 @@ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Carles Bellver <carles.bellver@cent.uji.es> * @author Carles Bellver <carles.bellver@gmail.com> + * @author daniel@6temes.cat */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -27,7 +28,7 @@ $lang['btn_revs'] = 'Revisions anteriors'; $lang['btn_recent'] = 'Canvis recents'; $lang['btn_upload'] = 'Penja'; $lang['btn_cancel'] = 'Cancel·la'; -$lang['btn_index'] = 'Índex'; +$lang['btn_index'] = 'Mapa del lloc'; $lang['btn_secedit'] = 'Edita'; $lang['btn_login'] = 'Entra'; $lang['btn_logout'] = 'Surt'; @@ -38,14 +39,15 @@ $lang['btn_back'] = 'Enrere'; $lang['btn_backlink'] = 'Què hi enllaça'; $lang['btn_backtomedia'] = 'Torna a la selecció de fitxers'; $lang['btn_subscribe'] = 'Subscripció a canvis d\'aquesta pàgina'; -$lang['btn_unsubscribe'] = 'Cancel·la subscripció a pàgina'; $lang['btn_profile'] = 'Actualització del perfil'; $lang['btn_reset'] = 'Reinicia'; +$lang['btn_resendpwd'] = 'Estableix una nova contrasenya'; $lang['btn_draft'] = 'Edita esborrany'; $lang['btn_recover'] = 'Recupera esborrany'; $lang['btn_draftdel'] = 'Suprimeix esborrany'; $lang['btn_revert'] = 'Restaura'; $lang['btn_register'] = 'Registra\'m'; +$lang['btn_apply'] = 'Aplica'; $lang['loggedinas'] = 'Heu entrat com'; $lang['user'] = 'Nom d\'usuari'; $lang['pass'] = 'Contrasenya'; @@ -75,6 +77,7 @@ $lang['profnoempty'] = 'No es pot deixar en blanc el nom o l\'adreça $lang['profchanged'] = 'El perfil d\'usuari s\'ha actualitzat correctament.'; $lang['pwdforget'] = 'Heu oblidat la contrasenya? Podeu obtenir-ne una de nova.'; $lang['resendna'] = 'Aquest wiki no permet tornar a enviar la contrasenya.'; +$lang['resendpwd'] = 'Estableix una nova contrasenya per'; $lang['resendpwdmissing'] = 'Heu d\'emplenar tots els camps.'; $lang['resendpwdnouser'] = 'No s\'ha pogut trobar aquest usuari a la base de dades.'; $lang['resendpwdbadauth'] = 'Aquest codi d\'autenticació no és vàlid. Assegureu-vos d\'utilitzar l\'enllaç de confirmació complet.'; @@ -87,10 +90,52 @@ $lang['searchmedia_in'] = 'Cerca en: %s'; $lang['txt_upload'] = 'Trieu el fitxer que voleu penjar'; $lang['txt_filename'] = 'Introduïu el nom wiki (opcional)'; $lang['txt_overwrt'] = 'Sobreescriu el fitxer actual'; +$lang['maxuploadsize'] = 'Puja com a màxim %s per arxiu.'; $lang['lockedby'] = 'Actualment blocat per:'; $lang['lockexpire'] = 'Venciment del blocatge:'; -$lang['js']['willexpire'] = 'El blocatge per a editar aquesta pàgina venç d\'aquí a un minut.\nUtilitzeu la visualització prèvia per reiniciar el rellotge i evitar conflictes.'; -$lang['js']['notsavedyet'] = "Heu fet canvis que es perdran si no els deseu.\nVoleu continuar?"; +$lang['js']['willexpire'] = 'El blocatge per a editar aquesta pàgina venç d\'aquí a un minut.\nUtilitzeu la visualització prèvia per reiniciar el rellotge i evitar conflictes.'; +$lang['js']['notsavedyet'] = 'Heu fet canvis que es perdran si no els deseu. +Voleu continuar?'; +$lang['js']['searchmedia'] = 'Cerca fitxers'; +$lang['js']['keepopen'] = 'Manté la finestra oberta'; +$lang['js']['hidedetails'] = 'Oculta detalls'; +$lang['js']['mediatitle'] = 'Propietats de l\'enllaç'; +$lang['js']['mediadisplay'] = 'Tipus d\'enllaç'; +$lang['js']['mediaalign'] = 'Alineació'; +$lang['js']['mediasize'] = 'Mida de la imatge'; +$lang['js']['mediatarget'] = 'Destí de l\'enllaç'; +$lang['js']['mediaclose'] = 'Tanca'; +$lang['js']['mediainsert'] = 'Inserta'; +$lang['js']['mediadisplayimg'] = 'Mostra la imatge'; +$lang['js']['mediadisplaylnk'] = 'Mostra només l\'enllaç'; +$lang['js']['mediasmall'] = 'Versió petita'; +$lang['js']['mediamedium'] = 'Versió mitjana'; +$lang['js']['medialarge'] = 'Versió gran'; +$lang['js']['mediaoriginal'] = 'Versió original'; +$lang['js']['medialnk'] = 'Enllaç a la pàgina de detalls'; +$lang['js']['mediadirect'] = 'Enllaç directe a l\'original'; +$lang['js']['medianolnk'] = 'No hi ha enllaç'; +$lang['js']['medianolink'] = 'No enllacis la imatge'; +$lang['js']['medialeft'] = 'Alinea la imatge a l\'esquerra.'; +$lang['js']['mediaright'] = 'Alinea la imatge a la dreta.'; +$lang['js']['mediacenter'] = 'Alinea la imatge al mig.'; +$lang['js']['medianoalign'] = 'No facis servir alineació.'; +$lang['js']['nosmblinks'] = 'Els enllaços amb recursos compartits de Windows només funcionen amb el Microsoft Internet Explorer. +Si voleu podeu copiar i enganxar l\'enllaç.'; +$lang['js']['linkwiz'] = 'Auxiliar d\'enllaços'; +$lang['js']['linkto'] = 'Enllaça a:'; +$lang['js']['del_confirm'] = 'Suprimiu aquesta entrada?'; +$lang['js']['restore_confirm'] = 'Vols realment restaurar aquesta versió?'; +$lang['js']['media_diff'] = 'Veure les diferències:'; +$lang['js']['media_diff_both'] = 'Un al costat de l\'altre'; +$lang['js']['media_diff_opacity'] = 'Resalta'; +$lang['js']['media_diff_portions'] = 'Llisca'; +$lang['js']['media_select'] = 'Escull els arxius'; +$lang['js']['media_upload_btn'] = 'Pujar'; +$lang['js']['media_done_btn'] = 'Fet'; +$lang['js']['media_drop'] = 'Arrossega aquí els arxius a pujar'; +$lang['js']['media_cancel'] = 'esborra'; +$lang['js']['media_overwrt'] = 'Sobreescriu els arxius existents'; $lang['rssfailed'] = 'S\'ha produït un error en recollir aquesta alimentació: '; $lang['nothingfound'] = 'No s\'ha trobat res.'; $lang['mediaselect'] = 'Selecció de fitxers'; @@ -108,14 +153,7 @@ $lang['deletefail'] = 'No s\'ha pogut suprimir el fitxer "%s". Compro $lang['mediainuse'] = 'No s\'ha pogut suprimir el fitxer "%s". Encara s\'està utilitzant.'; $lang['namespaces'] = 'Espais'; $lang['mediafiles'] = 'Fitxers disponibles en'; -$lang['js']['searchmedia'] = 'Cerca fitxers'; -$lang['js']['keepopen'] = 'Manté la finestra oberta'; -$lang['js']['hidedetails'] = 'Oculta detalls'; -$lang['js']['nosmblinks'] = 'Els enllaços amb recursos compartits de Windows només funcionen amb el Microsoft Internet Explorer. -Si voleu podeu copiar i enganxar l\'enllaç.'; -$lang['js']['linkwiz'] = 'Auxiliar d\'enllaços'; -$lang['js']['linkto'] = 'Enllaça a:'; -$lang['js']['del_confirm'] = 'Suprimiu aquesta entrada?'; +$lang['accessdenied'] = 'No teniu permís per a veure aquesta pàgina.'; $lang['mediausage'] = 'Utilitzeu la sintaxi següent per referir-vos a aquest enllaç:'; $lang['mediaview'] = 'Mostra el fitxer original'; $lang['mediaroot'] = 'arrel'; @@ -131,6 +169,10 @@ $lang['current'] = 'actual'; $lang['yours'] = 'La vostra versió'; $lang['diff'] = 'Mostra diferències amb la versió actual'; $lang['diff2'] = 'Mostra diferències entre les revisions seleccionades'; +$lang['difflink'] = 'Enllaç a la visualització de la comparació'; +$lang['diff_type'] = 'Veieu les diferències:'; +$lang['diff_inline'] = 'En línia'; +$lang['diff_side'] = 'Un al costat de l\'altre'; $lang['line'] = 'Línia'; $lang['breadcrumb'] = 'Camí'; $lang['youarehere'] = 'Sou aquí'; @@ -143,10 +185,20 @@ $lang['external_edit'] = 'edició externa'; $lang['summary'] = 'Resum d\'edició'; $lang['noflash'] = 'Per a visualitzar aquest contingut necessiteu el <a href="http://www.adobe.com/products/flashplayer/">connector d\'Adobe Flash</a>.'; $lang['download'] = 'Baixa el fragment'; +$lang['tools'] = 'Eines'; +$lang['user_tools'] = 'Eines de l\'usuari'; +$lang['site_tools'] = 'Eines del lloc'; +$lang['page_tools'] = 'Eines de la pàgina'; +$lang['skip_to_content'] = 'salta al contingut'; +$lang['sidebar'] = 'Barra lateral'; $lang['mail_newpage'] = 'pàgina afegida:'; $lang['mail_changed'] = 'pàgina modificada:'; $lang['mail_new_user'] = 'nou usuari:'; $lang['mail_upload'] = 'fitxer penjat:'; +$lang['changes_type'] = 'Veure els canvis de'; +$lang['pages_changes'] = 'Pàgines'; +$lang['media_changes'] = 'Arxius gràfics'; +$lang['both_changes'] = 'Pàgines i arxius gràfics'; $lang['qb_bold'] = 'Negreta'; $lang['qb_italic'] = 'Cursiva'; $lang['qb_underl'] = 'Subratllat'; @@ -187,13 +239,27 @@ $lang['img_copyr'] = 'Copyright'; $lang['img_format'] = 'Format'; $lang['img_camera'] = 'Càmera'; $lang['img_keywords'] = 'Paraules clau'; -$lang['subscribe_success'] = 'S\'ha afegit %s a la llista de subscripcions de %s'; -$lang['subscribe_error'] = 'S\'ha produït un error en afegir %s a la llista de subscripcions de %s'; -$lang['subscribe_noaddress'] = 'No hi ha cap adreça de correu associada al vostre nom d\'usuari. No se us ha pogut afegir a la llista de subscripcions.'; -$lang['unsubscribe_success'] = '%s ha estat suprimit de la llista de subscripcions de %s'; -$lang['unsubscribe_error'] = 'S\'ha produït un error en suprimir %s de la llista de subscripcions de %s'; +$lang['img_width'] = 'Ample'; +$lang['img_height'] = 'Alçada'; +$lang['subscr_subscribe_success'] = 'S\'ha afegit %s a la llista de subscripcions per %s'; +$lang['subscr_subscribe_error'] = 'Hi ha hagut un error a l\'afegir %s a la llista per %s'; +$lang['subscr_subscribe_noaddress'] = 'No hi ha cap adreça associada pel vostre nom d\'usuari, no podeu ser afegit a la llista de subscripcions'; +$lang['subscr_unsubscribe_success'] = 'S\'ha esborrat %s de la llista de subscripcions per %s'; +$lang['subscr_unsubscribe_error'] = 'Hi ha hagut un error a l\'esborrar %s de la llista de subscripcions per %s'; +$lang['subscr_already_subscribed'] = '%s ja està subscrit a %s'; +$lang['subscr_not_subscribed'] = '%s no està subscrit a %s'; +$lang['subscr_m_not_subscribed'] = 'En aquests moments no esteu subscrit a l\'actual pàgina o espai'; +$lang['subscr_m_new_header'] = 'Afegeix subcripció'; +$lang['subscr_m_current_header'] = 'Subscripcions actuals'; +$lang['subscr_m_unsubscribe'] = 'Donar-se de baixa'; +$lang['subscr_m_subscribe'] = 'Donar-se d\'alta'; +$lang['subscr_m_receive'] = 'Rebre'; +$lang['subscr_style_every'] = 'Envia\'m un correu electrònic per a cada canvi'; +$lang['subscr_style_digest'] = 'Envia\'m un correu electrònic amb un resum dels canvis per a cada pàgina (cada %.2f dies)'; +$lang['subscr_style_list'] = 'llistat de pàgines canviades des de l\'últim correu electrònic (cada %.2f dies)'; $lang['authmodfailed'] = 'La configuració de l\'autenticació d\'usuaris és errònia. Informeu els administradors del wiki.'; $lang['authtempfail'] = 'L\'autenticació d\'usuaris no està disponible temporalment. Si aquesta situació persisteix, si us plau informeu els administradors del wiki.'; +$lang['authpwdexpire'] = 'La vostra contrasenya caducarà en %d dies, l\'hauríeu de canviar aviat.'; $lang['i_chooselang'] = 'Trieu l\'idioma'; $lang['i_installer'] = 'Instal·lador de DokuWiki'; $lang['i_wikiname'] = 'Nom del wiki'; @@ -208,13 +274,14 @@ $lang['i_confexists'] = '<code>%s</code> ja existeix'; $lang['i_writeerr'] = 'No es pot crear <code>%s</code>. Comproveu els permisos del directori i/o del fitxer i creeu el fitxer manualment.'; $lang['i_badhash'] = 'dokuwiki.php no reconegut o modificat (hash=<code>%s</code>)'; $lang['i_badval'] = '<code>%s</code> - valor il·legal o buit'; -$lang['i_success'] = 'La configuració s\'ha acabat amb èxit. Ara podeu suprimir el fitxer install.php. Aneu al vostre nou <a href="doku.php?id=wiki:welcome">DokuWiki</a>.'; -$lang['i_failure'] = 'S\'han produït alguns errors en escriure els fitxers de configuració. Potser caldrà que els arregleu manualment abans d\'utilitzar el vostre nou <a href="doku.php?id=wiki:welcome">DokuWiki</a>.'; +$lang['i_success'] = 'La configuració s\'ha acabat amb èxit. Ara podeu suprimir el fitxer install.php. Aneu al vostre nou <a href="doku.php">DokuWiki</a>.'; +$lang['i_failure'] = 'S\'han produït alguns errors en escriure els fitxers de configuració. Potser caldrà que els arregleu manualment abans d\'utilitzar el vostre nou <a href="doku.php">DokuWiki</a>.'; $lang['i_policy'] = 'Política ACL inicial'; $lang['i_pol0'] = 'Wiki obert (tothom pot llegir, escriure i penjar fitxers)'; $lang['i_pol1'] = 'Wiki públic (tothom pot llegir, els usuaris registrats poden escriure i penjar fitxers)'; $lang['i_pol2'] = 'Wiki tancat (només els usuaris registrats poden llegir, escriure i penjar fitxers)'; $lang['i_retry'] = 'Reintenta'; +$lang['i_license'] = 'Escolliu el tipus de llicència que voleu fer servir per al vostre contingut:'; $lang['recent_global'] = 'Esteu veient els canvis recents de l\'espai <strong>%s</strong>. També podeu veure els <a href="%s">canvis recents de tot el wiki</a>.'; $lang['years'] = 'fa %d anys'; $lang['months'] = 'fa %d mesos'; @@ -223,3 +290,27 @@ $lang['days'] = 'fa %d dies'; $lang['hours'] = 'fa %d hores'; $lang['minutes'] = 'fa %d minuts'; $lang['seconds'] = 'fa %d segons'; +$lang['wordblock'] = 'El vostre canvi no s\'ha guardat perquè conté text blocat (spam)'; +$lang['media_uploadtab'] = 'Puja'; +$lang['media_searchtab'] = 'Busca'; +$lang['media_file'] = 'Fitxer'; +$lang['media_viewtab'] = 'Mostra'; +$lang['media_edittab'] = 'Edita'; +$lang['media_historytab'] = 'Històric'; +$lang['media_list_thumbs'] = 'Miniatura'; +$lang['media_list_rows'] = 'Files'; +$lang['media_sort_name'] = 'Nom'; +$lang['media_sort_date'] = 'Data'; +$lang['media_namespaces'] = 'Escolliu l\'espai'; +$lang['media_files'] = 'Arxius a %s'; +$lang['media_upload'] = 'Puja a %s'; +$lang['media_search'] = 'Busca a %s'; +$lang['media_view'] = '%s'; +$lang['media_viewold'] = '%s a %s'; +$lang['media_edit'] = 'Edita %s'; +$lang['media_history'] = 'Històric de %s'; +$lang['media_meta_edited'] = 'metadata editada'; +$lang['media_perm_read'] = 'No teniu permisos suficients per a llegir arxius.'; +$lang['media_perm_upload'] = 'No teniu permisos suficients per a pujar arxius'; +$lang['media_update'] = 'Puja la nova versió'; +$lang['media_restore'] = 'Restaura aquesta versió'; diff --git a/inc/lang/ca/mailwrap.html b/inc/lang/ca/mailwrap.html new file mode 100644 index 000000000..ed3bb6e9d --- /dev/null +++ b/inc/lang/ca/mailwrap.html @@ -0,0 +1,13 @@ +<html> +<head> +<title>@TITLE@</title> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +</head> +<body> + +@HTMLBODY@ + +<br /><hr /> +<small>Aquest correu electrònic ha estat generat per DokuWiki a @DOKUWIKIURL@.</small> +</body> +</html>
\ No newline at end of file diff --git a/inc/lang/ca/resetpwd.txt b/inc/lang/ca/resetpwd.txt new file mode 100644 index 000000000..565f1d5b0 --- /dev/null +++ b/inc/lang/ca/resetpwd.txt @@ -0,0 +1,3 @@ +===== Establiu una nova contrasenya ===== + +Introdueixi una nova contrasenya pel seu compte a aquest wiki.
\ No newline at end of file diff --git a/inc/lang/ca/subscr_digest.txt b/inc/lang/ca/subscr_digest.txt new file mode 100644 index 000000000..2b95f97a5 --- /dev/null +++ b/inc/lang/ca/subscr_digest.txt @@ -0,0 +1,21 @@ +Hola! + +La pàgina @PAGE@ al wiki @TITLE@ ha canviat. +A continuació podeu veure els canvis: + +-------------------------------------------------------- +@DIFF@ +-------------------------------------------------------- + +Versió anterior: @OLDPAGE@ +Nova versió: @NEWPAGE@ + +Si voleu cancel·lar les notificacions per a la pàgina, accediu al wiki a +@DOKUWIKIURL@, visiteu +@SUBSCRIBE@ +i doneu-vos de baixa dels canvis de la pàgina o de l'espai. + + +-- +Aquest mail ha estat generat per DokuWiki a +@DOKUWIKIURL@
\ No newline at end of file diff --git a/inc/lang/ca/subscr_form.txt b/inc/lang/ca/subscr_form.txt new file mode 100644 index 000000000..d3679454f --- /dev/null +++ b/inc/lang/ca/subscr_form.txt @@ -0,0 +1,3 @@ +===== Gestió de les Subscripcions ===== + +Aquesta pàgina podeu gestiona les vostres subscripcions per a les pàgines i els espais actuals.
\ No newline at end of file diff --git a/inc/lang/ca/subscr_list.txt b/inc/lang/ca/subscr_list.txt new file mode 100644 index 000000000..56bcad545 --- /dev/null +++ b/inc/lang/ca/subscr_list.txt @@ -0,0 +1,21 @@ +Hola! + +Alguna(es) pàgina(es) de l'espai @PAGE@ al wiki @TITLE@ han canviat. +A continuació podeu veure els canvis: + +-------------------------------------------------------- +@DIFF@ +-------------------------------------------------------- + +Versió anterior: @OLDPAGE@ +Nova versió: @NEWPAGE@ + +Si voleu cancel·lar les notificacions per a la pàgina, accediu al wiki a +@DOKUWIKIURL@, visiteu +@SUBSCRIBE@ +i doneu-vos de baixa dels canvis de la pàgina o de l'espai. + + +-- +Aquest mail ha estat generat per DokuWiki a +@DOKUWIKIURL@
\ No newline at end of file diff --git a/inc/lang/da/subscr_single.txt b/inc/lang/da/subscr_single.txt index 64b14588c..cdc554513 100644 --- a/inc/lang/da/subscr_single.txt +++ b/inc/lang/da/subscr_single.txt @@ -15,7 +15,7 @@ Ny Revision: @NEWPAGE@ For at slå side notifikationer fra, skal du logge ind på @DOKUWIKIURL@ og besøge -@NEWPAGE@ +@SUBSCRIBE@ og slå abonnoment for side / navnerum ændringer fra. -- diff --git a/inc/lang/de-informal/subscr_single.txt b/inc/lang/de-informal/subscr_single.txt index 3c557bc17..6e3f58b9f 100644 --- a/inc/lang/de-informal/subscr_single.txt +++ b/inc/lang/de-informal/subscr_single.txt @@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@ Um das Abonnement für diese Seite aufzulösen, melde dich im Wiki an @DOKUWIKIURL@, besuche dann -@NEWPAGE@ +@SUBSCRIBE@ und klicke auf den Link 'Aboverwaltung'. -- diff --git a/inc/lang/de/subscr_single.txt b/inc/lang/de/subscr_single.txt index f3e1cd393..da9914e50 100644 --- a/inc/lang/de/subscr_single.txt +++ b/inc/lang/de/subscr_single.txt @@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@ Um das Abonnement für diese Seite aufzulösen, melden Sie sich im Wiki an @DOKUWIKIURL@, besuchen dann -@NEWPAGE@ +@SUBSCRIBE@ und klicken auf die Taste 'Aboverwaltung'. -- diff --git a/inc/lang/en/subscr_single.txt b/inc/lang/en/subscr_single.txt index 673c4c32a..0bc310e04 100644 --- a/inc/lang/en/subscr_single.txt +++ b/inc/lang/en/subscr_single.txt @@ -15,7 +15,7 @@ New Revision: @NEWPAGE@ To cancel the page notifications, log into the wiki at @DOKUWIKIURL@ then visit -@NEWPAGE@ +@SUBSCRIBE@ and unsubscribe page and/or namespace changes. -- diff --git a/inc/lang/eo/subscr_single.txt b/inc/lang/eo/subscr_single.txt index 431fd0251..e4847e8ab 100644 --- a/inc/lang/eo/subscr_single.txt +++ b/inc/lang/eo/subscr_single.txt @@ -15,7 +15,7 @@ Nova versio: @NEWPAGE@ Por nuligi la paĝinformojn, ensalutu la vikion ĉe @DOKUWIKIURL@, poste iru al -@NEWPAGE@ +@SUBSCRIBE@ kaj malabonu la paĝajn kaj/aŭ nomspacajn ŝanĝojn. -- diff --git a/inc/lang/he/subscr_single.txt b/inc/lang/he/subscr_single.txt index 123b186c8..78b551e2f 100644 --- a/inc/lang/he/subscr_single.txt +++ b/inc/lang/he/subscr_single.txt @@ -14,7 +14,7 @@ לביטול התרעות בנוגע לעמוד, יש להיכנס לאתר הוויקי בכתובת @DOKUWIKIURL@ ואז לבקר בדף -@NEWPAGE@ +@SUBSCRIBE@ ולבטל את המינוי לקבלת שינויים בדף ו/או במרחב השם. -- diff --git a/inc/lang/ia/subscr_single.txt b/inc/lang/ia/subscr_single.txt index 3d6ef7103..445df197c 100644 --- a/inc/lang/ia/subscr_single.txt +++ b/inc/lang/ia/subscr_single.txt @@ -15,7 +15,7 @@ Version nove: @NEWPAGE@ Pro cancellar le notificationes de paginas, aperi un session al wiki a @DOKUWIKIURL@ postea visita -@NEWPAGE@ +@SUBSCRIBE@ e cancella tu subscription al modificationes in paginas e/o spatios de nomines. -- diff --git a/inc/lang/it/subscr_single.txt b/inc/lang/it/subscr_single.txt index 8cde8ea0f..a8649a4ef 100644 --- a/inc/lang/it/subscr_single.txt +++ b/inc/lang/it/subscr_single.txt @@ -15,7 +15,7 @@ Nuova revisione: @NEWPAGE@ Per non ricevere più queste notifiche, collegati al wiki all'indirizzo @DOKUWIKIURL@ e poi visita -@NEWPAGE@ +@SUBSCRIBE@ e rimuovi la sottoscrizione alle modifiche della pagina o categoria. diff --git a/inc/lang/ko/subscr_single.txt b/inc/lang/ko/subscr_single.txt index 6bd1885e6..2679db393 100644 --- a/inc/lang/ko/subscr_single.txt +++ b/inc/lang/ko/subscr_single.txt @@ -14,7 +14,7 @@ 새 버전 : @NEWPAGE@ 이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤 -@NEWPAGE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. +@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요. -- @DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다.
\ No newline at end of file diff --git a/inc/lang/la/subscr_digest.txt b/inc/lang/la/subscr_digest.txt index 629213359..32d378a7e 100644 --- a/inc/lang/la/subscr_digest.txt +++ b/inc/lang/la/subscr_digest.txt @@ -12,7 +12,7 @@ Noua recensio: @NEWPAGE@ Ut paginae adnotationes deleas, in uicem ineas in @DOKUWIKIURL@, deinde uideas -@NEWPAGE@ +@SUBSCRIBE@ et paginarum generum optiones mutes. -- diff --git a/inc/lang/la/subscr_single.txt b/inc/lang/la/subscr_single.txt index 7839791ea..14285014c 100644 --- a/inc/lang/la/subscr_single.txt +++ b/inc/lang/la/subscr_single.txt @@ -15,7 +15,7 @@ Noua recensio: @NEWPAGE@ Ut paginae adnotationes deleas, in uicem ineas in @DOKUWIKIURL@, deinde uideas -@NEWPAGE@ +@SUBSCRIBE@ et paginarum et\aut generum optiones mutasa. -- diff --git a/inc/lang/no/subscr_digest.txt b/inc/lang/no/subscr_digest.txt index 6afd0cc5c..670d39d32 100644 --- a/inc/lang/no/subscr_digest.txt +++ b/inc/lang/no/subscr_digest.txt @@ -12,7 +12,7 @@ Ny versjon: @NEWPAGE@ For å avslutte varslingen, logg inn på @DOKUWIKIURL@ og gå til -@NEWPAGE@ +@SUBSCRIBE@ og avslutt abonnementet på endringer av siden eller i navnerommet. -- diff --git a/inc/lang/no/subscr_list.txt b/inc/lang/no/subscr_list.txt index 72cd307cb..860d88d2a 100644 --- a/inc/lang/no/subscr_list.txt +++ b/inc/lang/no/subscr_list.txt @@ -9,7 +9,7 @@ Her er endringene: For å avslutte varslinga, logg inn på @DOKUWIKIURL@ og gå til -@NEWPAGE@ +@SUBSCRIBE@ og avslutt abonnementet på endringer av sida eller i navnerommet. -- diff --git a/inc/lang/no/subscr_single.txt b/inc/lang/no/subscr_single.txt index 25296da58..b26b3a879 100644 --- a/inc/lang/no/subscr_single.txt +++ b/inc/lang/no/subscr_single.txt @@ -15,7 +15,7 @@ Ny versjon: @NEWPAGE@ For å avslutte varslingen, logg inn på @DOKUWIKIURL@, gå til -@NEWPAGE@ +@SUBSCRIBE@ og avslutt abonnementet på endringer av siden eller i navnerommet. -- diff --git a/inc/lang/pt/subscr_single.txt b/inc/lang/pt/subscr_single.txt index 1187b5911..469c6bfb1 100644 --- a/inc/lang/pt/subscr_single.txt +++ b/inc/lang/pt/subscr_single.txt @@ -15,7 +15,7 @@ Revisão Nova: @NEWPAGE@ Para cancelar as notificações de página, inicie sessão no wiki em @DOKUWIKIURL@, visite -@NEWPAGE@ +@SUBSCRIBE@ e des-subscreva às alterações de página e/ou espaço de nome. -- diff --git a/inc/lang/sq/subscr_single.txt b/inc/lang/sq/subscr_single.txt index 90520be4f..df28ee176 100644 --- a/inc/lang/sq/subscr_single.txt +++ b/inc/lang/sq/subscr_single.txt @@ -15,7 +15,7 @@ Rishikimi i ri: @NEWPAGE@ Për të fshirë lajmërimet e faqes, hyni në wiki tek @DOKUWIKIURL@ dhe pastaj vizitoni -@NEWPAGE@ +@SUBSCRIBE@ dhe fshini ndryshimet e faqes dhe/ose hapësirës së emrit. -- diff --git a/inc/lang/tr/lang.php b/inc/lang/tr/lang.php index a8d8c5ac9..5430905b1 100644 --- a/inc/lang/tr/lang.php +++ b/inc/lang/tr/lang.php @@ -8,6 +8,7 @@ * @author Cihan Kahveci <kahvecicihan@gmail.com> * @author Yavuz Selim <yavuzselim@gmail.com> * @author Caleb Maclennan <caleb@alerque.com> + * @author farukerdemoncel@gmail.com */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -43,11 +44,14 @@ $lang['btn_backtomedia'] = 'Çokluortam dosyası seçimine dön'; $lang['btn_subscribe'] = 'Sayfa Değişikliklerini Bildir'; $lang['btn_profile'] = 'Kullanıcı Bilgilerini Güncelle'; $lang['btn_reset'] = 'Sıfırla'; +$lang['btn_resendpwd'] = 'Yeni şifre belirle'; $lang['btn_draft'] = 'Taslağı düzenle'; $lang['btn_recover'] = 'Taslağı geri yükle'; $lang['btn_draftdel'] = 'Taslağı sil'; $lang['btn_revert'] = 'Geri Yükle'; $lang['btn_register'] = 'Kayıt ol'; +$lang['btn_apply'] = 'Uygula'; +$lang['btn_media'] = 'Çokluortam Yöneticisi'; $lang['loggedinas'] = 'Giriş ismi'; $lang['user'] = 'Kullanıcı ismi'; $lang['pass'] = 'Parola'; @@ -77,6 +81,7 @@ $lang['profnoempty'] = 'Boş isim veya e-posta adresine izin verilmiyo $lang['profchanged'] = 'Kullanıcı bilgileri başarıyla değiştirildi.'; $lang['pwdforget'] = 'Parolanızı mı unuttunuz? Yeni bir parola alın'; $lang['resendna'] = 'Bu wiki parolayı tekrar göndermeyi desteklememektedir.'; +$lang['resendpwd'] = 'İçin yeni şifre belirle'; $lang['resendpwdmissing'] = 'Üzgünüz, tüm alanları doldurmalısınız.'; $lang['resendpwdnouser'] = 'Üzgünüz, veritabanımızda bu kullanıcıyı bulamadık.'; $lang['resendpwdbadauth'] = 'Üzgünüz, bu doğrulama kodu doğru değil. Doğrulama linkini tam olarak kullandığınıza emin olun.'; @@ -91,7 +96,7 @@ $lang['txt_filename'] = 'Dosya adı (zorunlu değil)'; $lang['txt_overwrt'] = 'Mevcut dosyanın üstüne yaz'; $lang['lockedby'] = 'Şu an şunun tarafından kilitli:'; $lang['lockexpire'] = 'Kilitin açılma tarihi:'; -$lang['js']['willexpire'] = 'Bu sayfayı değiştirme kilidinin süresi yaklaşık bir dakika içinde geçecek.\nÇakışmaları önlemek için önizleme tuşunu kullanarak kilit sayacını sıfırla.'; +$lang['js']['willexpire'] = 'Bu sayfayı değiştirme kilidinin süresi yaklaşık bir dakika içinde geçecek.\nÇakışmaları önlemek için önizleme tuşunu kullanarak kilit sayacını sıfırla.'; $lang['js']['notsavedyet'] = 'Kaydedilmemiş değişiklikler kaybolacak. Devam etmek istiyor musunuz?'; $lang['js']['searchmedia'] = 'Dosyalar için Ara'; @@ -122,6 +127,14 @@ $lang['js']['nosmblinks'] = 'Windows paylaşımı sadece Microsoft Internet $lang['js']['linkwiz'] = 'Bağlantı sihirbazı'; $lang['js']['linkto'] = 'Bağlantı:'; $lang['js']['del_confirm'] = 'Bu girişi sil?'; +$lang['js']['restore_confirm'] = 'Bu sürüme geri dönmek istediğinizden emin misiniz?'; +$lang['js']['media_diff'] = 'Farkları gör:'; +$lang['js']['media_select'] = 'Dosyalar seç...'; +$lang['js']['media_upload_btn'] = 'Yükle'; +$lang['js']['media_done_btn'] = 'Bitti'; +$lang['js']['media_drop'] = 'Yüklemek istediğiniz dosyaları buraya bırakın'; +$lang['js']['media_cancel'] = 'kaldır'; +$lang['js']['media_overwrt'] = 'Var olan dosyaların üzerine yaz'; $lang['rssfailed'] = 'Bu beslemeyi çekerken hata oluştu: '; $lang['nothingfound'] = 'Hiçbir şey yok.'; $lang['mediaselect'] = 'Çokluortam dosyası seçimi'; @@ -172,6 +185,9 @@ $lang['mail_newpage'] = 'sayfa eklenme:'; $lang['mail_changed'] = 'sayfa değiştirilme:'; $lang['mail_new_user'] = 'yeni kullanıcı'; $lang['mail_upload'] = 'dosya yüklendi:'; +$lang['pages_changes'] = 'Sayfalar'; +$lang['media_changes'] = 'Çokluortam dosyaları'; +$lang['both_changes'] = 'Sayfalar ve çoklu ortam dosyaları'; $lang['qb_bold'] = 'Kalın Yazı'; $lang['qb_italic'] = 'Eğik Yazı'; $lang['qb_underl'] = 'Altı Çizgili Yazı'; @@ -209,8 +225,14 @@ $lang['img_copyr'] = 'Telif Hakkı'; $lang['img_format'] = 'Biçim'; $lang['img_camera'] = 'Fotoğraf Makinası'; $lang['img_keywords'] = 'Anahtar Sözcükler'; +$lang['img_width'] = 'Genişlik'; +$lang['img_height'] = 'Yükseklik'; +$lang['img_manager'] = 'Ortam oynatıcısında göster'; +$lang['subscr_m_subscribe'] = 'Kayıt ol'; +$lang['subscr_m_receive'] = 'Al'; $lang['authmodfailed'] = 'Yanlış kullanıcı onaylama ayarı. Lütfen Wiki yöneticisine bildiriniz.'; $lang['authtempfail'] = 'Kullanıcı doğrulama geçici olarak yapılamıyor. Eğer bu durum devam ederse lütfen Wiki yöneticine haber veriniz.'; +$lang['authpwdexpire'] = 'Şifreniz %d gün sonra geçersiz hale gelecek, yakın bir zamanda değiştirmelisiniz.'; $lang['i_chooselang'] = 'Dili seçiniz'; $lang['i_installer'] = 'Dokuwiki Kurulum Sihirbazı'; $lang['i_wikiname'] = 'Wiki Adı'; @@ -225,11 +247,38 @@ $lang['i_confexists'] = '<code>%s</code> zaten var'; $lang['i_writeerr'] = '<code>%s</code> oluşturulamadı. Dosya/Klasör izin ayarlarını gözden geçirip dosyayı elle oluşturmalısınız.'; $lang['i_badhash'] = 'dokuwiki.php tanınamadı ya da değiştirilmiş (hash=<code>%s</code>)'; $lang['i_badval'] = '<code>%s</code> - Yanlış veya boş değer'; -$lang['i_success'] = 'Kurulum başarıyla tamamlandı. Şimdi install.php dosyasını silebilirsiniz. <a href="doku.php?id=wiki:welcome">Yeni DokuWikiniz</a>i kullanabilirsiniz.'; -$lang['i_failure'] = 'Ayar dosyalarını yazarken bazı hatalar oluştu. <a href="doku.php?id=wiki:welcome">Yeni DokuWikiniz</a>i kullanmadan önce bu hatalarınızı elle düzeltmeniz gerekebilir.'; +$lang['i_success'] = 'Kurulum başarıyla tamamlandı. Şimdi install.php dosyasını silebilirsiniz. <a href="doku.php">Yeni DokuWikiniz</a>i kullanabilirsiniz.'; +$lang['i_failure'] = 'Ayar dosyalarını yazarken bazı hatalar oluştu. <a href="doku.php">Yeni DokuWikiniz</a>i kullanmadan önce bu hatalarınızı elle düzeltmeniz gerekebilir.'; $lang['i_policy'] = 'İlk ACL ayarı'; $lang['i_pol0'] = 'Tamamen Açık Wiki (herkes okuyabilir, yazabilir ve dosya yükleyebilir)'; $lang['i_pol1'] = 'Açık Wiki (herkes okuyabilir, ancak sadece üye olanlar yazabilir ve dosya yükleyebilir)'; $lang['i_pol2'] = 'Kapalı Wiki (sadece üye olanlar okuyabilir, yazabilir ve dosya yükleyebilir)'; $lang['i_retry'] = 'Tekrar Dene'; +$lang['i_license'] = 'Lütfen içeriği hangi lisans altında yayınlamak istediğniizi belirtin:'; $lang['recent_global'] = '<b>%s</b> namespace\'i içerisinde yapılan değişiklikleri görüntülemektesiniz. Wiki\'deki tüm değişiklikleri de <a href="%s">bu adresten</a> görebilirsiniz. '; +$lang['years'] = '%d yıl önce'; +$lang['months'] = '%d ay önce'; +$lang['weeks'] = '%d hafta önce'; +$lang['days'] = '%d gün önce'; +$lang['hours'] = '%d saat önce'; +$lang['minutes'] = '%d dakika önce'; +$lang['seconds'] = '%d saniye önce'; +$lang['wordblock'] = 'Değişikliğiniz kaydedilmedi çünkü istenmeyen mesaj içeriyor (spam).'; +$lang['media_uploadtab'] = 'Karşıya yükle'; +$lang['media_searchtab'] = 'Ara'; +$lang['media_file'] = 'Dosya'; +$lang['media_viewtab'] = 'Görünüm'; +$lang['media_edittab'] = 'Düzenle'; +$lang['media_historytab'] = 'Geçmiş'; +$lang['media_list_thumbs'] = 'Küçük resimler'; +$lang['media_list_rows'] = 'Satırlar'; +$lang['media_sort_name'] = 'İsim'; +$lang['media_sort_date'] = 'Tarih'; +$lang['media_files'] = '%s deki dosyalar'; +$lang['media_upload'] = '%s dizinine yükle'; +$lang['media_search'] = '%s dizininde ara'; +$lang['media_view'] = '%s'; +$lang['media_edit'] = 'Düzenle %s'; +$lang['media_history'] = 'Geçmiş %s'; +$lang['media_perm_upload'] = 'Üzgünüm, karşıya dosya yükleme yetkiniz yok.'; +$lang['media_restore'] = 'Bu sürümü eski haline getir'; diff --git a/inc/lang/tr/resetpwd.txt b/inc/lang/tr/resetpwd.txt new file mode 100644 index 000000000..1ed758693 --- /dev/null +++ b/inc/lang/tr/resetpwd.txt @@ -0,0 +1,3 @@ + ====== Yeni şifre belirle ====== + +Lütfen bu wiki hesabınız için yeni bir şifre belirleyin.
\ No newline at end of file diff --git a/inc/lang/zh-tw/adminplugins.txt b/inc/lang/zh-tw/adminplugins.txt index fb1999269..6d21ac2cd 100644 --- a/inc/lang/zh-tw/adminplugins.txt +++ b/inc/lang/zh-tw/adminplugins.txt @@ -1 +1 @@ -===== 外加插件 =====
\ No newline at end of file +===== 附加元件 =====
\ No newline at end of file diff --git a/inc/lang/zh-tw/backlinks.txt b/inc/lang/zh-tw/backlinks.txt index 5b36728e7..6a8bf8896 100644 --- a/inc/lang/zh-tw/backlinks.txt +++ b/inc/lang/zh-tw/backlinks.txt @@ -1,4 +1,4 @@ ====== 反向連結 ====== -這裡是引用、連結到目前頁面的頁面清單。 +這是引用、連結到目前頁面的頁面清單。 diff --git a/inc/lang/zh-tw/diff.txt b/inc/lang/zh-tw/diff.txt index 17fad7ba0..e2c05001f 100644 --- a/inc/lang/zh-tw/diff.txt +++ b/inc/lang/zh-tw/diff.txt @@ -1,3 +1,3 @@ ====== 差異處 ====== -這裏顯示二個版本的差異處。
\ No newline at end of file +這裏顯示兩個版本的差異處。
\ No newline at end of file diff --git a/inc/lang/zh-tw/edit.txt b/inc/lang/zh-tw/edit.txt index bbe5bb8ed..f6b74794f 100644 --- a/inc/lang/zh-tw/edit.txt +++ b/inc/lang/zh-tw/edit.txt @@ -1 +1 @@ -編輯本頁並按下''儲存''即可。可在[[wiki:syntax|維基語法]]找到語法說明。請只在能讓本文品質「**更好**」時才編輯。如果只是要測試,請使用 [[playground:playground|遊樂場]]。 +編輯本頁後,請按下「儲存」按鈕。若要參看語法說明,請到[[wiki:syntax|語法]]頁。請只在能讓本文品質**更好**時才編輯。如果只是要測試,請移玉步至 [[playground:playground|遊樂場]]。
\ No newline at end of file diff --git a/inc/lang/zh-tw/editrev.txt b/inc/lang/zh-tw/editrev.txt index 96f9a7c6a..98a800ab1 100644 --- a/inc/lang/zh-tw/editrev.txt +++ b/inc/lang/zh-tw/editrev.txt @@ -1,2 +1,2 @@ -**您目前載入的是本份文件的舊版!** 您如果存檔,這些資料就會被存成另一份。 +**您目前載入的是本份文件的舊版!** 您如果存檔,這些舊版資料就會變成最新版本。 ---- diff --git a/inc/lang/zh-tw/index.txt b/inc/lang/zh-tw/index.txt index bba277041..1b89e0c5d 100644 --- a/inc/lang/zh-tw/index.txt +++ b/inc/lang/zh-tw/index.txt @@ -1,3 +1,3 @@ ====== 站台地圖 ====== -這個站台地圖列出了所有允許的頁面,依 [[doku>namespaces|分類空間]] 排序。
\ No newline at end of file +這個站台地圖列出了所有允許的頁面,依 [[doku>namespaces|分類名稱]] 排序。
\ No newline at end of file diff --git a/inc/lang/zh-tw/install.html b/inc/lang/zh-tw/install.html index 2a8b1aac3..9a0d1dcd9 100644 --- a/inc/lang/zh-tw/install.html +++ b/inc/lang/zh-tw/install.html @@ -1,8 +1,8 @@ <p>本頁面旨在幫助您完成第一次安装和設定 <a href="http://dokuwiki.org">Dokuwiki</a>。關於安裝工具的更多訊息請參閱 <a href="http://dokuwiki.org/installer">官方文檔頁面</a>。</p> -<p>DokuWiki 使用普通檔案儲存維基頁面以及與頁面相關的訊息(例如:圖像,搜尋索引,修訂記錄等)。為了正常運作,DokuWiki <strong>必須</strong> 擁有針對那些路徑和檔案的寫入權限。本安裝工具無法設定目錄權限,這通常要透過命令行、FTP 或您主機上的控制台(如cPanel)進行。</p> +<p>DokuWiki 使用普通檔案來儲存 wiki 頁面,以及與頁面相關的訊息(例如:圖像、搜尋索引、修訂記錄等)。為了正常運作,DokuWiki <strong>必須</strong> 擁有針對那些路徑和檔案的寫入權限。本安裝工具無法設定目錄權限,這通常要透過命令行、FTP 或您主機上的控制台(如cPanel)進行。</p> -<p>本安裝工具將設定您的 DokuWiki 用於 <abbr title="訪問控制列表">ACL</abbr> 的設定檔,它能讓管理員登入並使用「管理」功能來安裝插件、管理用户、管理訪問權限和其他設定設定。它並不是 DokuWiki 正常運作所必須,但安裝之後將更方便管理。</p> +<p>本安裝工具將設定您的 DokuWiki 用於 <abbr title="訪問控制列表">ACL</abbr> 的設定檔,它能讓管理員登入並使用「管理」功能來安裝附加元件、管理使用者、管理訪問權限和其他設定設定。它並不是 DokuWiki 正常運作所必須,但安裝之後將更方便管理。</p> -<p>有經驗的用戶或有特殊需求的用戶請參閱更詳細的 <a href="http://dokuwiki.org/install">安裝指南</a> +<p>有經驗的或有特殊需求的使用者,請參閱更詳細的 <a href="http://dokuwiki.org/install">安裝指南</a> 和 <a href="http://dokuwiki.org/config">設定</a>。</p>
\ No newline at end of file diff --git a/inc/lang/zh-tw/lang.php b/inc/lang/zh-tw/lang.php index 9f380acb5..ddb35617e 100644 --- a/inc/lang/zh-tw/lang.php +++ b/inc/lang/zh-tw/lang.php @@ -11,6 +11,7 @@ * @author Danny Lin * @author Shuo-Ting Jian <shoting@gmail.com> * @author syaoranhinata@gmail.com + * @author Ichirou Uchiki <syaoranhinata@gmail.com> */ $lang['encoding'] = 'utf-8'; $lang['direction'] = 'ltr'; @@ -19,7 +20,7 @@ $lang['doublequoteclosing'] = '”'; $lang['singlequoteopening'] = '‘'; $lang['singlequoteclosing'] = '’'; $lang['apostrophe'] = '’'; -$lang['btn_edit'] = '編修本頁'; +$lang['btn_edit'] = '編輯本頁'; $lang['btn_source'] = '顯示原始碼'; $lang['btn_show'] = '顯示頁面'; $lang['btn_create'] = '建立此頁'; @@ -34,7 +35,7 @@ $lang['btn_recent'] = '最近更新'; $lang['btn_upload'] = '上傳'; $lang['btn_cancel'] = '取消'; $lang['btn_index'] = '站台地圖'; -$lang['btn_secedit'] = '改這段'; +$lang['btn_secedit'] = '編輯此段'; $lang['btn_login'] = '登入'; $lang['btn_logout'] = '登出'; $lang['btn_admin'] = '管理選單'; @@ -61,40 +62,40 @@ $lang['newpass'] = '新密碼'; $lang['oldpass'] = '目前密碼'; $lang['passchk'] = '確認密碼'; $lang['remember'] = '記住帳號密碼'; -$lang['fullname'] = '真實姓名'; +$lang['fullname'] = '姓名'; $lang['email'] = '電郵'; $lang['profile'] = '使用者個人資料'; $lang['badlogin'] = '很抱歉,您的使用者名稱或密碼可能有錯誤。'; $lang['minoredit'] = '小修改'; $lang['draftdate'] = '草稿已自動存檔於'; -$lang['nosecedit'] = '頁面在這之間已被修改,過時的區段資料已載入全頁取代。'; +$lang['nosecedit'] = '在您編輯期間,其他使用者修改過本頁面。區段資料已逾時,因此系統載入了全頁,以取代之。'; $lang['regmissing'] = '很抱歉,所有欄位都要填寫。'; -$lang['reguexists'] = '很抱歉,本帳號已被註冊。'; -$lang['regsuccess'] = '使用者已建立,密碼已寄發至該 email。'; -$lang['regsuccess2'] = '使用者已建立。'; +$lang['reguexists'] = '很抱歉,有人已使用了這個帳號。'; +$lang['regsuccess'] = '使用者帳號已建立,密碼已寄發至該電郵。'; +$lang['regsuccess2'] = '使用者帳號已建立。'; $lang['regmailfail'] = '寄出密碼信似乎發生錯誤,請跟管理員聯絡!'; -$lang['regbadmail'] = '您輸入的 email 似乎不對,如果您認為是正確的,請與管理員聯絡。'; +$lang['regbadmail'] = '您輸入的電郵似乎不對,如果您認為是正確的,請與管理員聯絡。'; $lang['regbadpass'] = '兩次輸入的密碼不一致,請再試一次。'; $lang['regpwmail'] = '您的 DokuWiki 帳號密碼'; $lang['reghere'] = '您還沒有帳號嗎?註冊一個吧。'; -$lang['profna'] = '本維基不開放修改個人資料。'; -$lang['profnochange'] = '未做任何變更。'; +$lang['profna'] = '在本 wiki 上,不能修改個人資料。'; +$lang['profnochange'] = '並未作任何變更。'; $lang['profnoempty'] = '帳號或電郵地址不可空白!'; -$lang['profchanged'] = '個人資料已成功更新。'; +$lang['profchanged'] = '個人資料已更新。'; $lang['pwdforget'] = '忘記密碼了?索取新密碼!'; -$lang['resendna'] = '本維基不開放重寄密碼。'; +$lang['resendna'] = '本 wiki 並不支援重寄密碼。'; $lang['resendpwd'] = '設定新密碼供'; $lang['resendpwdmissing'] = '抱歉,您必須填寫所有欄位。'; $lang['resendpwdnouser'] = '抱歉,資料庫內找不到這個使用者。'; $lang['resendpwdbadauth'] = '抱歉,認證碼無效。請確認您使用了完整的確認連結。'; $lang['resendpwdconfirm'] = '確認連結已通過郵件發送給您了。'; $lang['resendpwdsuccess'] = '您的新密碼已寄出。'; -$lang['license'] = '若未特別註明,此維基上的內容都是採用以下授權方式:'; +$lang['license'] = '若無特別註明,本 wiki 上的內容都是採用以下授權方式:'; $lang['licenseok'] = '注意:編輯此頁面表示您已同意以下的授權方式:'; $lang['searchmedia'] = '搜尋檔名:'; $lang['searchmedia_in'] = '在 %s 裏搜尋'; $lang['txt_upload'] = '請選擇要上傳的檔案'; -$lang['txt_filename'] = '請輸入要存在維基內的檔案名稱 (非必要)'; +$lang['txt_filename'] = '請輸入要上傳至本 wiki 的檔案名稱 (非必要)'; $lang['txt_overwrt'] = '是否要覆蓋原有檔案'; $lang['maxuploadsize'] = '每個上傳檔案不可大於 %s 。'; $lang['lockedby'] = '目前已被下列人員鎖定'; @@ -135,7 +136,7 @@ $lang['js']['media_diff'] = '檢視差異:'; $lang['js']['media_diff_both'] = '並排'; $lang['js']['media_diff_opacity'] = '重疊'; $lang['js']['media_diff_portions'] = '滑動'; -$lang['js']['media_select'] = '選擇檔案…'; +$lang['js']['media_select'] = '選擇檔案……'; $lang['js']['media_upload_btn'] = '上傳'; $lang['js']['media_done_btn'] = '完成'; $lang['js']['media_drop'] = '拖拉檔案到此上傳'; @@ -145,27 +146,27 @@ $lang['rssfailed'] = '擷取 RSS 饋送檔時發生錯誤:'; $lang['nothingfound'] = '沒找到任何結果。'; $lang['mediaselect'] = '媒體檔案'; $lang['fileupload'] = '上傳媒體檔案'; -$lang['uploadsucc'] = '上傳成功'; -$lang['uploadfail'] = '上傳失敗。似乎是權限錯誤?'; +$lang['uploadsucc'] = '已上傳'; +$lang['uploadfail'] = '無法上傳。是否因權限錯誤?'; $lang['uploadwrong'] = '拒絕上傳。這個副檔名被禁止了!'; $lang['uploadexist'] = '檔案已存在,未處理。'; $lang['uploadbadcontent'] = '上傳檔案的內容不符合 %s 檔的副檔名。'; -$lang['uploadspam'] = '這次的上傳被垃圾訊息黑名單阻檔了。'; -$lang['uploadxss'] = '這次的上傳因可能的惡意的內容而被阻檔。'; -$lang['uploadsize'] = '上傳的檔案太大了 (最大:%s)'; +$lang['uploadspam'] = '是次上傳被垃圾訊息黑名單阻檔了。'; +$lang['uploadxss'] = '因可能含有惡意內容,是次上傳已被阻檔。'; +$lang['uploadsize'] = '上傳的檔案太大了 (最大為:%s)'; $lang['deletesucc'] = '檔案 "%s" 已刪除。'; $lang['deletefail'] = '檔案 "%s" 無法刪除,請檢查權限定。'; -$lang['mediainuse'] = '檔案 "%s" 未刪除,因為它正被使用。'; -$lang['namespaces'] = '分類空間'; +$lang['mediainuse'] = '檔案 "%s" 仍在使用,並未刪除。'; +$lang['namespaces'] = '分類名稱'; $lang['mediafiles'] = '可用的檔案有'; $lang['accessdenied'] = '您不可以檢視此頁面。'; $lang['mediausage'] = '使用以下的語法來連結此檔案:'; $lang['mediaview'] = '檢視原始檔案'; $lang['mediaroot'] = 'root'; -$lang['mediaupload'] = '上傳檔案至目前的分類空間。要建立子分類空間,將其名稱加在「上傳並重命名為」檔案名的前面,並用英文冒號隔開。'; +$lang['mediaupload'] = '上傳檔案至目前分類名稱之下。要建立子分類名稱,請將其名稱加在「上傳並重命名為」檔案名的前面,並用英文冒號隔開。'; $lang['mediaextchange'] = '檔案類型已由 .%s 變更為 .%s !'; $lang['reference'] = '引用到本頁的,合計有'; -$lang['ref_inuse'] = '此檔案無法刪除,因為它正被以下頁面使用:'; +$lang['ref_inuse'] = '此檔案無法刪除,因以下頁面正在使用它:'; $lang['ref_hidden'] = '一些參考內容位於您沒有讀取權限的頁面中'; $lang['hits'] = '個符合'; $lang['quickhits'] = '符合的頁面名稱'; @@ -175,12 +176,12 @@ $lang['yours'] = '您的版本'; $lang['diff'] = '顯示與目前版本的差異'; $lang['diff2'] = '顯示選擇版本間的差異'; $lang['difflink'] = '連向這個比對檢視'; -$lang['diff_type'] = '檢視差異:'; +$lang['diff_type'] = '檢視差異:'; $lang['diff_inline'] = '行內'; $lang['diff_side'] = '並排'; $lang['line'] = '行'; $lang['breadcrumb'] = '足跡'; -$lang['youarehere'] = '您在這裡'; +$lang['youarehere'] = '您在這裏'; $lang['lastmod'] = '上一次變更'; $lang['by'] = '由'; $lang['deleted'] = '移除'; @@ -188,17 +189,17 @@ $lang['created'] = '建立'; $lang['restored'] = '恢復為舊版'; $lang['external_edit'] = '外部編輯'; $lang['summary'] = '編輯摘要'; -$lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>'; +$lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 附加元件</a>。'; $lang['download'] = '下載程式碼片段'; $lang['tools'] = '工具'; -$lang['user_tools'] = '用戶工具'; +$lang['user_tools'] = '使用者工具'; $lang['site_tools'] = '網站工具'; $lang['page_tools'] = '頁面工具'; $lang['skip_to_content'] = '跳至內容'; $lang['sidebar'] = '側欄'; $lang['mail_newpage'] = '增加的頁面:'; $lang['mail_changed'] = '變更的頁面:'; -$lang['mail_subscribe_list'] = '分類空間中更動的頁面:'; +$lang['mail_subscribe_list'] = '分類名稱中變更的頁面:'; $lang['mail_new_user'] = '新使用者:'; $lang['mail_upload'] = '已上傳檔案:'; $lang['changes_type'] = '檢視最近更新類型'; @@ -229,10 +230,10 @@ $lang['qb_media'] = '加入圖片或檔案'; $lang['qb_sig'] = '插入簽名'; $lang['qb_smileys'] = '表情符號'; $lang['qb_chars'] = '特殊字元'; -$lang['upperns'] = '前往父分類空間'; +$lang['upperns'] = '前往父分類名稱'; $lang['admin_register'] = '新增使用者'; $lang['metaedit'] = '編輯後設資料'; -$lang['metasaveerr'] = '後設資料寫入失敗'; +$lang['metasaveerr'] = '後設資料無法寫入'; $lang['metasaveok'] = '後設資料已儲存'; $lang['img_backto'] = '回上一頁'; $lang['img_title'] = '標題'; @@ -253,9 +254,9 @@ $lang['subscr_subscribe_error'] = '將 %s 加入至 %s 的訂閱列表時發生 $lang['subscr_subscribe_noaddress'] = '沒有與您登入相關的地址,無法將您加入訂閱列表'; $lang['subscr_unsubscribe_success'] = '已將 %s 移除自 %s 的訂閱列表'; $lang['subscr_unsubscribe_error'] = '將 %s 移除自 %s 的訂閱列表時發生錯誤'; -$lang['subscr_already_subscribed'] = '%s 已經被 %s 訂閱了'; -$lang['subscr_not_subscribed'] = '%s 尚未被 %s 訂閱'; -$lang['subscr_m_not_subscribed'] = '您尚未訂閱目前的頁面或分類空間。'; +$lang['subscr_already_subscribed'] = '%s 已經獲 %s 訂閱了'; +$lang['subscr_not_subscribed'] = '%s 尚未獲 %s 訂閱'; +$lang['subscr_m_not_subscribed'] = '您尚未訂閱目前的頁面或分類名稱。'; $lang['subscr_m_new_header'] = '加入訂閱'; $lang['subscr_m_current_header'] = '目前訂閱'; $lang['subscr_m_unsubscribe'] = '取消訂閱'; @@ -264,34 +265,34 @@ $lang['subscr_m_receive'] = '接收'; $lang['subscr_style_every'] = '每次更改都發送信件'; $lang['subscr_style_digest'] = '對每個頁面發送更改的摘要信件 (每 %.2f 天)'; $lang['subscr_style_list'] = '自上次發信以來更改的頁面的列表 (每 %.2f 天)'; -$lang['authmodfailed'] = '帳號認證的設定不正確,請通知該維基管理員。'; -$lang['authtempfail'] = '帳號認證目前暫不提供,若本狀況持續發生的話,請通知該維基管理員。'; +$lang['authmodfailed'] = '帳號認證的設定不正確,請通知該本 wiki 管理員。'; +$lang['authtempfail'] = '帳號認證目前暫不提供。若本狀況持續,請通知本 wiki 管理員。'; $lang['authpwdexpire'] = '您的密碼將在 %d 天內到期,請馬上更換新密碼。'; $lang['i_chooselang'] = '選擇您的語系'; $lang['i_installer'] = 'DokuWiki 安裝工具'; -$lang['i_wikiname'] = '維基名稱'; +$lang['i_wikiname'] = '本 wiki 的名稱'; $lang['i_enableacl'] = '啟用 ACL (建議)'; -$lang['i_superuser'] = '超級用戶'; +$lang['i_superuser'] = '超級使用者'; $lang['i_problems'] = '安裝程式發現如下的問題。您必須修正它們才能繼續。'; $lang['i_modified'] = '出於安全考量,本腳本只能用於安裝全新且未修改的 Dokuwiki。 您可以重新解壓下載的封包或查閱完整的<a href=\"http://dokuwiki.org/install\">Dokuwiki 安裝指南</a>'; $lang['i_funcna'] = 'PHP 函數 <code>%s</code> 無法使用。也許您的主機供應者基於某些理由停用了它?'; $lang['i_phpver'] = '您的 PHP 版本 <code>%s</code> 比需要的版本 <code>%s</code> 還低。您必須更新您的PHP。'; -$lang['i_permfail'] = '<code>%s</code> 無法被 DokuWiki 寫入。您必須修正該目錄的權限!'; +$lang['i_permfail'] = '<code>%s</code> 無法經由 DokuWiki 寫入。您必須修正該目錄的權限!'; $lang['i_confexists'] = '<code>%s</code> 已經存在'; $lang['i_writeerr'] = '無法建立 <code>%s</code>。您必須檢查目錄/檔案的權限並手動建立該檔案。'; -$lang['i_badhash'] = '無法辨識或被變更的 dokuwiki.php (hash=<code>%s</code>)'; -$lang['i_badval'] = '<code>%s</code> - 非法或空白的值'; -$lang['i_success'] = '設定已成功完成。您現在可以刪除 install.php 檔案。繼續到 -<a href="doku.php?id=wiki:welcome">您的新 DokuWiki</a>.'; -$lang['i_failure'] = '寫入設定檔時發生了一些錯誤。您必須在使用<a href="doku.php?id=wiki:welcome">您的新 Dokuwiki</a> 之前手動修正它們。'; +$lang['i_badhash'] = '無法辨識或已遭修改的 dokuwiki.php (hash=<code>%s</code>)'; +$lang['i_badval'] = '<code>%s</code> —— 非法或空白的值'; +$lang['i_success'] = '設定已完成。您現在可以刪除 install.php 檔案。繼續到 +<a href="doku.php">您的新 DokuWiki</a>.'; +$lang['i_failure'] = '寫入設定檔時發生了一些錯誤。您必須在使用<a href="doku.php">您的新 Dokuwiki</a> 之前手動修正它們。'; $lang['i_policy'] = '初步的 ACL 政策'; -$lang['i_pol0'] = '開放的維基 (任何人可讀取、寫入、上傳)'; -$lang['i_pol1'] = '公開的維基 (任何人可讀取,註冊使用者可寫入與上傳)'; -$lang['i_pol2'] = '封閉的維基 (只有註冊使用者可讀取、寫入、上傳)'; +$lang['i_pol0'] = '開放的 wiki (任何人可讀取、寫入、上傳)'; +$lang['i_pol1'] = '公開的 wiki (任何人可讀取,註冊使用者可寫入與上傳)'; +$lang['i_pol2'] = '封閉的 wiki (只有註冊使用者可讀取、寫入、上傳)'; $lang['i_retry'] = '重試'; $lang['i_license'] = '請選擇您想要的內容發布許可協議:'; -$lang['recent_global'] = '您正在閱讀分類空間: <b>%s</b> 中的變更。您亦可觀看整個維基的<a href="%s">最近更新</a>。'; +$lang['recent_global'] = '您正在閱讀分類名稱: <b>%s</b> 中的變更。您亦可觀看本 wiki <a href="%s">所有的最近更新</a>。'; $lang['years'] = '%d 年前'; $lang['months'] = '%d 個月前'; $lang['weeks'] = '%d 週前'; @@ -299,7 +300,7 @@ $lang['days'] = '%d 天前'; $lang['hours'] = '%d 個小時前'; $lang['minutes'] = '%d 分鐘前'; $lang['seconds'] = '%s 秒鐘前'; -$lang['wordblock'] = '您的更改沒有被儲存,因为它包含被阻擋的文字 (垃圾訊息)。'; +$lang['wordblock'] = '無法儲存您的更改,因為它含有受阻擋的文字 (垃圾訊息)。'; $lang['media_uploadtab'] = '上傳'; $lang['media_searchtab'] = '搜尋'; $lang['media_file'] = '檔案'; @@ -310,7 +311,7 @@ $lang['media_list_thumbs'] = '縮圖'; $lang['media_list_rows'] = '列表'; $lang['media_sort_name'] = '名稱'; $lang['media_sort_date'] = '日期'; -$lang['media_namespaces'] = '選擇分類空間'; +$lang['media_namespaces'] = '選擇分類名稱'; $lang['media_files'] = '在 %s 中的檔案'; $lang['media_upload'] = '上傳至 %s'; $lang['media_search'] = '在 %s 中搜尋'; diff --git a/inc/lang/zh-tw/locked.txt b/inc/lang/zh-tw/locked.txt index e13fdc890..819e59e2f 100644 --- a/inc/lang/zh-tw/locked.txt +++ b/inc/lang/zh-tw/locked.txt @@ -1,3 +1,3 @@ ====== 頁面鎖定 ====== -本頁目前正由其他使用者編修中,您必須等他完成編輯或等鎖定時間過去。 +其他使用者正在編輯本頁,您必須等他完成編輯或等鎖定時間過去。 diff --git a/inc/lang/zh-tw/login.txt b/inc/lang/zh-tw/login.txt index 058cc5712..b82f08a20 100644 --- a/inc/lang/zh-tw/login.txt +++ b/inc/lang/zh-tw/login.txt @@ -1,5 +1,4 @@ ====== 登入 ====== -您尚未登入,請輸入您的使用者名稱和密碼。 另外,瀏覽器需要打開 cookies 設定以進行登入。 - +您尚未登入,請輸入您的使用者名稱和密碼。 另外,瀏覽器需要啟用 cookies 以登入本 wiki。 diff --git a/inc/lang/zh-tw/mailtext.txt b/inc/lang/zh-tw/mailtext.txt index 3b6ece377..2a402c2fb 100644 --- a/inc/lang/zh-tw/mailtext.txt +++ b/inc/lang/zh-tw/mailtext.txt @@ -2,7 +2,7 @@ 日期 : @DATE@ 瀏覽器 : @BROWSER@ -IP位址 : @IPADDRESS@ +IP 位址 : @IPADDRESS@ 主機名稱 : @HOSTNAME@ 舊版本 : @OLDPAGE@ 新版本 : @NEWPAGE@ diff --git a/inc/lang/zh-tw/norev.txt b/inc/lang/zh-tw/norev.txt index bd1c7a623..2a32ba6a8 100644 --- a/inc/lang/zh-tw/norev.txt +++ b/inc/lang/zh-tw/norev.txt @@ -1,3 +1,3 @@ ====== 無此版本 ====== -該版本的文件不存在。請用 「舊版」按鈕檢視該文件所有舊版本清單。
\ No newline at end of file +該版本的文件不存在。請用「舊版」按鈕檢視該文件所有舊版本清單。
\ No newline at end of file diff --git a/inc/lang/zh-tw/preview.txt b/inc/lang/zh-tw/preview.txt index c68f94819..95d4b10e1 100644 --- a/inc/lang/zh-tw/preview.txt +++ b/inc/lang/zh-tw/preview.txt @@ -1,4 +1,4 @@ ====== 預覽 ====== -以下是預覽該文件的狀態。請記住:**它還沒被儲存喔**! +以下是該文件的預覽。請記住:**您還未儲存它**! diff --git a/inc/lang/zh-tw/pwconfirm.txt b/inc/lang/zh-tw/pwconfirm.txt index 994367980..fb8a5cb82 100644 --- a/inc/lang/zh-tw/pwconfirm.txt +++ b/inc/lang/zh-tw/pwconfirm.txt @@ -1,13 +1,13 @@ @FULLNAME@ 您好! -有人為您在 @DOKUWIKIURL@ 註冊的使用者 @TITLE@ 請求新密碼 +感謝您在 @TITLE@ ( @DOKUWIKIURL@ ) 註冊了使用者帳號。我們收到請求,希望能允許此帳號使用新密碼。 -如果您沒有請求新密碼,請忽略這封郵件。 +如果您沒有發送此請求,請忽略這封郵件。 -要確認使用新密碼,請拜訪以下的連結。 +若您真的要使用新密碼,請拜訪以下的連結。 @CONFIRM@ -- 本信件由以下 DokuWiki 站台產生: -@DOKUWIKIURL@ +@DOKUWIKIURL@
\ No newline at end of file diff --git a/inc/lang/zh-tw/read.txt b/inc/lang/zh-tw/read.txt index a8305611f..4a472cd0d 100644 --- a/inc/lang/zh-tw/read.txt +++ b/inc/lang/zh-tw/read.txt @@ -1 +1 @@ -本頁是唯讀的,您可以看到原始碼,但不能更動它。您如果覺得這是誤判,請詢問管理員。
\ No newline at end of file +本頁是唯讀的,您可以看到原始碼,但不能更動它。您如果覺得它不應被鎖上,請詢問管理員。
\ No newline at end of file diff --git a/inc/lang/zh-tw/register.txt b/inc/lang/zh-tw/register.txt index 0da401ccd..3ff68dee3 100644 --- a/inc/lang/zh-tw/register.txt +++ b/inc/lang/zh-tw/register.txt @@ -1,4 +1,3 @@ ====== 註冊新使用者 ====== -填寫以下資料以註冊維基帳號,請確定您提供的是**合法的 email 地址**-如果這裡沒要求您填寫密碼,您的新密碼會自動產生並寄送到該地址。登錄名稱必須是合法的[[doku>pagename|頁面名稱]]。 - +若要註冊本 wiki 的帳號,請填寫下列資料。請確定您提供的是**合法的電郵地址**。如果您不必填寫密碼,系統就會為您自動產生登入密碼,並寄送到該電郵地址。登錄名稱須符合正確[[doku>pagename|頁面名稱]]之條件。 diff --git a/inc/lang/zh-tw/registermail.txt b/inc/lang/zh-tw/registermail.txt index 489e3f9d3..fb4951d60 100644 --- a/inc/lang/zh-tw/registermail.txt +++ b/inc/lang/zh-tw/registermail.txt @@ -2,11 +2,11 @@ 帳號 : @NEWUSER@ 姓名 : @NEWNAME@ -E-mail : @NEWEMAIL@ +電郵 : @NEWEMAIL@ 日期 : @DATE@ 瀏覽器 : @BROWSER@ -IP位址 : @IPADDRESS@ +IP 位址 : @IPADDRESS@ 主機名稱 : @HOSTNAME@ -- diff --git a/inc/lang/zh-tw/resendpwd.txt b/inc/lang/zh-tw/resendpwd.txt index 3dbfad750..46078a348 100644 --- a/inc/lang/zh-tw/resendpwd.txt +++ b/inc/lang/zh-tw/resendpwd.txt @@ -1,3 +1,3 @@ ====== 寄送新密碼 ====== -請在以下欄位輸入您的帳號,新密碼將會寄送到您註冊時填寫的 email 地址。 +請在以下欄位輸入您的帳號,新密碼將會寄送到您註冊時填寫的電郵地址。
\ No newline at end of file diff --git a/inc/lang/zh-tw/revisions.txt b/inc/lang/zh-tw/revisions.txt index 479705b95..4818839ac 100644 --- a/inc/lang/zh-tw/revisions.txt +++ b/inc/lang/zh-tw/revisions.txt @@ -1,3 +1,3 @@ ====== 舊版 ====== -以下是該文件的舊版本。如要恢復成某個舊版次,就點下它,然後按「編修本頁」,並存檔起來就可以了。 +以下是該文件的舊版本。如要恢復成某個舊版次,就點下它,然後按「編輯本頁」,並存檔起來就可以了。 diff --git a/inc/lang/zh-tw/stopwords.txt b/inc/lang/zh-tw/stopwords.txt index 55b67ed16..e549250bd 100644 --- a/inc/lang/zh-tw/stopwords.txt +++ b/inc/lang/zh-tw/stopwords.txt @@ -1,9 +1,9 @@ -# 這檔是製作索引檔(index)時不要列入的關鍵字,格式為每字(詞)就使用一行。 -# 在修改時,請注意要用 UNIX 格式的換行符號(newline)處理,而非 DOS 的 CR-LR 喔 -# (如果在 MS Windows 環境使用的話,可使用 vim win32版 或 UltraEdit或其他類似編輯器修改) +# 本清單列出製作索引檔 (index) 時不要列入的關鍵字,格式為每字 (詞) 佔一行。 +# 在修改本清單時,請注意要用 UNIX 格式的換行符號 (newline) 處理,而非 DOS 的 CR-LR 。 +# (如果在 MS Windows 環境使用的話,可使用 vim win32 版、 UltraEdit 或其他類似編輯器修改。) # -# 還有,不必把小於 3 個字元(英數字元)都包括進來。 -# 目前本清單的內容是以 http://www.ranks.nl/stopwords/ 為基礎而發展的。 +# 還有,不必把小於 3 個字元 (英數字元) 都包括進來。 +# 目前本清單的內容是以 http://www.ranks.nl/stopwords/ 為基礎,發展而成的。 about are and diff --git a/inc/lang/zh-tw/subscr_digest.txt b/inc/lang/zh-tw/subscr_digest.txt index a0f2be73e..a17a0551d 100644 --- a/inc/lang/zh-tw/subscr_digest.txt +++ b/inc/lang/zh-tw/subscr_digest.txt @@ -1,6 +1,6 @@ 您好! -維基 @TITLE@ 的頁面 @PAGE@ 已更改。 +本 wiki ( @TITLE@ ) 的頁面 @PAGE@ 已更改。 更改內容如下: -------------------------------------------------------- @@ -10,9 +10,9 @@ 舊版本:@OLDPAGE@ 新版本:@NEWPAGE@ -要取消頁面提醒,請登入維基 @DOKUWIKIURL@ +要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@ 然後拜訪 @SUBSCRIBE@ -並取消訂閱頁面或分類空間的更改。 +並取消訂閱頁面或分類名稱的更改。 -- 本信件由以下 DokuWiki 站台產生: diff --git a/inc/lang/zh-tw/subscr_form.txt b/inc/lang/zh-tw/subscr_form.txt index 394d4cbad..ba3f16113 100644 --- a/inc/lang/zh-tw/subscr_form.txt +++ b/inc/lang/zh-tw/subscr_form.txt @@ -1,3 +1,3 @@ ====== 訂閱管理 ====== -這個頁面允許您管理在目前頁面和分類空間的訂閱。
\ No newline at end of file +在此頁裏,您可以管理在目前頁面及分類名稱之訂閱。
\ No newline at end of file diff --git a/inc/lang/zh-tw/subscr_list.txt b/inc/lang/zh-tw/subscr_list.txt index 078eae63e..ea82dd35d 100644 --- a/inc/lang/zh-tw/subscr_list.txt +++ b/inc/lang/zh-tw/subscr_list.txt @@ -1,15 +1,15 @@ 您好! -維基 @TITLE@ 的 @PAGE@ 分類空間的頁面已更改。 +本 wiki ( @TITLE@ ) 的 @PAGE@ 分類名稱頁面已更改。 更改內容如下: -------------------------------------------------------- @DIFF@ -------------------------------------------------------- -要取消頁面提醒,請登入維基 @DOKUWIKIURL@ +要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@ 然後拜訪 @SUBSCRIBE@ -並取消訂閱頁面或分類空間的更改。 +並取消訂閱頁面或分類名稱的更改。 -- 本信件由以下 DokuWiki 站台產生: diff --git a/inc/lang/zh-tw/subscr_single.txt b/inc/lang/zh-tw/subscr_single.txt index 5128140d0..14d87bb73 100644 --- a/inc/lang/zh-tw/subscr_single.txt +++ b/inc/lang/zh-tw/subscr_single.txt @@ -1,6 +1,6 @@ 您好! -維基 @TITLE@ 的頁面 @PAGE@ 已更改。 +本 wiki ( @TITLE@ ) 的頁面 @PAGE@ 已更改。 更改內容如下: -------------------------------------------------------- @@ -13,9 +13,9 @@ 舊版本 : @OLDPAGE@ 新版本 : @NEWPAGE@ -要取消頁面提醒,請登入維基 @DOKUWIKIURL@ +要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@ 然後拜訪 @NEWPAGE@ -並取消訂閱頁面或分類空間的更改。 +並取消訂閱頁面或分類名稱的更改。 -- 本信件由以下 DokuWiki 站台產生: diff --git a/inc/lang/zh-tw/updateprofile.txt b/inc/lang/zh-tw/updateprofile.txt index 47f2ae1c4..a7a2ad803 100644 --- a/inc/lang/zh-tw/updateprofile.txt +++ b/inc/lang/zh-tw/updateprofile.txt @@ -1,3 +1,3 @@ ====== 更新個人資料 ====== -您只需變更想更新的欄位就好,帳號名稱不能變更。
\ No newline at end of file +您只需修改想更新的欄位就好,帳號名稱不能變更。
\ No newline at end of file diff --git a/inc/lang/zh-tw/uploadmail.txt b/inc/lang/zh-tw/uploadmail.txt index b4c1311ba..87bac7c9a 100644 --- a/inc/lang/zh-tw/uploadmail.txt +++ b/inc/lang/zh-tw/uploadmail.txt @@ -3,7 +3,7 @@ 檔名 : @MEDIA@ 日期 : @DATE@ 瀏覽器 : @BROWSER@ -IP位址 : @IPADDRESS@ +IP 位址 : @IPADDRESS@ 主機名稱 : @HOSTNAME@ 大小 : @SIZE@ MIME類型 : @MIME@ @@ -11,4 +11,4 @@ MIME類型 : @MIME@ -- 本信件由以下 DokuWiki 站台產生: -@DOKUWIKIURL@ +@DOKUWIKIURL@
\ No newline at end of file diff --git a/inc/load.php b/inc/load.php index 49c307054..7fd9fc9d0 100644 --- a/inc/load.php +++ b/inc/load.php @@ -82,6 +82,7 @@ function load_autoload($name){ 'Mailer' => DOKU_INC.'inc/Mailer.class.php', 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', + 'Subscription' => DOKU_INC.'inc/subscription.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/inc/media.php b/inc/media.php index 6335bf210..572b1177c 100644 --- a/inc/media.php +++ b/inc/media.php @@ -535,32 +535,13 @@ function media_contentcheck($file,$mime){ * Send a notify mail on uploads * * @author Andreas Gohr <andi@splitbrain.org> - * @fixme this should embed thumbnails of images in HTML version */ function media_notify($id,$file,$mime,$old_rev=false){ - global $lang; global $conf; - global $INFO; if(empty($conf['notify'])) return; //notify enabled? - $text = rawLocale('uploadmail'); - $trep = array( - 'MIME' => $mime, - 'MEDIA' => ml($id,'',true,'&',true), - 'SIZE' => filesize_h(filesize($file)), - ); - - if ($old_rev && $conf['mediarevisions']) { - $trep['OLD'] = ml($id, "rev=$old_rev", true, '&', true); - } else { - $trep['OLD'] = '---'; - } - - $mail = new Mailer(); - $mail->to($conf['notify']); - $mail->subject($lang['mail_upload'].' '.$id); - $mail->setBody($text,$trep); - return $mail->send(); + $subscription = new Subscription(); + return $subscription->send_media_diff($conf['notify'], 'uploadmail', $id, $old_rev, ''); } /** diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 68b92ca43..71f3aa4bf 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -803,6 +803,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); $link['class'] .= ' mediafile mf_'.$class; $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true); + $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))).')'; } if($hash) $link['url'] .= '#'.$hash; diff --git a/inc/plugin.php b/inc/plugin.php index e4bba989d..153e89407 100644 --- a/inc/plugin.php +++ b/inc/plugin.php @@ -81,8 +81,8 @@ class DokuWiki_Plugin { * retrieve a language dependent file and pass to xhtml renderer for display * plugin equivalent of p_locale_xhtml() * - * @param $id id of language dependent wiki page - * @return string parsed contents of the wiki page in xhtml format + * @param string $id id of language dependent wiki page + * @return string parsed contents of the wiki page in xhtml format */ function locale_xhtml($id) { return p_cached_output($this->localFN($id)); diff --git a/inc/search.php b/inc/search.php index 1cecfd5ec..53bd240e8 100644 --- a/inc/search.php +++ b/inc/search.php @@ -247,11 +247,16 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){ * @author Andreas Gohr <andi@splitbrain.org> */ function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ + if(isset($opts['depth']) && $opts['depth']){ + $parts = explode('/',ltrim($file,'/')); + if(($type == 'd' && count($parts) > $opts['depth']) + || ($type != 'd' && count($parts) > $opts['depth'] + 1)){ + return false; // depth reached + } + } + //we do nothing with directories if($type == 'd'){ - if(!$opts['depth']) return true; // recurse forever - $parts = explode('/',ltrim($file,'/')); - if(count($parts) == $opts['depth']) return false; // depth reached return true; } diff --git a/inc/subscription.php b/inc/subscription.php index 6b201c266..2989de032 100644 --- a/inc/subscription.php +++ b/inc/subscription.php @@ -1,414 +1,697 @@ <?php /** - * Utilities for handling (email) subscriptions - * - * The public interface of this file consists of the functions - * - subscription_find - * - subscription_send_digest - * - subscription_send_list - * - subscription_set - * - get_info_subscribed - * - subscription_addresslist - * - subscription_lock - * - subscription_unlock + * Class for handling (email) subscriptions * * @author Adrian Lang <lang@cosmocode.de> + * @author Andreas Gohr <andi@splitbrain.org> * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) */ +class Subscription { -/** - * Get the name of the metafile tracking subscriptions to target page or - * namespace - * - * @author Adrian Lang <lang@cosmocode.de> - * - * @param string $id The target page or namespace, specified by id; Namespaces - * are identified by appending a colon. - * @return string - */ -function subscription_filename($id) { - $meta_fname = '.mlist'; - if ((substr($id, -1, 1) === ':')) { - $meta_froot = getNS($id); - $meta_fname = '/' . $meta_fname; - } else { - $meta_froot = $id; + /** + * Check if subscription system is enabled + * + * @return bool + */ + public function isenabled() { + return actionOK('subscribe'); } - return metaFN((string) $meta_froot, $meta_fname); -} -/** - * Lock subscription info for an ID - * - * @author Adrian Lang <lang@cosmocode.de> - * @param string $id The target page or namespace, specified by id; Namespaces - * are identified by appending a colon. - * @return string - */ -function subscription_lock_filename ($id){ - global $conf; - return $conf['lockdir'].'/_subscr_' . md5($id) . '.lock'; -} + /** + * Return the subscription meta file for the given ID + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * @return string + */ + protected function file($id) { + $meta_fname = '.mlist'; + if((substr($id, -1, 1) === ':')) { + $meta_froot = getNS($id); + $meta_fname = '/'.$meta_fname; + } else { + $meta_froot = $id; + } + return metaFN((string) $meta_froot, $meta_fname); + } -/** - * Creates a lock file for writing subscription data - * - * @todo add lock time parameter to io_lock() and use this instead - * @param $id - * @return bool - */ -function subscription_lock($id) { - global $conf; - $lock = subscription_lock_filename($id); + /** + * Lock subscription info + * + * We don't use io_lock() her because we do not wait for the lock and use a larger stale time + * + * @author Adrian Lang <lang@cosmocode.de> + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * @return bool true, if you got a succesful lock + */ + protected function lock($id) { + global $conf; + + $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock'; + + if(is_dir($lock) && time() - @filemtime($lock) > 60 * 5) { + // looks like a stale lock - remove it + @rmdir($lock); + } + + // try creating the lock directory + if(!@mkdir($lock, $conf['dmode'])) { + return false; + } - if (is_dir($lock) && time()-@filemtime($lock) > 60*5) { - // looks like a stale lock - remove it - @rmdir($lock); + if($conf['dperm']) chmod($lock, $conf['dperm']); + return true; } - // try creating the lock directory - if (!@mkdir($lock,$conf['dmode'])) { - return false; + /** + * Unlock subscription info + * + * @author Adrian Lang <lang@cosmocode.de> + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * @return bool + */ + protected function unlock($id) { + global $conf; + $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock'; + return @rmdir($lock); } - if($conf['dperm']) chmod($lock, $conf['dperm']); - return true; -} + /** + * Construct a regular expression for parsing a subscription definition line + * + * @author Andreas Gohr <andi@splitbrain.org> + * + * @param string|array $user + * @param string|array $style + * @param string|array $data + * @return string complete regexp including delimiters + * @throws Exception when no data is passed + */ + protected function buildregex($user = null, $style = null, $data = null) { + // always work with arrays + $user = (array) $user; + $style = (array) $style; + $data = (array) $data; -/** - * Unlock subscription info for an ID - * - * @author Adrian Lang <lang@cosmocode.de> - * @param string $id The target page or namespace, specified by id; Namespaces - * are identified by appending a colon. - * @return bool - */ -function subscription_unlock($id) { - $lockf = subscription_lock_filename($id); - return @rmdir($lockf); -} + // clean + $user = array_filter(array_map('trim', $user)); + $style = array_filter(array_map('trim', $style)); + $data = array_filter(array_map('trim', $data)); -/** - * Set subscription information - * - * Allows to set subscription information for permanent storage in meta files. - * Subscriptions consist of a target object, a subscribing user, a subscribe - * style and optional data. - * A subscription may be deleted by specifying an empty subscribe style. - * Only one subscription per target and user is allowed. - * The function returns false on error, otherwise true. Note that no error is - * returned if a subscription should be deleted but the user is not subscribed - * and the subscription meta file exists. - * - * @author Adrian Lang <lang@cosmocode.de> - * - * @param string $user The subscriber or unsubscriber - * @param string $page The target object (page or namespace), specified by - * id; Namespaces are identified by a trailing colon. - * @param string $style The subscribe style; DokuWiki currently implements - * “every”, “digest”, and “list”. - * @param string $data An optional data blob - * @param bool $overwrite Whether an existing subscription may be overwritten - * @return bool - */ -function subscription_set($user, $page, $style, $data = null, - $overwrite = false) { - global $lang; - if (is_null($style)) { - // Delete subscription. - $file = subscription_filename($page); - if (!@file_exists($file)) { - msg(sprintf($lang['subscr_not_subscribed'], $user, - prettyprint_id($page)), -1); - return false; + // user names are encoded + $user = array_map('auth_nameencode', $user); + + // quote + $user = array_map('preg_quote_cb', $user); + $style = array_map('preg_quote_cb', $style); + $data = array_map('preg_quote_cb', $data); + + // join + $user = join('|', $user); + $style = join('|', $style); + $data = join('|', $data); + + // any data at all? + if($user.$style.$data === '') throw new Exception('no data passed'); + + // replace empty values, set which ones are optional + $sopt = ''; + $dopt = ''; + if($user === '') { + $user = '\S+'; + } + if($style === '') { + $style = '\S+'; + $sopt = '?'; + } + if($data === '') { + $data = '\S+'; + $dopt = '?'; } - // io_deleteFromFile does not return false if no line matched. - return io_deleteFromFile($file, - subscription_regex(array('user' => auth_nameencode($user))), - true); + // assemble + return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/"; } - // Delete subscription if one exists and $overwrite is true. If $overwrite - // is false, fail. - $subs = subscription_find($page, array('user' => $user)); - if (count($subs) > 0 && isset($subs[$page])) { - if (!$overwrite) { - msg(sprintf($lang['subscr_already_subscribed'], $user, - prettyprint_id($page)), -1); - return false; - } - // Fail if deletion failed, else continue. - if (!subscription_set($user, $page, null)) { - return false; + /** + * Recursively search for matching subscriptions + * + * This function searches all relevant subscription files for a page or + * namespace. + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $page The target object’s (namespace or page) id + * @param string|array $user + * @param string|array $style + * @param string|array $data + * @return array + */ + public function subscribers($page, $user = null, $style = null, $data = null) { + if(!$this->isenabled()) return array(); + + // Construct list of files which may contain relevant subscriptions. + $files = array(':' => $this->file(':')); + do { + $files[$page] = $this->file($page); + $page = getNS(rtrim($page, ':')).':'; + } while($page !== ':'); + + $re = $this->buildregex($user, $style, $data); + + // Handle files. + $result = array(); + foreach($files as $target => $file) { + if(!@file_exists($file)) continue; + + $lines = file($file); + foreach($lines as $line) { + // fix old style subscription files + if(strpos($line, ' ') === false) $line = trim($line)." every\n"; + + // check for matching entries + if(!preg_match($re, $line, $m)) continue; + + $u = rawurldecode($m[1]); // decode the user name + if(!isset($result[$target])) $result[$target] = array(); + $result[$target][$u] = array($m[2], $m[3]); // add to result + } } + return array_reverse($result); } - $file = subscription_filename($page); - $content = auth_nameencode($user) . ' ' . $style; - if (!is_null($data)) { - $content .= ' ' . $data; + /** + * Adds a new subscription for the given page or namespace + * + * This will automatically overwrite any existent subscription for the given user on this + * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces. + * + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * @param string $user + * @param string $style + * @param string $data + * @throws Exception when user or style is empty + * @return bool + */ + public function add($id, $user, $style, $data = '') { + if(!$this->isenabled()) return false; + + // delete any existing subscription + $this->remove($id, $user); + + $user = auth_nameencode(trim($user)); + $style = trim($style); + $data = trim($data); + + if(!$user) throw new Exception('no subscription user given'); + if(!$style) throw new Exception('no subscription style given'); + if(!$data) $data = time(); //always add current time for new subscriptions + + $line = "$user $style $data\n"; + $file = $this->file($id); + return io_saveFile($file, $line, true); } - return io_saveFile($file, $content . "\n", true); -} -/** - * Recursively search for matching subscriptions - * - * This function searches all relevant subscription files for a page or - * namespace. - * - * @author Adrian Lang <lang@cosmocode.de> - * @see function subscription_regex for $pre documentation - * - * @param string $page The target object’s (namespace or page) id - * @param array $pre A hash of predefined values - * @return array - */ -function subscription_find($page, $pre) { - // Construct list of files which may contain relevant subscriptions. - $filenames = array(':' => subscription_filename(':')); - do { - $filenames[$page] = subscription_filename($page); - $page = getNS(rtrim($page, ':')) . ':'; - } while ($page !== ':'); - - // Handle files. - $matches = array(); - foreach ($filenames as $cur_page => $filename) { - if (!@file_exists($filename)) { - continue; + /** + * Removes a subscription for the given page or namespace + * + * This removes all subscriptions matching the given criteria on the given page or + * namespace. It will *not* modify any subscriptions that may exist in higher + * namespaces. + * + * @param string $id The target object’s (namespace or page) id + * @param string|array $user + * @param string|array $style + * @param string|array $data + * @return bool + */ + public function remove($id, $user = null, $style = null, $data = null) { + if(!$this->isenabled()) return false; + + $file = $this->file($id); + if(!file_exists($file)) return true; + + $re = $this->buildregex($user, $style, $data); + return io_deleteFromFile($file, $re, true); + } + + /** + * Get data for $INFO['subscribed'] + * + * $INFO['subscribed'] is either false if no subscription for the current page + * and user is in effect. Else it contains an array of arrays with the fields + * “target”, “style”, and optionally “data”. + * + * @param string $id Page ID, defaults to global $ID + * @param string $user User, defaults to $_SERVER['REMOTE_USER'] + * @return array + * @author Adrian Lang <lang@cosmocode.de> + */ + function user_subscription($id = '', $user = '') { + if(!$this->isenabled()) return false; + + global $ID; + if(!$id) $id = $ID; + if(!$user) $user = $_SERVER['REMOTE_USER']; + + $subs = $this->subscribers($id, $user); + if(!count($subs)) return false; + + $result = array(); + foreach($subs as $target => $info) { + $result[] = array( + 'target' => $target, + 'style' => $info[$user][0], + 'data' => $info[$user][1] + ); } - $subscriptions = file($filename); - foreach ($subscriptions as $subscription) { - if (strpos($subscription, ' ') === false) { - // This is an old subscription file. - $subscription = trim($subscription) . " every\n"; - } - list($user, $rest) = explode(' ', $subscription, 2); - $subscription = rawurldecode($user) . " " . $rest; + return $result; + } - if (preg_match(subscription_regex($pre), $subscription, - $line_matches) === 0) { - continue; - } - $match = array_slice($line_matches, 1); - if (!isset($matches[$cur_page])) { - $matches[$cur_page] = array(); + /** + * Send digest and list subscriptions + * + * This sends mails to all subscribers that have a subscription for namespaces above + * the given page if the needed $conf['subscribe_time'] has passed already. + * + * This function is called form lib/exe/indexer.php + * + * @param string $page + * @return int number of sent mails + */ + public function send_bulk($page) { + if(!$this->isenabled()) return 0; + + /** @var auth_basic $auth */ + global $auth; + global $conf; + global $USERINFO; + $count = 0; + + $subscriptions = $this->subscribers($page, null, array('digest', 'list')); + + // remember current user info + $olduinfo = $USERINFO; + $olduser = $_SERVER['REMOTE_USER']; + + foreach($subscriptions as $target => $users) { + if(!$this->lock($target)) continue; + + foreach($users as $user => $info) { + list($style, $lastupdate) = $info; + + $lastupdate = (int) $lastupdate; + if($lastupdate + $conf['subscribe_time'] > time()) { + // Less than the configured time period passed since last + // update. + continue; + } + + // Work as the user to make sure ACLs apply correctly + $USERINFO = $auth->getUserData($user); + $_SERVER['REMOTE_USER'] = $user; + if($USERINFO === false) continue; + if(!$USERINFO['mail']) continue; + + if(substr($target, -1, 1) === ':') { + // subscription target is a namespace, get all changes within + $changes = getRecentsSince($lastupdate, null, getNS($target)); + } else { + // single page subscription, check ACL ourselves + if(auth_quickaclcheck($target) < AUTH_READ) continue; + $meta = p_get_metadata($target); + $changes = array($meta['last_change']); + } + + // Filter out pages only changed in small and own edits + $change_ids = array(); + foreach($changes as $rev) { + $n = 0; + while(!is_null($rev) && $rev['date'] >= $lastupdate && + ($_SERVER['REMOTE_USER'] === $rev['user'] || + $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) { + $rev = getRevisions($rev['id'], $n++, 1); + $rev = (count($rev) > 0) ? $rev[0] : null; + } + + if(!is_null($rev) && $rev['date'] >= $lastupdate) { + // Some change was not a minor one and not by myself + $change_ids[] = $rev['id']; + } + } + + // send it + if($style === 'digest') { + foreach($change_ids as $change_id) { + $this->send_digest( + $USERINFO['mail'], $change_id, + $lastupdate + ); + $count++; + } + } elseif($style === 'list') { + $this->send_list($USERINFO['mail'], $change_ids, $target); + $count++; + } + // TODO: Handle duplicate subscriptions. + + // Update notification time. + $this->add($target, $user, $style, time()); } - $matches[$cur_page][] = $match; + $this->unlock($target); } - } - return array_reverse($matches); -} -/** - * Get data for $INFO['subscribed'] - * - * $INFO['subscribed'] is either false if no subscription for the current page - * and user is in effect. Else it contains an array of arrays with the fields - * “target”, “style”, and optionally “data”. - * - * @author Adrian Lang <lang@cosmocode.de> - */ -function get_info_subscribed() { - global $ID; - global $conf; - if (!$conf['subscribers']) { - return false; + // restore current user info + $USERINFO = $olduinfo; + $_SERVER['REMOTE_USER'] = $olduser; + return $count; } - $subs = subscription_find($ID, array('user' => $_SERVER['REMOTE_USER'])); - if (count($subs) === 0) { - return false; + /** + * Send the diff for some page change + * + * @param string $subscriber_mail The target mail address + * @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...) + * @param string $id Page for which the notification is + * @param int|null $rev Old revision if any + * @param string $summary Change summary if any + * @return bool true if successfully sent + */ + public function send_diff($subscriber_mail, $template, $id, $rev = null, $summary = '') { + global $DIFF_INLINESTYLES; + + // prepare replacements (keys not set in hrep will be taken from trep) + $trep = array( + 'PAGE' => $id, + 'NEWPAGE' => wl($id, '', true, '&'), + 'SUMMARY' => $summary, + 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&') + ); + $hrep = array(); + + if($rev) { + $subject = 'changed'; + $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&'); + + $old_content = rawWiki($id, $rev); + $new_content = rawWiki($id); + + $df = new Diff(explode("\n", $old_content), + explode("\n", $new_content)); + $dformat = new UnifiedDiffFormatter(); + $tdiff = $dformat->format($df); + + $DIFF_INLINESTYLES = true; + $df = new Diff(explode("\n", hsc($old_content)), + explode("\n", hsc($new_content))); + $dformat = new InlineDiffFormatter(); + $hdiff = $dformat->format($df); + $hdiff = '<table>'.$hdiff.'</table>'; + $DIFF_INLINESTYLES = false; + } else { + $subject = 'newpage'; + $trep['OLDPAGE'] = '---'; + $tdiff = rawWiki($id); + $hdiff = nl2br(hsc($tdiff)); + } + + $trep['DIFF'] = $tdiff; + $hrep['DIFF'] = $hdiff; + + $headers = array('Message-Id' => $this->getMessageID($id)); + if ($rev) { + $headers['In-Reply-To'] = $this->getMessageID($id, $rev); + } + + return $this->send( + $subscriber_mail, $subject, $id, + $template, $trep, $hrep, $headers + ); } - $_ret = array(); - foreach ($subs as $target => $subs_data) { - $new = array('target' => $target, - 'style' => $subs_data[0][0]); - if (count($subs_data[0]) > 1) { - $new['data'] = $subs_data[0][1]; + /** + * Send the diff for some media change + * + * @fixme this should embed thumbnails of images in HTML version + * @param string $subscriber_mail The target mail address + * @param string $template Mail template ('uploadmail', ...) + * @param string $id Media file for which the notification is + * @param int|bool $rev Old revision if any + * @return bool true if successfully sent + */ + public function send_media_diff($subscriber_mail, $template, $id, $rev = false) { + global $conf; + + $file = mediaFN($id); + list($mime, $ext) = mimetype($id); + + $trep = array( + 'MIME' => $mime, + 'MEDIA' => ml($id,'',true,'&',true), + 'SIZE' => filesize_h(filesize($file)), + ); + + if ($rev && $conf['mediarevisions']) { + $trep['OLD'] = ml($id, "rev=$rev", true, '&', true); + } else { + $trep['OLD'] = '---'; + } + + $headers = array('Message-Id' => $this->getMessageID($id, @filemtime($file))); + if ($rev) { + $headers['In-Reply-To'] = $this->getMessageID($id, $rev); } - $_ret[] = $new; + + $this->send($subscriber_mail, 'upload', $id, $template, $trep, null, $headers); + } - return $_ret; -} + /** + * Send a notify mail on new registration + * + * @author Andreas Gohr <andi@splitbrain.org> + * + * @param string $login login name of the new user + * @param string $fullname full name of the new user + * @param string $email email address of the new user + * @return bool true if a mail was sent + */ + public function send_register($login, $fullname, $email) { + global $conf; + if(empty($conf['registernotify'])) return false; -/** - * Construct a regular expression parsing a subscription definition line - * - * @author Adrian Lang <lang@cosmocode.de> - * - * @param array $pre A hash of predefined values; “user”, “style”, and - * “data” may be set to limit the results to - * subscriptions matching these parameters. If - * “escaped” is true, these fields are inserted into the - * regular expression without escaping. - * - * @return string complete regexp including delimiters - */ -function subscription_regex($pre = array()) { - if (!isset($pre['escaped']) || $pre['escaped'] === false) { - $pre = array_map('preg_quote_cb', $pre); + $trep = array( + 'NEWUSER' => $login, + 'NEWNAME' => $fullname, + 'NEWEMAIL' => $email, + ); + + return $this->send( + $conf['registernotify'], + 'new_user', + $login, + 'registermail', + $trep + ); } - foreach (array('user', 'style', 'data') as $key) { - if (!isset($pre[$key])) { - $pre[$key] = '(\S+)'; + + /** + * Send a digest mail + * + * Sends a digest mail showing a bunch of changes of a single page. Basically the same as send_diff() + * but determines the last known revision first + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $subscriber_mail The target mail address + * @param array $id The ID + * @param int $lastupdate Time of the last notification + * @return bool + */ + protected function send_digest($subscriber_mail, $id, $lastupdate) { + $n = 0; + do { + $rev = getRevisions($id, $n++, 1); + $rev = (count($rev) > 0) ? $rev[0] : null; + } while(!is_null($rev) && $rev > $lastupdate); + + return $this->send_diff( + $subscriber_mail, + 'subscr_digest', + $id, $rev + ); + } + + /** + * Send a list mail + * + * Sends a list mail showing a list of changed pages. + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $subscriber_mail The target mail address + * @param array $ids Array of ids + * @param string $ns_id The id of the namespace + * @return bool true if a mail was sent + */ + protected function send_list($subscriber_mail, $ids, $ns_id) { + if(count($ids) === 0) return false; + + $tlist = ''; + $hlist = '<ul>'; + foreach($ids as $id) { + $link = wl($id, array(), true); + $tlist .= '* '.$link.NL; + $hlist .= '<li><a href="'.$link.'">'.hsc($id).'</a></li>'.NL; } + $hlist .= '</ul>'; + + $id = prettyprint_id($ns_id); + $trep = array( + 'DIFF' => rtrim($tlist), + 'PAGE' => $id, + 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&') + ); + $hrep = array( + 'DIFF' => $hlist + ); + + return $this->send( + $subscriber_mail, + 'subscribe_list', + $ns_id, + 'subscr_list', $trep, $hrep + ); } - return '/^' . $pre['user'] . '(?: ' . $pre['style'] . - '(?: ' . $pre['data'] . ')?)?$/'; -} -/** - * Return a string with the email addresses of all the - * users subscribed to a page - * - * This is the default action for COMMON_NOTIFY_ADDRESSLIST. - * - * @author Steven Danz <steven-danz@kc.rr.com> - * @author Adrian Lang <lang@cosmocode.de> - * - * @todo this does NOT return a string but uses a reference to write back, either fix function or docs - * @param array $data Containing $id (the page id), $self (whether the author - * should be notified, $addresslist (current email address - * list) - * @return string - */ -function subscription_addresslist(&$data){ - global $conf; - /** @var auth_basic $auth */ - global $auth; + /** + * Helper function for sending a mail + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $subscriber_mail The target mail address + * @param string $subject The lang id of the mail subject (without the + * prefix “mail_”) + * @param string $context The context of this mail, eg. page or namespace id + * @param string $template The name of the mail template + * @param array $trep Predefined parameters used to parse the + * template (in text format) + * @param array $hrep Predefined parameters used to parse the + * template (in HTML format), null to default to $trep + * @param array $headers Additional mail headers in the form 'name' => 'value' + * @return bool + */ + protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null, $headers = array()) { + global $lang; + global $conf; + + $text = rawLocale($template); + $subject = $lang['mail_'.$subject].' '.$context; + $mail = new Mailer(); + $mail->bcc($subscriber_mail); + $mail->subject($subject); + $mail->setBody($text, $trep, $hrep); + if(in_array($template, array('subscr_list', 'subscr_digest'))){ + $mail->from($conf['mailfromnobody']); + } + if(isset($trep['SUBSCRIBE'])) { + $mail->setHeader('List-Unsubscribe', '<'.$trep['SUBSCRIBE'].'>', false); + } - $id = $data['id']; - $self = $data['self']; - $addresslist = $data['addresslist']; + foreach ($headers as $header => $value) { + $mail->setHeader($header, $value); + } - if (!$conf['subscribers'] || $auth === null) { - return ''; + return $mail->send(); } - $pres = array('style' => 'every', 'escaped' => true); - if (!$self && isset($_SERVER['REMOTE_USER'])) { - $pres['user'] = '((?!' . preg_quote_cb($_SERVER['REMOTE_USER']) . - '(?: |$))\S+)'; + + /** + * Get a valid message id for a certain $id and revision (or the current revision) + * @param string $id The id of the page (or media file) the message id should be for + * @param string $rev The revision of the page, set to the current revision of the page $id if not set + * @return string + */ + protected function getMessageID($id, $rev = NULL) { + static $listid = null; + if (is_null($listid)) { + $server = parse_url(DOKU_URL, PHP_URL_HOST); + $listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server; + $listid = urlencode($listid); + $listid = strtolower(trim($listid, '.')); + } + + if (is_null($rev)) { + $rev = @filemtime(wikiFN($id)); + } + + return "<$id?rev=$rev@$listid>"; } - $subs = subscription_find($id, $pres); - $emails = array(); - foreach ($subs as $by_targets) { - foreach ($by_targets as $sub) { - $info = $auth->getUserData($sub[0]); - if ($info === false) continue; - $level = auth_aclcheck($id, $sub[0], $info['grps']); - if ($level >= AUTH_READ) { - if (strcasecmp($info['mail'], $conf['notify']) != 0) { - $emails[$sub[0]] = $info['mail']; + + /** + * Default callback for COMMON_NOTIFY_ADDRESSLIST + * + * Aggregates all email addresses of user who have subscribed the given page with 'every' style + * + * @author Steven Danz <steven-danz@kc.rr.com> + * @author Adrian Lang <lang@cosmocode.de> + * + * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead, + * use an array for the addresses within it + * + * @param array &$data Containing $id (the page id), $self (whether the author + * should be notified, $addresslist (current email address + * list) + */ + public function notifyaddresses(&$data) { + if(!$this->isenabled()) return; + + /** @var auth_basic $auth */ + global $auth; + global $conf; + + $id = $data['id']; + $self = $data['self']; + $addresslist = $data['addresslist']; + + $subscriptions = $this->subscribers($id, null, 'every'); + + $result = array(); + foreach($subscriptions as $target => $users) { + foreach($users as $user => $info) { + $userinfo = $auth->getUserData($user); + if($userinfo === false) continue; + if(!$userinfo['mail']) continue; + if(!$self && $user == $_SERVER['REMOTE_USER']) continue; //skip our own changes + + $level = auth_aclcheck($id, $user, $userinfo['grps']); + if($level >= AUTH_READ) { + if(strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere + $result[$user] = $userinfo['mail']; + } } } } + $data['addresslist'] = trim($addresslist.','.implode(',', $result), ','); } - $data['addresslist'] = trim($addresslist . ',' . implode(',', $emails), ','); } /** - * Send a digest mail + * Compatibility wrapper around Subscription:notifyaddresses * - * Sends a digest mail showing a bunch of changes. + * for plugins emitting COMMON_NOTIFY_ADDRESSLIST themselves and relying on on this to + * be the default handler * - * @author Adrian Lang <lang@cosmocode.de> + * @param array $data event data for * - * @param string $subscriber_mail The target mail address - * @param array $id The ID - * @param int $lastupdate Time of the last notification + * @deprecated 2012-12-07 */ -function subscription_send_digest($subscriber_mail, $id, $lastupdate) { - $n = 0; - do { - $rev = getRevisions($id, $n++, 1); - $rev = (count($rev) > 0) ? $rev[0] : null; - } while (!is_null($rev) && $rev > $lastupdate); - - $replaces = array('NEWPAGE' => wl($id, '', true, '&'), - 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')); - if (!is_null($rev)) { - $subject = 'changed'; - $replaces['OLDPAGE'] = wl($id, "rev=$rev", true, '&'); - $df = new Diff(explode("\n", rawWiki($id, $rev)), - explode("\n", rawWiki($id))); - $dformat = new UnifiedDiffFormatter(); - $replaces['DIFF'] = $dformat->format($df); - } else { - $subject = 'newpage'; - $replaces['OLDPAGE'] = 'none'; - $replaces['DIFF'] = rawWiki($id); - } - subscription_send($subscriber_mail, $replaces, $subject, $id, - 'subscr_digest'); -} - -/** - * Send a list mail - * - * Sends a list mail showing a list of changed pages. - * - * @author Adrian Lang <lang@cosmocode.de> - * - * @param string $subscriber_mail The target mail address - * @param array $ids Array of ids - * @param string $ns_id The id of the namespace - */ -function subscription_send_list($subscriber_mail, $ids, $ns_id) { - if (count($ids) === 0) return; - global $conf; - $list = ''; - foreach ($ids as $id) { - $list .= '* ' . wl($id, array(), true) . NL; - } - subscription_send($subscriber_mail, - array('DIFF' => rtrim($list), - 'SUBSCRIBE' => wl($ns_id . $conf['start'], - array('do' => 'subscribe'), - true, '&')), - 'subscribe_list', - prettyprint_id($ns_id), - 'subscr_list'); -} - -/** - * Helper function for sending a mail - * - * @author Adrian Lang <lang@cosmocode.de> - * - * @param string $subscriber_mail The target mail address - * @param array $replaces Predefined parameters used to parse the - * template - * @param string $subject The lang id of the mail subject (without the - * prefix “mail_”) - * @param string $id The page or namespace id - * @param string $template The name of the mail template - * @return bool - */ -function subscription_send($subscriber_mail, $replaces, $subject, $id, $template) { - global $lang; - global $conf; - - $text = rawLocale($template); - $trep = array_merge($replaces, array('PAGE' => $id)); - $hrep = $trep; - $hrep['DIFF'] = nl2br(htmlspecialchars($hrep['DIFF'])); - - $subject = $lang['mail_' . $subject] . ' ' . $id; - $mail = new Mailer(); - $mail->bcc($subscriber_mail); - $mail->subject($subject); - $mail->setBody($text,$trep,$hrep); - $mail->from($conf['mailfromnobody']); - $mail->setHeader( - 'List-Unsubscribe', - '<'.wl($id,array('do'=>'subscribe'),true,'&').'>', - false - ); - return $mail->send(); -} +function subscription_addresslist(&$data) { + $sub = new Subscription(); + $sub->notifyaddresses($data); +}
\ No newline at end of file |