diff --git a/MiniTemplator.class.php b/MiniTemplator.class.php new file mode 100644 index 000000000..69281cb5e --- /dev/null +++ b/MiniTemplator.class.php @@ -0,0 +1,922 @@ + +* Template syntax: +* +* Variables: +* ${VariableName} +* +* Blocks: +* <!-- $BeginBlock BlockName --> +* ... block content ... +* <!-- $EndBlock BlockName --> +* +* Include a subtemplate: +* <!-- $Include RelativeFileName --> +* +* +*
+* General remarks:
+*  - Variable names and block names are case-insensitive.
+*  - The same variable may be used multiple times within a template.
+*  - Blocks can be nested.
+*  - Multiple blocks with the same name may occur within a template.
+* 
+* +*
+* Public methods:
+*   readTemplateFromFile   - Reads the template from a file.
+*   setTemplateString      - Assigns a new template string.
+*   setVariable            - Sets a template variable.
+*   setVariableEsc         - Sets a template variable to an escaped string value.
+*   variableExists         - Checks whether a template variable exists.
+*   addBlock               - Adds an instance of a template block.
+*   blockExists            - Checks whether a block exists.
+*   reset                  - Clears all variables and blocks.
+*   generateOutput         - Generates the HTML page and writes it to the PHP output stream.
+*   generateOutputToFile   - Generates the HTML page and writes it to a file.
+*   generateOutputToString - Generates the HTML page and writes it to a string.
+* 
+* +* Home page: {@link http://www.source-code.biz/MiniTemplator}
+* License: This module is released under the GNU/LGPL license ({@link http://www.gnu.org/licenses/lgpl.html}).
+* Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland. All rights reserved.
+* This product is provided "as is" without warranty of any kind.
+* +* Version history:
+* 2001-10-24 Christian d'Heureuse (chdh): VBasic version created.
+* 2002-01-26 Markus Angst: ported to PHP4.
+* 2003-04-07 chdh: changes to adjust to Java version.
+* 2003-07-08 chdh: Method variableExists added. +* Method setVariable changed to trigger an error when the variable does not exist.
+* 2004-04-07 chdh: Parameter isOptional added to method setVariable. +* Licensing changed from GPL to LGPL.
+* 2004-04-18 chdh: Method blockExists added.
+* 2004-10-28 chdh:
+* Method setVariableEsc added.
+* Multiple blocks with the same name may now occur within a template.
+* No error ("unknown command") is generated any more, if a HTML comment starts with "${".
+* 2004-11-06 chdh:
+* "$Include" command implemented.
+* 2004-11-20 chdh:
+* "$Include" command changed so that the command text is not copied to the output file.
+*/ + +class MiniTemplator { + +//--- public member variables --------------------------------------------------------------------------------------- + +/** +* Base path for relative file names of subtemplates (for the $Include command). +* This path is prepended to the subtemplate file names. It must be set before +* readTemplateFromFile or setTemplateString. +* @access public +*/ +var $subtemplateBasePath; + +//--- private member variables -------------------------------------------------------------------------------------- + +/**#@+ +* @access private +*/ + +var $maxNestingLevel = 50; // maximum number of block nestings +var $maxInclTemplateSize = 1000000; // maximum length of template string when including subtemplates +var $template; // Template file data +var $varTab; // variables table, array index is variable no + // Fields: + // varName // variable name + // varValue // variable value +var $varTabCnt; // no of entries used in VarTab +var $varNameToNoMap; // maps variable names to variable numbers +var $varRefTab; // variable references table + // Contains an entry for each variable reference in the template. Ordered by TemplatePos. + // Fields: + // varNo // variable no + // tPosBegin // template position of begin of variable reference + // tPosEnd // template position of end of variable reference + // blockNo // block no of the (innermost) block that contains this variable reference + // blockVarNo // block variable no. Index into BlockInstTab.BlockVarTab +var $varRefTabCnt; // no of entries used in VarRefTab +var $blockTab; // Blocks table, array index is block no + // Contains an entry for each block in the template. Ordered by TPosBegin. + // Fields: + // blockName // block name + // nextWithSameName; // block no of next block with same name or -1 (blocks are backward linked in relation to template position) + // tPosBegin // template position of begin of block + // tPosContentsBegin // template pos of begin of block contents + // tPosContentsEnd // template pos of end of block contents + // tPosEnd // template position of end of block + // nestingLevel // block nesting level + // parentBlockNo // block no of parent block + // definitionIsOpen // true while $BeginBlock processed but no $EndBlock + // instances // number of instances of this block + // firstBlockInstNo // block instance no of first instance of this block or -1 + // lastBlockInstNo // block instance no of last instance of this block or -1 + // currBlockInstNo // current block instance no, used during generation of output file + // blockVarCnt // no of variables in block + // blockVarNoToVarNoMap // maps block variable numbers to variable numbers + // firstVarRefNo // variable reference no of first variable of this block or -1 +var $blockTabCnt; // no of entries used in BlockTab +var $blockNameToNoMap; // maps block names to block numbers +var $openBlocksTab; + // During parsing, this table contains the block numbers of the open parent blocks (nested outer blocks). + // Indexed by the block nesting level. +var $blockInstTab; // block instances table + // This table contains an entry for each block instance that has been added. + // Indexed by BlockInstNo. + // Fields: + // blockNo // block number + // instanceLevel // instance level of this block + // InstanceLevel is an instance counter per block. + // (In contrast to blockInstNo, which is an instance counter over the instances of all blocks) + // parentInstLevel // instance level of parent block + // nextBlockInstNo // pointer to next instance of this block or -1 + // Forward chain for instances of same block. + // blockVarTab // block instance variables +var $blockInstTabCnt; // no of entries used in BlockInstTab + +var $currentNestingLevel; // Current block nesting level during parsing. +var $templateValid; // true if a valid template is prepared +var $outputMode; // 0 = to PHP output stream, 1 = to file, 2 = to string +var $outputFileHandle; // file handle during writing of output file +var $outputError; // true when an output error occurred +var $outputString; // string buffer for the generated HTML page + +/**#@-*/ + +//--- constructor --------------------------------------------------------------------------------------------------- + +/** +* Constructs a MiniTemplator object. +* @access public +*/ +function MiniTemplator() { + $this->templateValid = false; } + +//--- template string handling -------------------------------------------------------------------------------------- + +/** +* Reads the template from a file. +* @param string $fileName name of the file that contains the template. +* @return boolean true on success, false on error. +* @access public +*/ +function readTemplateFromFile ($fileName) { + if (!$this->readFileIntoString($fileName,$s)) { + $this->triggerError ("Error while reading template file " . $fileName . "."); + return false; } + if (!$this->setTemplateString($s)) return false; + return true; } + +/** +* Assigns a new template string. +* @param string $templateString contents of the template file. +* @return boolean true on success, false on error. +* @access public +*/ +function setTemplateString ($templateString) { + $this->templateValid = false; + $this->template = $templateString; + if (!$this->parseTemplate()) return false; + $this->reset(); + $this->templateValid = true; + return true; } + +/** +* Loads the template string for a subtemplate (used for the $Include command). +* @return boolean true on success, false on error. +* @access private +*/ +function loadSubtemplate ($subtemplateName, &$s) { + $subtemplateFileName = $this->combineFileSystemPath($this->subtemplateBasePath,$subtemplateName); + if (!$this->readFileIntoString($subtemplateFileName,$s)) { + $this->triggerError ("Error while reading subtemplate file " . $subtemplateFileName . "."); + return false; } + return true; } + +//--- template parsing ---------------------------------------------------------------------------------------------- + +/** +* Parses the template. +* @return boolean true on success, false on error. +* @access private +*/ +function parseTemplate() { + $this->initParsing(); + $this->beginMainBlock(); + if (!$this->parseTemplateCommands()) return false; + $this->endMainBlock(); + if (!$this->checkBlockDefinitionsComplete()) return false; + if (!$this->parseTemplateVariables()) return false; + $this->associateVariablesWithBlocks(); + return true; } + +/** +* @access private +*/ +function initParsing() { + $this->varTab = array(); + $this->varTabCnt = 0; + $this->varNameToNoMap = array(); + $this->varRefTab = array(); + $this->varRefTabCnt = 0; + $this->blockTab = array(); + $this->blockTabCnt = 0; + $this->blockNameToNoMap = array(); + $this->openBlocksTab = array(); } + +/** +* Registers the main block. +* The main block is an implicitly defined block that covers the whole template. +* @access private +*/ +function beginMainBlock() { + $blockNo = 0; + $this->registerBlock('@@InternalMainBlock@@', $blockNo); + $bte =& $this->blockTab[$blockNo]; + $bte['tPosBegin'] = 0; + $bte['tPosContentsBegin'] = 0; + $bte['nestingLevel'] = 0; + $bte['parentBlockNo'] = -1; + $bte['definitionIsOpen'] = true; + $this->openBlocksTab[0] = $blockNo; + $this->currentNestingLevel = 1; } + +/** +* Completes the main block registration. +* @access private +*/ +function endMainBlock() { + $bte =& $this->blockTab[0]; + $bte['tPosContentsEnd'] = strlen($this->template); + $bte['tPosEnd'] = strlen($this->template); + $bte['definitionIsOpen'] = false; + $this->currentNestingLevel -= 1; } + +/** +* Parses commands within the template in the format "". +* @return boolean true on success, false on error. +* @access private +*/ +function parseTemplateCommands() { + $p = 0; + while (true) { + $p0 = strpos($this->template,'',$p0); + if ($p === false) { + $this->triggerError ("Invalid HTML comment in template at offset $p0."); + return false; } + $p += 3; + $cmdL = substr($this->template,$p0+4,$p-$p0-7); + if (!$this->processTemplateCommand($cmdL,$p0,$p,$resumeFromStart)) + return false; + if ($resumeFromStart) $p = $p0; } + return true; } + +/** +* @return boolean true on success, false on error. +* @access private +*/ +function processTemplateCommand ($cmdL, $cmdTPosBegin, $cmdTPosEnd, &$resumeFromStart) { + $resumeFromStart = false; + $p = 0; + $cmd = ''; + if (!$this->parseWord($cmdL,$p,$cmd)) return true; + $parms = substr($cmdL,$p); + switch (strtoupper($cmd)) { + case '$BEGINBLOCK': + if (!$this->processBeginBlockCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) + return false; + break; + case '$ENDBLOCK': + if (!$this->processEndBlockCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) + return false; + break; + case '$INCLUDE': + if (!$this->processincludeCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) + return false; + $resumeFromStart = true; + break; + default: + if ($cmd{0} == '$' && !(strlen($cmd) >= 2 && $cmd{1} == '{')) { + $this->triggerError ("Unknown command \"$cmd\" in template at offset $cmdTPosBegin."); + return false; }} + return true; } + +/** +* Processes the $BeginBlock command. +* @return boolean true on success, false on error. +* @access private +*/ +function processBeginBlockCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { + $p = 0; + if (!$this->parseWord($parms,$p,$blockName)) { + $this->triggerError ("Missing block name in \$BeginBlock command in template at offset $cmdTPosBegin."); + return false; } + if (trim(substr($parms,$p)) != '') { + $this->triggerError ("Extra parameter in \$BeginBlock command in template at offset $cmdTPosBegin."); + return false; } + $this->registerBlock ($blockName, $blockNo); + $btr =& $this->blockTab[$blockNo]; + $btr['tPosBegin'] = $cmdTPosBegin; + $btr['tPosContentsBegin'] = $cmdTPosEnd; + $btr['nestingLevel'] = $this->currentNestingLevel; + $btr['parentBlockNo'] = $this->openBlocksTab[$this->currentNestingLevel-1]; + $this->openBlocksTab[$this->currentNestingLevel] = $blockNo; + $this->currentNestingLevel += 1; + if ($this->currentNestingLevel > $this->maxNestingLevel) { + $trhis->triggerError ("Block nesting overflow in template at offset $cmdTPosBegin."); + return false; } + return true; } + +/** +* Processes the $EndBlock command. +* @return boolean true on success, false on error. +* @access private +*/ +function processEndBlockCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { + $p = 0; + if (!$this->parseWord($parms,$p,$blockName)) { + $this->triggerError ("Missing block name in \$EndBlock command in template at offset $cmdTPosBegin."); + return false; } + if (trim(substr($parms,$p)) != '') { + $this->triggerError ("Extra parameter in \$EndBlock command in template at offset $cmdTPosBegin."); + return false; } + if (!$this->lookupBlockName($blockName,$blockNo)) { + $this->triggerError ("Undefined block name \"$blockName\" in \$EndBlock command in template at offset $cmdTPosBegin."); + return false; } + $this->currentNestingLevel -= 1; + $btr =& $this->blockTab[$blockNo]; + if (!$btr['definitionIsOpen']) { + $this->triggerError ("Multiple \$EndBlock command for block \"$blockName\" in template at offset $cmdTPosBegin."); + return false; } + if ($btr['nestingLevel'] != $this->currentNestingLevel) { + $this->triggerError ("Block nesting level mismatch at \$EndBlock command for block \"$blockName\" in template at offset $cmdTPosBegin."); + return false; } + $btr['tPosContentsEnd'] = $cmdTPosBegin; + $btr['tPosEnd'] = $cmdTPosEnd; + $btr['definitionIsOpen'] = false; + return true; } + +/** +* @access private +*/ +function registerBlock($blockName, &$blockNo) { + $blockNo = $this->blockTabCnt++; + $btr =& $this->blockTab[$blockNo]; + $btr = array(); + $btr['blockName'] = $blockName; + if (!$this->lookupBlockName($blockName,$btr['nextWithSameName'])) + $btr['nextWithSameName'] = -1; + $btr['definitionIsOpen'] = true; + $btr['instances'] = 0; + $btr['firstBlockInstNo'] = -1; + $btr['lastBlockInstNo'] = -1; + $btr['blockVarCnt'] = 0; + $btr['firstVarRefNo'] = -1; + $btr['blockVarNoToVarNoMap'] = array(); + $this->blockNameToNoMap[strtoupper($blockName)] = $blockNo; } + +/** +* Checks that all block definitions are closed. +* @return boolean true on success, false on error. +* @access private +*/ +function checkBlockDefinitionsComplete() { + for ($blockNo=0; $blockNo < $this->blockTabCnt; $blockNo++) { + $btr =& $this->blockTab[$blockNo]; + if ($btr['definitionIsOpen']) { + $this->triggerError ("Missing \$EndBlock command in template for block " . $btr['blockName'] . "."); + return false; }} + if ($this->currentNestingLevel != 0) { + $this->triggerError ("Block nesting level error at end of template."); + return false; } + return true; } + +/** +* Processes the $Include command. +* @return boolean true on success, false on error. +* @access private +*/ +function processIncludeCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { + $p = 0; + if (!$this->parseWordOrQuotedString($parms,$p,$subtemplateName)) { + $this->triggerError ("Missing or invalid subtemplate name in \$Include command in template at offset $cmdTPosBegin."); + return false; } + if (trim(substr($parms,$p)) != '') { + $this->triggerError ("Extra parameter in \$include command in template at offset $cmdTPosBegin."); + return false; } + return $this->insertSubtemplate($subtemplateName,$cmdTPosBegin,$cmdTPosEnd); } + +/** +* Processes the $Include command. +* @return boolean true on success, false on error. +* @access private +*/ +function insertSubtemplate ($subtemplateName, $tPos1, $tPos2) { + if (strlen($this->template) > $this->maxInclTemplateSize) { + $this->triggerError ("Subtemplate include aborted because the internal template string is longer than $this->maxInclTemplateSize characters."); + return false; } + if (!$this->loadSubtemplate($subtemplateName,$subtemplate)) return false; + // (Copying the template to insert a subtemplate is a bit slow. In a future implementation of MiniTemplator, + // a table could be used that contains references to the string fragments.) + $this->template = substr($this->template,0,$tPos1) . $subtemplate . substr($this->template,$tPos2); + return true; } + +/** +* Parses variable references within the template in the format "${VarName}". +* @return boolean true on success, false on error. +* @access private +*/ +function parseTemplateVariables() { + $p = 0; + while (true) { + $p = strpos($this->template, '${', $p); + if ($p === false) break; + $p0 = $p; + $p = strpos($this->template, '}', $p); + if ($p === false) { + $this->triggerError ("Invalid variable reference in template at offset $p0."); + return false; } + $p += 1; + $varName = trim(substr($this->template, $p0+2, $p-$p0-3)); + if (strlen($varName) == 0) { + $this->triggerError ("Empty variable name in template at offset $p0."); + return false; } + $this->registerVariableReference ($varName, $p0, $p); } + return true; } + +/** +* @access private +*/ +function registerVariableReference ($varName, $tPosBegin, $tPosEnd) { + if (!$this->lookupVariableName($varName,$varNo)) + $this->registerVariable($varName,$varNo); + $varRefNo = $this->varRefTabCnt++; + $vrtr =& $this->varRefTab[$varRefNo]; + $vrtr = array(); + $vrtr['tPosBegin'] = $tPosBegin; + $vrtr['tPosEnd'] = $tPosEnd; + $vrtr['varNo'] = $varNo; } + +/** +* @access private +*/ +function registerVariable ($varName, &$varNo) { + $varNo = $this->varTabCnt++; + $vtr =& $this->varTab[$varNo]; + $vtr = array(); + $vtr['varName'] = $varName; + $vtr['varValue'] = ''; + $this->varNameToNoMap[strtoupper($varName)] = $varNo; } + +/** +* Associates variable references with blocks. +* @access private +*/ +function associateVariablesWithBlocks() { + $varRefNo = 0; + $activeBlockNo = 0; + $nextBlockNo = 1; + while ($varRefNo < $this->varRefTabCnt) { + $vrtr =& $this->varRefTab[$varRefNo]; + $varRefTPos = $vrtr['tPosBegin']; + $varNo = $vrtr['varNo']; + if ($varRefTPos >= $this->blockTab[$activeBlockNo]['tPosEnd']) { + $activeBlockNo = $this->blockTab[$activeBlockNo]['parentBlockNo']; + continue; } + if ($nextBlockNo < $this->blockTabCnt) { + if ($varRefTPos >= $this->blockTab[$nextBlockNo]['tPosBegin']) { + $activeBlockNo = $nextBlockNo; + $nextBlockNo += 1; + continue; }} + $btr =& $this->blockTab[$activeBlockNo]; + if ($varRefTPos < $btr['tPosBegin']) + $this->programLogicError(1); + $blockVarNo = $btr['blockVarCnt']++; + $btr['blockVarNoToVarNoMap'][$blockVarNo] = $varNo; + if ($btr['firstVarRefNo'] == -1) + $btr['firstVarRefNo'] = $varRefNo; + $vrtr['blockNo'] = $activeBlockNo; + $vrtr['blockVarNo'] = $blockVarNo; + $varRefNo += 1; }} + +//--- build up (template variables and blocks) ---------------------------------------------------------------------- + +/** +* Clears all variables and blocks. +* This method can be used to produce another HTML page with the same +* template. It is faster than creating another MiniTemplator object, +* because the template does not have to be parsed again. +* All variable values are cleared and all added block instances are deleted. +* @access public +*/ +function reset() { + for ($varNo=0; $varNo<$this->varTabCnt; $varNo++) + $this->varTab[$varNo]['varValue'] = ''; + for ($blockNo=0; $blockNo<$this->blockTabCnt; $blockNo++) { + $btr =& $this->blockTab[$blockNo]; + $btr['instances'] = 0; + $btr['firstBlockInstNo'] = -1; + $btr['lastBlockInstNo'] = -1; } + $this->blockInstTab = array(); + $this->blockInstTabCnt = 0; } + +/** +* Sets a template variable. +* For variables that are used in blocks, the variable value +* must be set before {@link addBlock} is called. +* @param string $variableName the name of the variable to be set. +* @param string $variableValue the new value of the variable. +* @param boolean $isOptional Specifies whether an error should be +* generated when the variable does not exist in the template. If +* $isOptional is false and the variable does not exist, an error is +* generated. +* @return boolean true on success, or false on error (e.g. when no +* variable with the specified name exists in the template and +* $isOptional is false). +* @access public +*/ +function setVariable ($variableName, $variableValue, $isOptional=false) { + if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } + if (!$this->lookupVariableName($variableName,$varNo)) { + if ($isOptional) return true; + $this->triggerError ("Variable \"$variableName\" not defined in template."); + return false; } + $this->varTab[$varNo]['varValue'] = $variableValue; + return true; } + +/** +* Sets a template variable to an escaped string. +* This method is identical to (@link setVariable), except that +* the characters <, >, &, ' and " of variableValue are +* replaced by their corresponding HTML/XML character entity codes. +* For variables that are used in blocks, the variable value +* must be set before {@link addBlock} is called. +* @param string $variableName the name of the variable to be set. +* @param string $variableValue the new value of the variable. Special HTML/XML characters are escaped. +* @param boolean $isOptional Specifies whether an error should be +* generated when the variable does not exist in the template. If +* $isOptional is false and the variable does not exist, an error is +* generated. +* @return boolean true on success, or false on error (e.g. when no +* variable with the specified name exists in the template and +* $isOptional is false). +* @access public +*/ +function setVariableEsc ($variableName, $variableValue, $isOptional=false) { + return $this->setVariable($variableName,htmlspecialchars($variableValue,ENT_QUOTES),$isOptional); } + +/** +* Checks whether a variable with the specified name exists within the template. +* @param string $variableName the name of the variable. +* @return boolean true if the variable exists, or false when no +* variable with the specified name exists in the template. +* @access public +*/ +function variableExists ($variableName) { + if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } + return $this->lookupVariableName($variableName,$varNo); } + +/** +* Adds an instance of a template block. +* If the block contains variables, these variables must be set +* before the block is added. +* If the block contains subblocks (nested blocks), the subblocks +* must be added before this block is added. +* If multiple blocks exist with the specified name, an instance +* is added for each block occurence. +* @param string blockName the name of the block to be added. +* @return boolean true on success, false on error (e.g. when no +* block with the specified name exists in the template). +* @access public +*/ +function addBlock($blockName) { + if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } + if (!$this->lookupBlockName($blockName,$blockNo)) { + $this->triggerError ("Block \"$blockName\" not defined in template."); + return false; } + while ($blockNo != -1) { + $this->addBlockByNo($blockNo); + $blockNo = $this->blockTab[$blockNo]['nextWithSameName']; } + return true; } + +/** +* @access private +*/ +function addBlockByNo ($blockNo) { + $btr =& $this->blockTab[$blockNo]; + $this->registerBlockInstance ($blockInstNo); + $bitr =& $this->blockInstTab[$blockInstNo]; + if ($btr['firstBlockInstNo'] == -1) + $btr['firstBlockInstNo'] = $blockInstNo; + if ($btr['lastBlockInstNo'] != -1) + $this->blockInstTab[$btr['lastBlockInstNo']]['nextBlockInstNo'] = $blockInstNo; + // set forward pointer of chain + $btr['lastBlockInstNo'] = $blockInstNo; + $parentBlockNo = $btr['parentBlockNo']; + $blockVarCnt = $btr['blockVarCnt']; + $bitr['blockNo'] = $blockNo; + $bitr['instanceLevel'] = $btr['instances']++; + if ($parentBlockNo == -1) + $bitr['parentInstLevel'] = -1; + else + $bitr['parentInstLevel'] = $this->blockTab[$parentBlockNo]['instances']; + $bitr['nextBlockInstNo'] = -1; + $bitr['blockVarTab'] = array(); + // copy instance variables for this block + for ($blockVarNo=0; $blockVarNo<$blockVarCnt; $blockVarNo++) { + $varNo = $btr['blockVarNoToVarNoMap'][$blockVarNo]; + $bitr['blockVarTab'][$blockVarNo] = $this->varTab[$varNo]['varValue']; }} + +/** +* @access private +*/ +function registerBlockInstance (&$blockInstNo) { + $blockInstNo = $this->blockInstTabCnt++; } + +/** +* Checks whether a block with the specified name exists within the template. +* @param string $blockName the name of the block. +* @return boolean true if the block exists, or false when no +* block with the specified name exists in the template. +* @access public +*/ +function blockExists ($blockName) { + if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } + return $this->lookupBlockName($blockName,$blockNo); } + +//--- output generation --------------------------------------------------------------------------------------------- + +/** +* Generates the HTML page and writes it to the PHP output stream. +* @return boolean true on success, false on error. +* @access public +*/ +function generateOutput () { + $this->outputMode = 0; + if (!$this->generateOutputPage()) return false; + return true; } + +/** +* Generates the HTML page and writes it to a file. +* @param string $fileName name of the output file. +* @return boolean true on success, false on error. +* @access public +*/ +function generateOutputToFile ($fileName) { + $fh = fopen($fileName,"wb"); + if ($fh === false) return false; + $this->outputMode = 1; + $this->outputFileHandle = $fh; + $ok = $this->generateOutputPage(); + fclose ($fh); + return $ok; } + +/** +* Generates the HTML page and writes it to a string. +* @param string $outputString variable that receives +* the contents of the generated HTML page. +* @return boolean true on success, false on error. +* @access public +*/ +function generateOutputToString (&$outputString) { + $outputString = "Error"; + $this->outputMode = 2; + $this->outputString = ""; + if (!$this->generateOutputPage()) return false; + $outputString = $this->outputString; + return true; } + +/** +* @access private +* @return boolean true on success, false on error. +*/ +function generateOutputPage() { + if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } + if ($this->blockTab[0]['instances'] == 0) + $this->addBlockByNo (0); // add main block + for ($blockNo=0; $blockNo < $this->blockTabCnt; $blockNo++) { + $btr =& $this->blockTab[$blockNo]; + $btr['currBlockInstNo'] = $btr['firstBlockInstNo']; } + $this->outputError = false; + $this->writeBlockInstances (0, -1); + if ($this->outputError) return false; + return true; } + +/** +* Writes all instances of a block that are contained within a specific +* parent block instance. +* Called recursively. +* @access private +*/ +function writeBlockInstances ($blockNo, $parentInstLevel) { + $btr =& $this->blockTab[$blockNo]; + while (!$this->outputError) { + $blockInstNo = $btr['currBlockInstNo']; + if ($blockInstNo == -1) break; + $bitr =& $this->blockInstTab[$blockInstNo]; + if ($bitr['parentInstLevel'] < $parentInstLevel) + $this->programLogicError (2); + if ($bitr['parentInstLevel'] > $parentInstLevel) break; + $this->writeBlockInstance ($blockInstNo); + $btr['currBlockInstNo'] = $bitr['nextBlockInstNo']; }} + +/** +* @access private +*/ +function writeBlockInstance($blockInstNo) { + $bitr =& $this->blockInstTab[$blockInstNo]; + $blockNo = $bitr['blockNo']; + $btr =& $this->blockTab[$blockNo]; + $tPos = $btr['tPosContentsBegin']; + $subBlockNo = $blockNo + 1; + $varRefNo = $btr['firstVarRefNo']; + while (!$this->outputError) { + $tPos2 = $btr['tPosContentsEnd']; + $kind = 0; // assume end-of-block + if ($varRefNo != -1 && $varRefNo < $this->varRefTabCnt) { // check for variable reference + $vrtr =& $this->varRefTab[$varRefNo]; + if ($vrtr['tPosBegin'] < $tPos) { + $varRefNo += 1; + continue; } + if ($vrtr['tPosBegin'] < $tPos2) { + $tPos2 = $vrtr['tPosBegin']; + $kind = 1; }} + if ($subBlockNo < $this->blockTabCnt) { // check for subblock + $subBtr =& $this->blockTab[$subBlockNo]; + if ($subBtr['tPosBegin'] < $tPos) { + $subBlockNo += 1; + continue; } + if ($subBtr['tPosBegin'] < $tPos2) { + $tPos2 = $subBtr['tPosBegin']; + $kind = 2; }} + if ($tPos2 > $tPos) + $this->writeString (substr($this->template,$tPos,$tPos2-$tPos)); + switch ($kind) { + case 0: // end of block + return; + case 1: // variable + $vrtr =& $this->varRefTab[$varRefNo]; + if ($vrtr['blockNo'] != $blockNo) + $this->programLogicError (4); + $variableValue = $bitr['blockVarTab'][$vrtr['blockVarNo']]; + $this->writeString ($variableValue); + $tPos = $vrtr['tPosEnd']; + $varRefNo += 1; + break; + case 2: // sub block + $subBtr =& $this->blockTab[$subBlockNo]; + if ($subBtr['parentBlockNo'] != $blockNo) + $this->programLogicError (3); + $this->writeBlockInstances ($subBlockNo, $bitr['instanceLevel']); // recursive call + $tPos = $subBtr['tPosEnd']; + $subBlockNo += 1; + break; }}} + +/** +* @access private +*/ +function writeString ($s) { + if ($this->outputError) return; + switch ($this->outputMode) { + case 0: // output to PHP output stream + if (!print($s)) + $this->outputError = true; + break; + case 1: // output to file + $rc = fwrite($this->outputFileHandle, $s); + if ($rc === false) $this->outputError = true; + break; + case 2: // output to string + $this->outputString .= $s; + break; }} + +//--- name lookup routines ------------------------------------------------------------------------------------------ + +/** +* Maps variable name to variable number. +* @return boolean true on success, false if the variable is not found. +* @access private +*/ +function lookupVariableName ($varName, &$varNo) { + $x =& $this->varNameToNoMap[strtoupper($varName)]; + if (!isset($x)) return false; + $varNo = $x; + return true; } + +/** +* Maps block name to block number. +* If there are multiple blocks with the same name, the block number of the last +* registered block with that name is returned. +* @return boolean true on success, false when the block is not found. +* @access private +*/ +function lookupBlockName ($blockName, &$blockNo) { + $x =& $this->blockNameToNoMap[strtoupper($blockName)]; + if (!isset($x)) return false; + $blockNo = $x; + return true; } + +//--- general utility routines ----------------------------------------------------------------------------------------- + +/** +* Reads a file into a string. +* @return boolean true on success, false on error. +* @access private +*/ +function readFileIntoString ($fileName, &$s) { + if (function_exists('version_compare') && version_compare(phpversion(),"4.3.0",">=")) { + $s = file_get_contents($fileName); + if ($s === false) return false; + return true; } + $fh = fopen($fileName,"rb"); + if ($fh === false) return false; + $fileSize = filesize($fileName); + if ($fileSize === false) {close ($fh); return false; } + $s = fread($fh,$fileSize); + fclose ($fh); + if (strlen($s) != $fileSize) return false; + return true; } + +/** +* @access private +* @return boolean true on success, false when the end of the string is reached. +*/ +function parseWord ($s, &$p, &$w) { + $sLen = strlen($s); + while ($p < $sLen && ord($s{$p}) <= 32) $p++; + if ($p >= $sLen) return false; + $p0 = $p; + while ($p < $sLen && ord($s{$p}) > 32) $p++; + $w = substr($s, $p0, $p - $p0); + return true; } + +/** +* @access private +* @return boolean true on success, false on error. +*/ +function parseQuotedString ($s, &$p, &$w) { + $sLen = strlen($s); + while ($p < $sLen && ord($s{$p}) <= 32) $p++; + if ($p >= $sLen) return false; + if (substr($s,$p,1) != '"') return false; + $p++; $p0 = $p; + while ($p < $sLen && $s{$p} != '"') $p++; + if ($p >= $sLen) return false; + $w = substr($s, $p0, $p - $p0); + $p++; + return true; } + +/** +* @access private +* @return boolean true on success, false on error. +*/ +function parseWordOrQuotedString ($s, &$p, &$w) { + $sLen = strlen($s); + while ($p < $sLen && ord($s{$p}) <= 32) $p++; + if ($p >= $sLen) return false; + if (substr($s,$p,1) == '"') + return $this->parseQuotedString($s,$p,$w); + else + return $this->parseWord($s,$p,$w); } + +/** +* Combine two file system paths. +* @access private +*/ +function combineFileSystemPath ($path1, $path2) { + if ($path1 == '' || $path2 == '') return $path2; + $s = $path1; + if (substr($s,-1) != '\\' && substr($s,-1) != '/') $s = $s . "/"; + if (substr($path2,0,1) == '\\' || substr($path2,0,1) == '/') + $s = $s . substr($path2,1); + else + $s = $s . $path2; + return $s; } + +/** +* @access private +*/ +function triggerError ($msg) { + trigger_error ("MiniTemplator error: $msg", E_USER_ERROR); } + +/** +* @access private +*/ +function programLogicError ($errorId) { + die ("MiniTemplator: Program logic error $errorId.\n"); } + +} +?> diff --git a/config.php-dist b/config.php-dist index 05ec08ea6..6da8eb1f0 100644 --- a/config.php-dist +++ b/config.php-dist @@ -105,9 +105,6 @@ define('DIGEST_ENABLE', true); // Global option to enable daily digests - define('DIGEST_HOSTNAME', 'your.domain.dom'); - // Hostname for email digest signature - define('DIGEST_EMAIL_LIMIT', 10); // The maximum amount of emails sent in one digest batch diff --git a/functions.php b/functions.php index 9e9eb6f35..2303f54ad 100644 --- a/functions.php +++ b/functions.php @@ -3208,47 +3208,40 @@ $digest = $tuple[0]; $headlines_count = $tuple[1]; $affected_ids = $tuple[2]; + $digest_text = $tuple[3]; if ($headlines_count > 0) { - if (!DIGEST_SMTP_HOST) { + $mail = new PHPMailer(); - $rc = mail($line["login"] . " <" . $line["email"] . ">", - "[tt-rss] New headlines for last 24 hours", $digest, - "From: " . DIGEST_FROM_NAME . " <" . DIGEST_FROM_ADDRESS . ">\n". - "Content-Type: text/plain; charset=\"utf-8\"\n". - "Content-Transfer-Encoding: 8bit\n"); + $mail->PluginDir = "phpmailer/"; + $mail->SetLanguage("en", "phpmailer/language/"); - } else { + $mail->CharSet = "UTF-8"; - $mail = new PHPMailer(); + $mail->From = DIGEST_FROM_ADDRESS; + $mail->FromName = DIGEST_FROM_NAME; + $mail->AddAddress($line["email"], $line["login"]); - $mail->PluginDir = "phpmailer/"; - $mail->SetLanguage("en", "phpmailer/language/"); - - $mail->CharSet = "UTF-8"; - - $mail->From = DIGEST_FROM_ADDRESS; - $mail->FromName = DIGEST_FROM_NAME; - $mail->AddAddress($line["email"], $line["login"]); + if (DIGEST_SMTP_HOST) { $mail->Host = DIGEST_SMTP_HOST; $mail->Mailer = "smtp"; - $mail->Username = DIGEST_SMTP_LOGIN; $mail->Password = DIGEST_SMTP_PASSWORD; - - $mail->Subject = "[tt-rss] New headlines for last 24 hours"; - $mail->Body = $digest; - - $rc = $mail->Send(); - - if (!$rc) print "ERROR: " . $mail->ErrorInfo; - } + $mail->IsHTML(true); + $mail->Subject = "[tt-rss] New headlines for last 24 hours"; + $mail->Body = $digest; + $mail->AltBody = $digest_text; + + $rc = $mail->Send(); + + if (!$rc) print "ERROR: " . $mail->ErrorInfo; + print "RC=$rc\n"; - if ($rc) { + if ($rc && $do_catchup) { print "Marking affected articles as read...\n"; catchupArticlesById($link, $affected_ids, 0, $line["id"]); } @@ -3261,15 +3254,25 @@ } } -// $digest = prepare_headlines_digest($link, $user_id, $days, $limit); - print "All done.\n"; } function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 100) { - $tmp = __("New headlines for last 24 hours, as of ") . date("Y/m/d H:m") . "\n"; - $tmp .= "=======================================================\n\n"; + + require_once "MiniTemplator.class.php"; + + $tpl = new MiniTemplator; + $tpl_t = new MiniTemplator; + + $tpl->readTemplateFromFile("templates/digest_template_html.txt"); + $tpl_t->readTemplateFromFile("templates/digest_template.txt"); + + $tpl->setVariable('CUR_DATE', date('Y/m/d')); + $tpl->setVariable('CUR_TIME', date('G:i')); + + $tpl_t->setVariable('CUR_DATE', date('Y/m/d')); + $tpl_t->setVariable('CUR_TIME', date('G:i')); $affected_ids = array(); @@ -3284,6 +3287,7 @@ date_entered, ttrss_user_entries.ref_id, link, + SUBSTRING(content, 1, 120) AS excerpt, SUBSTRING(last_updated,1,19) AS last_updated FROM ttrss_user_entries,ttrss_entries,ttrss_feeds @@ -3293,38 +3297,60 @@ AND $interval_query AND hidden = false AND ttrss_user_entries.owner_uid = $user_id - AND unread = true ORDER BY ttrss_feeds.title, date_entered DESC + AND unread = true + ORDER BY ttrss_feeds.title, date_entered DESC LIMIT $limit"); $cur_feed_title = ""; $headlines_count = db_num_rows($result); + $headlines = array(); + while ($line = db_fetch_assoc($result)) { + array_push($headlines, $line); + } + + for ($i = 0; $i < sizeof($headlines); $i++) { + + $line = $headlines[$i]; array_push($affected_ids, $line["ref_id"]); $updated = smart_date_time(strtotime($line["last_updated"])); - $feed_title = $line["feed_title"]; - if ($cur_feed_title != $feed_title) { - $cur_feed_title = $feed_title; + $tpl->setVariable('FEED_TITLE', $line["feed_title"]); + $tpl->setVariable('ARTICLE_TITLE', $line["title"]); + $tpl->setVariable('ARTICLE_LINK', $line["link"]); + $tpl->setVariable('ARTICLE_UPDATED', $updated); +// $tpl->setVariable('ARTICLE_EXCERPT', +// truncate_string(strip_tags($line["excerpt"]), 100)); - $tmp .= "$feed_title\n\n"; + $tpl->addBlock('article'); + + $tpl_t->setVariable('FEED_TITLE', $line["feed_title"]); + $tpl_t->setVariable('ARTICLE_TITLE', $line["title"]); + $tpl_t->setVariable('ARTICLE_LINK', $line["link"]); + $tpl_t->setVariable('ARTICLE_UPDATED', $updated); +// $tpl_t->setVariable('ARTICLE_EXCERPT', +// truncate_string(strip_tags($line["excerpt"]), 100)); + + $tpl_t->addBlock('article'); + + if ($headlines[$i]['feed_title'] != $headlines[$i+1]['feed_title']) { + $tpl->addBlock('feed'); + $tpl_t->addBlock('feed'); } - $tmp .= " * " . trim($line["title"]) . " - $updated\n"; - $tmp .= " " . trim($line["link"]) . "\n"; - $tmp .= "\n"; } - $tmp .= "--- \n"; - $tmp .= __("You have been sent this email because you have enabled daily digests in Tiny Tiny RSS at ") . - DIGEST_HOSTNAME . "\n". - __("To unsubscribe, visit your configuration options or contact instance owner.\n"); - + $tpl->addBlock('digest'); + $tpl->generateOutputToString($tmp); - return array($tmp, $headlines_count, $affected_ids); + $tpl_t->addBlock('digest'); + $tpl_t->generateOutputToString($tmp_t); + + return array($tmp, $headlines_count, $affected_ids, $tmp_t); } function check_for_update($link, $brief_fmt = true) { diff --git a/locale/fr_FR/LC_MESSAGES/messages.mo b/locale/fr_FR/LC_MESSAGES/messages.mo index 4802cdc11..e7279c7b6 100644 Binary files a/locale/fr_FR/LC_MESSAGES/messages.mo and b/locale/fr_FR/LC_MESSAGES/messages.mo differ diff --git a/locale/fr_FR/LC_MESSAGES/messages.po b/locale/fr_FR/LC_MESSAGES/messages.po index 003545ed6..6b726b697 100644 --- a/locale/fr_FR/LC_MESSAGES/messages.po +++ b/locale/fr_FR/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: messages\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-29 14:21+0300\n" +"POT-Creation-Date: 2007-10-30 12:46+0300\n" "PO-Revision-Date: 2007-09-27 18:17+0200\n" "Last-Translator: Thibaut Cousin \n" "Language-Team: Français \n" @@ -146,16 +146,16 @@ msgstr "" "Votre version de MySQL n'est pas gérée pour le moment. Reportez-vous au \n" "\t\tsite officiel pour plus d'informations." -#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3760 +#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3772 msgid "Starred articles" msgstr "Articles remarquables" -#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3767 +#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3779 #: modules/pref-feeds.php:1068 msgid "Published articles" msgstr "Articles publiés" -#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3745 +#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3757 msgid "Fresh articles" msgstr "Nouveaux articles" @@ -164,8 +164,8 @@ msgstr "Nouveaux articles" msgid "All feeds" msgstr "Tous les flux" -#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3924 -#: functions.php:3954 modules/pref-feeds.php:880 +#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3936 +#: functions.php:3966 modules/pref-feeds.php:880 msgid "Uncategorized" msgstr "Sans catégorie" @@ -185,142 +185,123 @@ msgstr "Résultats de recherche" msgid "Searched for" msgstr "Recherché" -#: functions.php:3271 -msgid "New headlines for last 24 hours, as of " -msgstr "Nouveaux en-têtes dans les dernières 24 heures, à compter de " - -#: functions.php:3322 -msgid "" -"You have been sent this email because you have enabled daily digests in Tiny " -"Tiny RSS at " -msgstr "" -"Vous recevez ce courrier électronique parce que vous avez activé la synthèse " -"quotidienne dans TIny Tiny RSS sur " - -#: functions.php:3324 -msgid "" -"To unsubscribe, visit your configuration options or contact instance owner.\n" -msgstr "" -"Pour vous désinscrire, modifiez votre configuration ou contactez " -"l'administrateur de votre TIny Tiny RSS.\n" - -#: functions.php:3555 functions.php:3602 functions.php:4650 +#: functions.php:3567 functions.php:3614 functions.php:4662 #: modules/pref-feeds.php:655 modules/pref-feeds.php:842 #: modules/pref-filters.php:255 modules/pref-labels.php:234 #: modules/pref-users.php:208 msgid "Select:" msgstr "Sélectionner :" -#: functions.php:3556 functions.php:3603 modules/pref-feeds.php:656 +#: functions.php:3568 functions.php:3615 modules/pref-feeds.php:656 #: modules/pref-feeds.php:843 modules/pref-filters.php:256 #: modules/pref-labels.php:235 modules/pref-users.php:209 msgid "All" msgstr "Tout" -#: functions.php:3557 functions.php:3561 functions.php:3604 functions.php:3607 +#: functions.php:3569 functions.php:3573 functions.php:3616 functions.php:3619 #: tt-rss.php:165 msgid "Unread" msgstr "Non lus" -#: functions.php:3558 functions.php:3605 modules/pref-feeds.php:657 +#: functions.php:3570 functions.php:3617 modules/pref-feeds.php:657 #: modules/pref-feeds.php:844 modules/pref-filters.php:257 #: modules/pref-labels.php:236 modules/pref-users.php:210 msgid "None" msgstr "Aucun" -#: functions.php:3560 +#: functions.php:3572 msgid "Toggle" msgstr "Marquages spéciaux " -#: functions.php:3562 functions.php:3608 tt-rss.php:164 +#: functions.php:3574 functions.php:3620 tt-rss.php:164 msgid "Starred" msgstr "Remarquables" -#: functions.php:3563 +#: functions.php:3575 msgid "Published" msgstr "Publiés" -#: functions.php:3566 localized_schema.php:15 +#: functions.php:3578 localized_schema.php:15 msgid "Mark as read" msgstr "Marquer comme lu" -#: functions.php:3567 +#: functions.php:3579 msgid "Selection" msgstr "La sélection" -#: functions.php:3568 +#: functions.php:3580 msgid "This page" msgstr "Cette page" -#: functions.php:3570 +#: functions.php:3582 msgid "Above active article" msgstr "Au-dessus de l'article courant" -#: functions.php:3571 +#: functions.php:3583 msgid "Below active article" msgstr "En dessous de l'article courant" -#: functions.php:3573 +#: functions.php:3585 msgid "Entire feed" msgstr "Tout le flux" -#: functions.php:3581 +#: functions.php:3593 msgid "Next page" msgstr "Page suivante" -#: functions.php:3582 +#: functions.php:3594 msgid "Previous page" msgstr "Page précédente" -#: functions.php:3583 +#: functions.php:3595 msgid "First page" msgstr "Première page" -#: functions.php:3593 functions.php:3619 +#: functions.php:3605 functions.php:3631 msgid "Convert to label" msgstr "Convertir en intitulé" -#: functions.php:3607 +#: functions.php:3619 msgid "Toggle:" msgstr "Marquages spéciaux :" -#: functions.php:3610 +#: functions.php:3622 msgid "Mark as read:" msgstr "Marquer comme lu :" -#: functions.php:3611 +#: functions.php:3623 msgid "Page" msgstr "Page" -#: functions.php:3612 modules/pref-filters.php:263 +#: functions.php:3624 modules/pref-filters.php:263 msgid "Feed" msgstr "Flux" -#: functions.php:3658 +#: functions.php:3670 msgid "Generated feed" msgstr "Flux généré" -#: functions.php:3994 +#: functions.php:4006 msgid "No feeds to display." msgstr "Aucun flux à afficher." -#: functions.php:4011 +#: functions.php:4023 msgid "Tags" msgstr "Étiquettes" -#: functions.php:4236 +#: functions.php:4248 msgid " - by " msgstr "- par " -#: functions.php:4285 +#: functions.php:4297 msgid "no tags" msgstr "aucune étiquette" -#: functions.php:4356 +#: functions.php:4368 msgid "Feed not found." msgstr "Flux non trouvé." -#: functions.php:4418 +#: functions.php:4430 msgid "" "Could not display feed (query failed). Please check label match syntax or " "local configuration." @@ -328,12 +309,12 @@ msgstr "" "Impossible d'afficher le flux (la requête l'a pas abouti). Veuillez vérifier " "la syntaxe de son intitulé ou la configuration locale." -#: functions.php:4616 +#: functions.php:4628 #, fuzzy msgid "Show article" msgstr "Marquer comme remarquable" -#: functions.php:4713 +#: functions.php:4725 msgid "No articles found." msgstr "Aucun article trouvé." @@ -1956,5 +1937,22 @@ msgstr "Détails de l'utilisateur" msgid "Reset password" msgstr "Réinitialiser le mot de passe" +#~ msgid "New headlines for last 24 hours, as of " +#~ msgstr "Nouveaux en-têtes dans les dernières 24 heures, à compter de " + +#~ msgid "" +#~ "You have been sent this email because you have enabled daily digests in " +#~ "Tiny Tiny RSS at " +#~ msgstr "" +#~ "Vous recevez ce courrier électronique parce que vous avez activé la " +#~ "synthèse quotidienne dans TIny Tiny RSS sur " + +#~ msgid "" +#~ "To unsubscribe, visit your configuration options or contact instance " +#~ "owner.\n" +#~ msgstr "" +#~ "Pour vous désinscrire, modifiez votre configuration ou contactez " +#~ "l'administrateur de votre TIny Tiny RSS.\n" + #~ msgid "  Update" #~ msgstr "  Mettre à jour" diff --git a/locale/pt_BR/LC_MESSAGES/messages.mo b/locale/pt_BR/LC_MESSAGES/messages.mo index 9b26ddc42..75306e9f9 100644 Binary files a/locale/pt_BR/LC_MESSAGES/messages.mo and b/locale/pt_BR/LC_MESSAGES/messages.mo differ diff --git a/locale/pt_BR/LC_MESSAGES/messages.po b/locale/pt_BR/LC_MESSAGES/messages.po index 9d6406a5d..ae71d93e3 100644 --- a/locale/pt_BR/LC_MESSAGES/messages.po +++ b/locale/pt_BR/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: tt-rss 1.2.14.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-29 14:21+0300\n" +"POT-Creation-Date: 2007-10-30 12:46+0300\n" "PO-Revision-Date: 2007-10-24 00:47-0200\n" "Last-Translator: Marcelo Jorge VIeira (metal) \n" "Language-Team: Portuguese/Brazil\n" @@ -140,16 +140,16 @@ msgstr "" "Sua versão do MySQL não é atualmente suportada. Por favor acesse \n" "\t\to site oficial para mais informações." -#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3760 +#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3772 msgid "Starred articles" msgstr "" -#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3767 +#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3779 #: modules/pref-feeds.php:1068 msgid "Published articles" msgstr "" -#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3745 +#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3757 msgid "Fresh articles" msgstr "" @@ -158,8 +158,8 @@ msgstr "" msgid "All feeds" msgstr "Todos os feeds" -#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3924 -#: functions.php:3954 modules/pref-feeds.php:880 +#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3936 +#: functions.php:3966 modules/pref-feeds.php:880 msgid "Uncategorized" msgstr "Não Categorizado" @@ -179,149 +179,134 @@ msgstr "" msgid "Searched for" msgstr "" -#: functions.php:3271 -msgid "New headlines for last 24 hours, as of " -msgstr "" - -#: functions.php:3322 -msgid "" -"You have been sent this email because you have enabled daily digests in Tiny " -"Tiny RSS at " -msgstr "" - -#: functions.php:3324 -msgid "" -"To unsubscribe, visit your configuration options or contact instance owner.\n" -msgstr "" - -#: functions.php:3555 functions.php:3602 functions.php:4650 +#: functions.php:3567 functions.php:3614 functions.php:4662 #: modules/pref-feeds.php:655 modules/pref-feeds.php:842 #: modules/pref-filters.php:255 modules/pref-labels.php:234 #: modules/pref-users.php:208 msgid "Select:" msgstr "Selecione:" -#: functions.php:3556 functions.php:3603 modules/pref-feeds.php:656 +#: functions.php:3568 functions.php:3615 modules/pref-feeds.php:656 #: modules/pref-feeds.php:843 modules/pref-filters.php:256 #: modules/pref-labels.php:235 modules/pref-users.php:209 msgid "All" msgstr "Todos" -#: functions.php:3557 functions.php:3561 functions.php:3604 functions.php:3607 +#: functions.php:3569 functions.php:3573 functions.php:3616 functions.php:3619 #: tt-rss.php:165 msgid "Unread" msgstr "Não Lido" -#: functions.php:3558 functions.php:3605 modules/pref-feeds.php:657 +#: functions.php:3570 functions.php:3617 modules/pref-feeds.php:657 #: modules/pref-feeds.php:844 modules/pref-filters.php:257 #: modules/pref-labels.php:236 modules/pref-users.php:210 msgid "None" msgstr "Nenhum" -#: functions.php:3560 +#: functions.php:3572 msgid "Toggle" msgstr "" -#: functions.php:3562 functions.php:3608 tt-rss.php:164 +#: functions.php:3574 functions.php:3620 tt-rss.php:164 msgid "Starred" msgstr "Favoritos" -#: functions.php:3563 +#: functions.php:3575 msgid "Published" msgstr "Publicado" -#: functions.php:3566 localized_schema.php:15 +#: functions.php:3578 localized_schema.php:15 msgid "Mark as read" msgstr "Marcar como lido" -#: functions.php:3567 +#: functions.php:3579 msgid "Selection" msgstr "Seleção" -#: functions.php:3568 +#: functions.php:3580 msgid "This page" msgstr "" -#: functions.php:3570 +#: functions.php:3582 msgid "Above active article" msgstr "" -#: functions.php:3571 +#: functions.php:3583 msgid "Below active article" msgstr "" -#: functions.php:3573 +#: functions.php:3585 msgid "Entire feed" msgstr "" -#: functions.php:3581 +#: functions.php:3593 msgid "Next page" msgstr "Próxima página" -#: functions.php:3582 +#: functions.php:3594 msgid "Previous page" msgstr "Página anterior" -#: functions.php:3583 +#: functions.php:3595 msgid "First page" msgstr "Primeira página" -#: functions.php:3593 functions.php:3619 +#: functions.php:3605 functions.php:3631 msgid "Convert to label" msgstr "" -#: functions.php:3607 +#: functions.php:3619 msgid "Toggle:" msgstr "" -#: functions.php:3610 +#: functions.php:3622 msgid "Mark as read:" msgstr "Marcar como lido:" -#: functions.php:3611 +#: functions.php:3623 msgid "Page" msgstr "Página" -#: functions.php:3612 modules/pref-filters.php:263 +#: functions.php:3624 modules/pref-filters.php:263 msgid "Feed" msgstr "Feed" -#: functions.php:3658 +#: functions.php:3670 msgid "Generated feed" msgstr "" -#: functions.php:3994 +#: functions.php:4006 msgid "No feeds to display." msgstr "Sem Feeds para exibir." -#: functions.php:4011 +#: functions.php:4023 msgid "Tags" msgstr "Tags" -#: functions.php:4236 +#: functions.php:4248 msgid " - by " msgstr " - por " -#: functions.php:4285 +#: functions.php:4297 msgid "no tags" msgstr "sem tags" -#: functions.php:4356 +#: functions.php:4368 msgid "Feed not found." msgstr "Feed não encontrado." -#: functions.php:4418 +#: functions.php:4430 msgid "" "Could not display feed (query failed). Please check label match syntax or " "local configuration." msgstr "" -#: functions.php:4616 +#: functions.php:4628 #, fuzzy msgid "Show article" msgstr "Favoritos" -#: functions.php:4713 +#: functions.php:4725 msgid "No articles found." msgstr "" diff --git a/locale/ru_RU/LC_MESSAGES/messages.mo b/locale/ru_RU/LC_MESSAGES/messages.mo index 28efb9c4d..5aab32d31 100644 Binary files a/locale/ru_RU/LC_MESSAGES/messages.mo and b/locale/ru_RU/LC_MESSAGES/messages.mo differ diff --git a/locale/ru_RU/LC_MESSAGES/messages.po b/locale/ru_RU/LC_MESSAGES/messages.po index 4b5e1eb83..b840ac48c 100644 --- a/locale/ru_RU/LC_MESSAGES/messages.po +++ b/locale/ru_RU/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-29 14:21+0300\n" +"POT-Creation-Date: 2007-10-30 12:46+0300\n" "PO-Revision-Date: 2007-08-18 15:14+0400\n" "Last-Translator: Andrew Dolgov \n" "Language-Team: Русский \n" @@ -140,16 +140,16 @@ msgid "" "\t\tofficial site for more information." msgstr "" -#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3760 +#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3772 msgid "Starred articles" msgstr "Отмеченные" -#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3767 +#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3779 #: modules/pref-feeds.php:1068 msgid "Published articles" msgstr "Опубликованные" -#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3745 +#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3757 #, fuzzy msgid "Fresh articles" msgstr "Отмеченные" @@ -159,8 +159,8 @@ msgstr "Отмеченные" msgid "All feeds" msgstr "Все каналы" -#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3924 -#: functions.php:3954 modules/pref-feeds.php:880 +#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3936 +#: functions.php:3966 modules/pref-feeds.php:880 msgid "Uncategorized" msgstr "Нет категории" @@ -180,151 +180,136 @@ msgstr "Результаты поиска" msgid "Searched for" msgstr "Поиск" -#: functions.php:3271 -msgid "New headlines for last 24 hours, as of " -msgstr "Новые заголовки за последние 24 часа, на " - -#: functions.php:3322 -msgid "" -"You have been sent this email because you have enabled daily digests in Tiny " -"Tiny RSS at " -msgstr "" - -#: functions.php:3324 -msgid "" -"To unsubscribe, visit your configuration options or contact instance owner.\n" -msgstr "" - -#: functions.php:3555 functions.php:3602 functions.php:4650 +#: functions.php:3567 functions.php:3614 functions.php:4662 #: modules/pref-feeds.php:655 modules/pref-feeds.php:842 #: modules/pref-filters.php:255 modules/pref-labels.php:234 #: modules/pref-users.php:208 msgid "Select:" msgstr "Выбрать:" -#: functions.php:3556 functions.php:3603 modules/pref-feeds.php:656 +#: functions.php:3568 functions.php:3615 modules/pref-feeds.php:656 #: modules/pref-feeds.php:843 modules/pref-filters.php:256 #: modules/pref-labels.php:235 modules/pref-users.php:209 msgid "All" msgstr "Все" -#: functions.php:3557 functions.php:3561 functions.php:3604 functions.php:3607 +#: functions.php:3569 functions.php:3573 functions.php:3616 functions.php:3619 #: tt-rss.php:165 msgid "Unread" msgstr "Новые" -#: functions.php:3558 functions.php:3605 modules/pref-feeds.php:657 +#: functions.php:3570 functions.php:3617 modules/pref-feeds.php:657 #: modules/pref-feeds.php:844 modules/pref-filters.php:257 #: modules/pref-labels.php:236 modules/pref-users.php:210 msgid "None" msgstr "Ничего" -#: functions.php:3560 +#: functions.php:3572 msgid "Toggle" msgstr "Изменить:" -#: functions.php:3562 functions.php:3608 tt-rss.php:164 +#: functions.php:3574 functions.php:3620 tt-rss.php:164 msgid "Starred" msgstr "Отмеченные" -#: functions.php:3563 +#: functions.php:3575 msgid "Published" msgstr "Опубликован" -#: functions.php:3566 localized_schema.php:15 +#: functions.php:3578 localized_schema.php:15 msgid "Mark as read" msgstr "Как прочитанные" -#: functions.php:3567 +#: functions.php:3579 #, fuzzy msgid "Selection" msgstr "Выбрать:" -#: functions.php:3568 +#: functions.php:3580 msgid "This page" msgstr "Эту страницу" -#: functions.php:3570 +#: functions.php:3582 msgid "Above active article" msgstr "" -#: functions.php:3571 +#: functions.php:3583 #, fuzzy msgid "Below active article" msgstr "Отфильтровать статью" -#: functions.php:3573 +#: functions.php:3585 msgid "Entire feed" msgstr "Весь канал" -#: functions.php:3581 +#: functions.php:3593 msgid "Next page" msgstr "След. стр." -#: functions.php:3582 +#: functions.php:3594 msgid "Previous page" msgstr "Пред. cтр." -#: functions.php:3583 +#: functions.php:3595 msgid "First page" msgstr "На первую" -#: functions.php:3593 functions.php:3619 +#: functions.php:3605 functions.php:3631 msgid "Convert to label" msgstr "Превратить в метку" -#: functions.php:3607 +#: functions.php:3619 msgid "Toggle:" msgstr "Изменить:" -#: functions.php:3610 +#: functions.php:3622 msgid "Mark as read:" msgstr "Пометить как прочит.:" -#: functions.php:3611 +#: functions.php:3623 msgid "Page" msgstr "Страница" -#: functions.php:3612 modules/pref-filters.php:263 +#: functions.php:3624 modules/pref-filters.php:263 msgid "Feed" msgstr "Канал" -#: functions.php:3658 +#: functions.php:3670 msgid "Generated feed" msgstr "" -#: functions.php:3994 +#: functions.php:4006 msgid "No feeds to display." msgstr "Нет каналов для отображения." -#: functions.php:4011 +#: functions.php:4023 msgid "Tags" msgstr "Теги" -#: functions.php:4236 +#: functions.php:4248 msgid " - by " msgstr ", автор - " -#: functions.php:4285 +#: functions.php:4297 msgid "no tags" msgstr "нет тегов" -#: functions.php:4356 +#: functions.php:4368 msgid "Feed not found." msgstr "Канал не найден." -#: functions.php:4418 +#: functions.php:4430 msgid "" "Could not display feed (query failed). Please check label match syntax or " "local configuration." msgstr "" -#: functions.php:4616 +#: functions.php:4628 #, fuzzy msgid "Show article" msgstr "Отмеченные" -#: functions.php:4713 +#: functions.php:4725 msgid "No articles found." msgstr "Статей не найдено." @@ -1871,6 +1856,9 @@ msgstr "Подробнее..." msgid "Reset password" msgstr "Сбросить пароль" +#~ msgid "New headlines for last 24 hours, as of " +#~ msgstr "Новые заголовки за последние 24 часа, на " + #~ msgid "  Update" #~ msgstr "  Обновить" diff --git a/locale/zh_CN/LC_MESSAGES/messages.mo b/locale/zh_CN/LC_MESSAGES/messages.mo index fd9d4f181..73dee5e96 100644 Binary files a/locale/zh_CN/LC_MESSAGES/messages.mo and b/locale/zh_CN/LC_MESSAGES/messages.mo differ diff --git a/locale/zh_CN/LC_MESSAGES/messages.po b/locale/zh_CN/LC_MESSAGES/messages.po index 5a83e8897..26b592689 100644 --- a/locale/zh_CN/LC_MESSAGES/messages.po +++ b/locale/zh_CN/LC_MESSAGES/messages.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiny Tiny RSS1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-29 14:21+0300\n" +"POT-Creation-Date: 2007-10-30 12:46+0300\n" "PO-Revision-Date: 2007-08-19 19:03+0800\n" "Last-Translator: sluke \n" "Language-Team: hicode.org \n" @@ -136,16 +136,16 @@ msgstr "" "不支持你的MySQL版本. 请访问 \n" "\t\t官方网站获取更多信息。" -#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3760 +#: functions.php:2286 functions.php:2625 functions.php:2985 functions.php:3772 msgid "Starred articles" msgstr "星级文章" -#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3767 +#: functions.php:2295 functions.php:2627 functions.php:2987 functions.php:3779 #: modules/pref-feeds.php:1068 msgid "Published articles" msgstr "已发布文章" -#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3745 +#: functions.php:2304 functions.php:2629 functions.php:2989 functions.php:3757 #, fuzzy msgid "Fresh articles" msgstr "星级文章" @@ -155,8 +155,8 @@ msgstr "星级文章" msgid "All feeds" msgstr "所有feed" -#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3924 -#: functions.php:3954 modules/pref-feeds.php:880 +#: functions.php:2576 functions.php:2615 functions.php:2963 functions.php:3936 +#: functions.php:3966 modules/pref-feeds.php:880 msgid "Uncategorized" msgstr "未分类" @@ -176,150 +176,135 @@ msgstr "搜索结果" msgid "Searched for" msgstr "搜索" -#: functions.php:3271 -msgid "New headlines for last 24 hours, as of " -msgstr "24小时最新提要,截至" - -#: functions.php:3322 -msgid "" -"You have been sent this email because you have enabled daily digests in Tiny " -"Tiny RSS at " -msgstr "由于您启用了Tiny Tiny RSS每日文摘,会收到此邮件。" - -#: functions.php:3324 -msgid "" -"To unsubscribe, visit your configuration options or contact instance owner.\n" -msgstr "若要退订,访问你的配置选项或联络管理员。\n" - -#: functions.php:3555 functions.php:3602 functions.php:4650 +#: functions.php:3567 functions.php:3614 functions.php:4662 #: modules/pref-feeds.php:655 modules/pref-feeds.php:842 #: modules/pref-filters.php:255 modules/pref-labels.php:234 #: modules/pref-users.php:208 msgid "Select:" msgstr "选择:" -#: functions.php:3556 functions.php:3603 modules/pref-feeds.php:656 +#: functions.php:3568 functions.php:3615 modules/pref-feeds.php:656 #: modules/pref-feeds.php:843 modules/pref-filters.php:256 #: modules/pref-labels.php:235 modules/pref-users.php:209 msgid "All" msgstr "所有" -#: functions.php:3557 functions.php:3561 functions.php:3604 functions.php:3607 +#: functions.php:3569 functions.php:3573 functions.php:3616 functions.php:3619 #: tt-rss.php:165 msgid "Unread" msgstr "未读" -#: functions.php:3558 functions.php:3605 modules/pref-feeds.php:657 +#: functions.php:3570 functions.php:3617 modules/pref-feeds.php:657 #: modules/pref-feeds.php:844 modules/pref-filters.php:257 #: modules/pref-labels.php:236 modules/pref-users.php:210 msgid "None" msgstr "无" -#: functions.php:3560 +#: functions.php:3572 msgid "Toggle" msgstr "触发开关" -#: functions.php:3562 functions.php:3608 tt-rss.php:164 +#: functions.php:3574 functions.php:3620 tt-rss.php:164 msgid "Starred" msgstr "星级" -#: functions.php:3563 +#: functions.php:3575 msgid "Published" msgstr "已发布" -#: functions.php:3566 localized_schema.php:15 +#: functions.php:3578 localized_schema.php:15 msgid "Mark as read" msgstr "标记为已读" -#: functions.php:3567 +#: functions.php:3579 msgid "Selection" msgstr "选择:" -#: functions.php:3568 +#: functions.php:3580 msgid "This page" msgstr "本页" -#: functions.php:3570 +#: functions.php:3582 msgid "Above active article" msgstr "" -#: functions.php:3571 +#: functions.php:3583 #, fuzzy msgid "Below active article" msgstr "过滤文章" -#: functions.php:3573 +#: functions.php:3585 msgid "Entire feed" msgstr "输入feed" -#: functions.php:3581 +#: functions.php:3593 msgid "Next page" msgstr "下页" -#: functions.php:3582 +#: functions.php:3594 msgid "Previous page" msgstr "上页" -#: functions.php:3583 +#: functions.php:3595 msgid "First page" msgstr "首页" -#: functions.php:3593 functions.php:3619 +#: functions.php:3605 functions.php:3631 msgid "Convert to label" msgstr "转换标签" -#: functions.php:3607 +#: functions.php:3619 msgid "Toggle:" msgstr "触发:" -#: functions.php:3610 +#: functions.php:3622 msgid "Mark as read:" msgstr "标记为已读:" -#: functions.php:3611 +#: functions.php:3623 msgid "Page" msgstr "页" -#: functions.php:3612 modules/pref-filters.php:263 +#: functions.php:3624 modules/pref-filters.php:263 msgid "Feed" msgstr "Feed" -#: functions.php:3658 +#: functions.php:3670 msgid "Generated feed" msgstr "产生feed" -#: functions.php:3994 +#: functions.php:4006 msgid "No feeds to display." msgstr "无feed显示。" -#: functions.php:4011 +#: functions.php:4023 msgid "Tags" msgstr "标签" -#: functions.php:4236 +#: functions.php:4248 msgid " - by " msgstr ", 由 - " -#: functions.php:4285 +#: functions.php:4297 msgid "no tags" msgstr "无标签" -#: functions.php:4356 +#: functions.php:4368 msgid "Feed not found." msgstr "未找到Feed." -#: functions.php:4418 +#: functions.php:4430 msgid "" "Could not display feed (query failed). Please check label match syntax or " "local configuration." msgstr "无法显示feed(查询失败); 请核对标签匹配语法或本地配置." -#: functions.php:4616 +#: functions.php:4628 #, fuzzy msgid "Show article" msgstr "星级文章" -#: functions.php:4713 +#: functions.php:4725 msgid "No articles found." msgstr "未找到文章。" @@ -1887,5 +1872,18 @@ msgstr "用户详细" msgid "Reset password" msgstr "重置密码" +#~ msgid "New headlines for last 24 hours, as of " +#~ msgstr "24小时最新提要,截至" + +#~ msgid "" +#~ "You have been sent this email because you have enabled daily digests in " +#~ "Tiny Tiny RSS at " +#~ msgstr "由于您启用了Tiny Tiny RSS每日文摘,会收到此邮件。" + +#~ msgid "" +#~ "To unsubscribe, visit your configuration options or contact instance " +#~ "owner.\n" +#~ msgstr "若要退订,访问你的配置选项或联络管理员。\n" + #~ msgid "  Update" #~ msgstr "  更新" diff --git a/templates/digest_template.txt b/templates/digest_template.txt new file mode 100644 index 000000000..aa56fb3ae --- /dev/null +++ b/templates/digest_template.txt @@ -0,0 +1,14 @@ + +New headlines for last 24 hours, as of ${CUR_DATE} ${CUR_TIME} +============================================================== + +${FEED_TITLE} + + +* ${ARTICLE_TITLE} - ${ARTICLE_UPDATED} + ${ARTICLE_LINK} + + +-- +To unsubscribe, visit your configuration options or contact instance owner. + diff --git a/templates/digest_template_html.txt b/templates/digest_template_html.txt new file mode 100644 index 000000000..4b85f8ba9 --- /dev/null +++ b/templates/digest_template_html.txt @@ -0,0 +1,14 @@ + +

New headlines for last 24 hours, as of ${CUR_DATE} ${CUR_TIME}

+ +

${FEED_TITLE}

+ + + + +

To unsubscribe, visit your configuration options or contact instance owner.

+