1<?php 2if (! class_exists('syntax_plugin_lang')) { 3 if (! defined('DOKU_PLUGIN')) { 4 if (! defined('DOKU_INC')) { 5 define('DOKU_INC', realpath(dirname(__FILE__) . '/../../') . '/'); 6 } // if 7 define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 8 } // if 9 // include parent class 10 require_once(DOKU_PLUGIN . 'syntax.php'); 11 12/** 13 * <tt>syntax_plugin_lang.php </tt>- A PHP4 class that implements 14 * a <tt>DokuWiki</tt> plugin to specify an area using a different 15 * language than the remaining document. 16 * 17 * <p> 18 * Markup a section of text to be using a different language, 19 * <tt>lang 2-letter-lang-code</tt> 20 * </p><pre> 21 * Copyright (C) 2005, 2007 DFG/M.Watermann, D-10247 Berlin, FRG 22 * All rights reserved 23 * EMail : <support@mwat.de> 24 * </pre> 25 * <div class="disclaimer"> 26 * This program is free software; you can redistribute it and/or modify 27 * it under the terms of the GNU General Public License as published by 28 * the Free Software Foundation; either 29 * <a href="http://www.gnu.org/licenses/gpl.html">version 3</a> of the 30 * License, or (at your option) any later version.<br> 31 * This software is distributed in the hope that it will be useful, 32 * but WITHOUT ANY WARRANTY; without even the implied warranty of 33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 * General Public License for more details. 35 * </div> 36 * @author <a href="mailto:support@mwat.de">Matthias Watermann</a> 37 * @version <tt>$Id: syntax_plugin_lang.php,v 1.4 2007/08/15 12:36:19 matthias Exp $</tt> 38 * @since created 1-Sep-2005 39 */ 40class syntax_plugin_lang extends DokuWiki_Syntax_Plugin { 41 42 /** 43 * @publicsection 44 */ 45 //@{ 46 47 /** 48 * Tell the parser whether the plugin accepts syntax mode 49 * <tt>$aMode</tt> within its own markup. 50 * 51 * @param $aMode String The requested syntaxmode. 52 * @return Boolean <tt>TRUE</tt> unless <tt>$aMode</tt> is 53 * <tt>plugin_lang</tt> (which would result in a 54 * <tt>FALSE</tt> method result). 55 * @public 56 * @see getAllowedTypes() 57 * @static 58 */ 59 function accepts($aMode) { 60 return ('plugin_lang' != $aMode); 61 } // accepts() 62 63 /** 64 * Connect lookup pattern to lexer. 65 * 66 * @param $aMode String The desired rendermode. 67 * @public 68 * @see render() 69 */ 70 function connectTo($aMode) { 71 // See http://www.w3.org/TR/html401/struct/dirlang.html#h-8.1.1; 72 // better (specialized) REs are used in 'handle()' method. 73 $this->Lexer->addEntryPattern( 74 '\x3Clang\s+[a-z\-A-Z0-9]{2,})?\s*\x3E\s*(?=(?s).*?\x3C\x2Flang\x3E)', 75 $aMode, 'plugin_lang'); 76 } // connectTo() 77 78 /** 79 * Get an associative array with plugin info. 80 * 81 * <p> 82 * The returned array holds the following fields: 83 * <dl> 84 * <dt>author</dt><dd>Author of the plugin</dd> 85 * <dt>email</dt><dd>Email address to contact the author</dd> 86 * <dt>date</dt><dd>Last modified date of the plugin in 87 * <tt>YYYY-MM-DD</tt> format</dd> 88 * <dt>name</dt><dd>Name of the plugin</dd> 89 * <dt>desc</dt><dd>Short description of the plugin (Text only)</dd> 90 * <dt>url</dt><dd>Website with more information on the plugin 91 * (eg. syntax description)</dd> 92 * </dl> 93 * @return Array Information about this plugin class. 94 * @public 95 * @static 96 */ 97 function getInfo() { 98 return array( 99 'author' => 'Matthias Watermann', 100 'email' => 'support@mwat.de', 101 'date' => '2007-08-15', 102 'name' => 'LANGuage Syntax Plugin', 103 'desc' => 'Markup a text area using another language', 104 'url' => 'http://wiki.splitbrain.org/plugin:lang'); 105 } // getInfo() 106 107 /** 108 * Where to sort in? 109 * 110 * @return Integer <tt>498</tt> (doesn't really matter). 111 * @public 112 * @static 113 */ 114 function getSort() { 115 return 498; 116 } // getSort() 117 118 /** 119 * Get the type of syntax this plugin defines. 120 * 121 * @return String <tt>'formatting'</tt>. 122 * @public 123 * @static 124 */ 125 function getType() { 126 return 'formatting'; 127 } // getType() 128 129 /** 130 * Handler to prepare matched data for the rendering process. 131 * 132 * <p> 133 * The <tt>$aState</tt> parameter gives the type of pattern 134 * which triggered the call to this method: 135 * </p> 136 * <dl> 137 * <dt>DOKU_LEXER_ENTER</dt> 138 * <dd>a pattern set by <tt>addEntryPattern()</tt></dd> 139 * <dt>DOKU_LEXER_MATCHED</dt> 140 * <dd>a pattern set by <tt>addPattern()</tt></dd> 141 * <dt>DOKU_LEXER_EXIT</dt> 142 * <dd> a pattern set by <tt>addExitPattern()</tt></dd> 143 * <dt>DOKU_LEXER_SPECIAL</dt> 144 * <dd>a pattern set by <tt>addSpecialPattern()</tt></dd> 145 * <dt>DOKU_LEXER_UNMATCHED</dt> 146 * <dd>ordinary text encountered within the plugin's syntax mode 147 * which doesn't match any pattern.</dd> 148 * </dl> 149 * @param $aMatch String The text matched by the patterns. 150 * @param $aState Integer The lexer state for the match. 151 * @param $aPos Integer The character position of the matched text. 152 * @param $aHandler Object Reference to the Doku_Handler object. 153 * @return Array Index <tt>[0]</tt> holds the current 154 * <tt>$aState</tt>, index <tt>[1]</tt> the match prepared for 155 * the <tt>render()</tt> method. 156 * @public 157 * @see render() 158 * @static 159 */ 160 function handle($aMatch, $aState, $aPos, &$aHandler) { 161 if (DOKU_LEXER_ENTER == $aState) { 162 $hits = array(); 163 // RFC 3066, "2. The Language tag", p. 2f. 164 // Language-Tag = Primary-subtag *( "-" Subtag ) 165 if (preg_match('|\s+([a-z]{2,3})\s*>|i', $aMatch, $hits)) { 166 // primary _only_ (most likely to be used) 167 return array($aState, $hits[1]); 168 } // if 169 if (preg_match('|\s+([a-z]{2,3}\-[a-z0-9]{2,})\s*>|i', 170 $aMatch, $hits)) { 171 // primary _and_ subtag 172 return array($aState, $hits[1]); 173 } // if 174 if (preg_match('|\s+([ix]\-[a-z0-9]{2,})\s*>|i', $aMatch, $hits)) { 175 // 1-letter primary _and_ subtag 176 return array($aState, $hits[1]); 177 } // if 178 if (preg_match('|\s+([a-z]{2,3})\-.*\s*>|i', $aMatch, $hits)) { 179 // convenience: accept primary with empty subtag 180 return array($aState, $hits[1]); 181 } // if 182 // invalid language specification 183 return array($aState, FALSE); 184 } // if 185 return array($aState, $aMatch); 186 } // handle() 187 188 /** 189 * Add exit pattern to lexer. 190 * 191 * @public 192 */ 193 function postConnect() { 194 $this->Lexer->addExitPattern('\x3C\x2Flang\x3E', 'plugin_lang'); 195 } // postConnect() 196 197 /** 198 * Handle the actual output creation. 199 * 200 * <p> 201 * The method checks for the given <tt>$aFormat</tt> and returns 202 * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt> 203 * contains a reference to the renderer object which is currently 204 * handling the rendering. The contents of <tt>$aData</tt> is the 205 * return value of the <tt>handle()</tt> method. 206 * </p> 207 * @param $aFormat String The output format to generate. 208 * @param $aRenderer Object A reference to the renderer object. 209 * @param $aData Array The data created by the <tt>handle()</tt> 210 * method. 211 * @return Boolean <tt>TRUE</tt> if rendered successfully, or 212 * <tt>FALSE</tt> otherwise. 213 * @public 214 * @see handle() 215 * 216 */ 217 function render($aFormat, &$aRenderer, &$aData) { 218 if ('xhtml' != $aFormat) { 219 return FALSE; 220 } // if 221 static $VALID = TRUE; // flag to notice invalid markup 222 switch ($aData[0]) { 223 case DOKU_LEXER_ENTER: 224 if ($aData[1]) { 225 $aRenderer->doc .= '<span lang="' . $aData[1] 226 . '" xml:lang="' . $aData[1] . '">'; 227 } else { 228 $VALID = FALSE; 229 } // if 230 return TRUE; 231 case DOKU_LEXER_UNMATCHED: 232 $aRenderer->doc .= str_replace(array('&','<', '>'), 233 array('&', '<', '>'), $aData[1]); 234 return TRUE; 235 case DOKU_LEXER_EXIT: 236 if ($VALID) { 237 $aRenderer->doc .= '</span>'; 238 } else { 239 $VALID = TRUE; 240 } // if 241 default: 242 return TRUE; 243 } // switch 244 } // render() 245 246 //@} 247} // class syntax_plugin_lang 248} // if 249?> 250