Index: trunk/tools/ToolserverI18N/TsIntuition.php |
— | — | @@ -0,0 +1,866 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * |
| 5 | + * Created on March 23, 2011 |
| 6 | + * |
| 7 | + * Copyright 2011 Krinkle <krinklemail@gmail.com> |
| 8 | + * |
| 9 | + * This file is licensed under |
| 10 | + * the Creative Commons Attribution 3.0 Unported License |
| 11 | + * <http://creativecommons.org/licenses/by/3.0/> |
| 12 | + * |
| 13 | + * @package TsIntuition |
| 14 | + */ |
| 15 | + |
| 16 | +// Protect against invalid entry |
| 17 | +if( !defined( 'TS_INTUITION' ) ) { |
| 18 | + echo "This file is part of TsIntuition and is not a valid entry point\n"; |
| 19 | + exit; |
| 20 | +} |
| 21 | + |
| 22 | +/** |
| 23 | + * This file contains the main class which the individual tools will |
| 24 | + * creating an instance of to use and configure their i18n. |
| 25 | + */ |
| 26 | +class TsIntuition { |
| 27 | + |
| 28 | + /* Variables |
| 29 | + * ------------------------------------------------- */ |
| 30 | + |
| 31 | + private $localBaseDir = '/home/krinkle/TsIntuition'; // to be moved to p_i18n |
| 32 | + |
| 33 | + private $suppresserrors = false; |
| 34 | + private $suppressnotices = true; |
| 35 | + private $stayalive = false; |
| 36 | + private $constructLang = false; |
| 37 | + private $currentTextdomain = 'general'; |
| 38 | + private $useRequestParam = true; |
| 39 | + |
| 40 | + private $currentLanguage = 'en'; |
| 41 | + |
| 42 | + // Changing this will invalidate all cookies |
| 43 | + private $cookieNames = array( 'userlang' => 'TsIntuition_userlang', 'track-expire' => 'TsIntuition_expiry' ); |
| 44 | + |
| 45 | + // Changing this will break existing permalinks |
| 46 | + private $paramNames = array( 'userlang' => 'userlang' ); |
| 47 | + |
| 48 | + // Here everything will be stored as arrays in arrays |
| 49 | + // Such as: $messageBlob['textdomain']['messagename']['langcode'] = 'Message string'; |
| 50 | + private $messageBlob = array(); |
| 51 | + |
| 52 | + // $loadedTextdomains[0] = 'general'; |
| 53 | + private $loadedTextdomains = array(); |
| 54 | + |
| 55 | + // Fallbacks are stored as an array of language codes |
| 56 | + // with their fallback as value |
| 57 | + // Such as Low German falling back to German: langFallbacks['nds'] = 'de'; |
| 58 | + private $langFallbacks = null; |
| 59 | + |
| 60 | + // Language names are stored as an array of language codes |
| 61 | + // with their native name as value |
| 62 | + // Such as as for Spanish: langNames['es'] = 'Español'; |
| 63 | + private $langNames = null; |
| 64 | + |
| 65 | + // This array keeps track of which languages are available in atleast one textdomain |
| 66 | + // $languages['en'] = true; |
| 67 | + private $availableLanguages = array(); |
| 68 | + |
| 69 | + // These variable names will be extracted from the message files |
| 70 | + private $includeVariables = array( 'messages' ); |
| 71 | + |
| 72 | + /* Init |
| 73 | + * ------------------------------------------------- */ |
| 74 | + |
| 75 | + /** |
| 76 | + * Initialize TsIntuition |
| 77 | + * |
| 78 | + * Pass a string (domain) or array (options) |
| 79 | + * |
| 80 | + * Options: |
| 81 | + * - suppresserrors |
| 82 | + * - suppressnotices |
| 83 | + * - stayalive |
| 84 | + * - globalfunctions |
| 85 | + * - lang |
| 86 | + * - domain |
| 87 | + * - param |
| 88 | + */ |
| 89 | + function __construct( $options = array() ) { |
| 90 | + if ( is_string( $options) ) { |
| 91 | + $options = array( 'domain' => $options ); |
| 92 | + } |
| 93 | + |
| 94 | + // Allow a tool to suppress errors, which will prevent TsIntuition from showing fatal errors |
| 95 | + if ( isset( $options['suppresserrors'] ) && $options['suppresserrors'] == true ) { |
| 96 | + $this->suppresserrors = true; |
| 97 | + $this->suppressnotices = true; |
| 98 | + } |
| 99 | + |
| 100 | + // Allow a tool to suppress errors, which will prevent TsIntuition from showing notices |
| 101 | + if ( isset( $options['suppressnotices'] ) && $options['suppressnotices'] == false ) { |
| 102 | + $this->suppressnotices = false; |
| 103 | + } |
| 104 | + |
| 105 | + // Allow a tool to prevent TsIntuition for exiting/dieing on fatal errors |
| 106 | + if ( isset( $options['stayalive'] ) && $options['stayalive'] == true ) { |
| 107 | + $this->stayalive = true; |
| 108 | + } |
| 109 | + |
| 110 | + // Allow a tool to disable the loading of global functions in case they have a _() and/or _e() already |
| 111 | + if ( !isset( $options['globalfunctions'] ) || $options['globalfunctions'] == true ) { |
| 112 | + require_once( $this->localBaseDir . '/Functions.php' ); |
| 113 | + } |
| 114 | + |
| 115 | + // If the tool doesn't want to use the cookie and parameter or would like to test something |
| 116 | + // The user language can be overridden here. Note you can also override it for individual |
| 117 | + // messages by passing the language code as third argument to msg(). |
| 118 | + if ( isset( $options['lang'] ) ) { |
| 119 | + $this->constructLang = $options['lang']; |
| 120 | + } |
| 121 | + |
| 122 | + // The textdomain of your tool can be set here. |
| 123 | + // Otherwise defaults to 'general'. See also documentation of msg() |
| 124 | + // First character is case-insensitive |
| 125 | + if ( isset( $options['domain'] ) ) { |
| 126 | + $this->setDomain( trim( lcfirst( $options['domain'] ) ) ); |
| 127 | + } |
| 128 | + |
| 129 | + // TsIntuition will choose the language based on a cookie. However it |
| 130 | + // can be manually overriden for permalinks through a request parameter. |
| 131 | + // By default this is 'userlang'. If you need this parameter for something else |
| 132 | + // you can disable this system here. To avoid inconsistencies between tools |
| 133 | + // a custom parameter name will not be supported. It's either on or off. |
| 134 | + if ( isset( $options['param'] ) ) { |
| 135 | + $this->setUseRequestParam( false ); |
| 136 | + } |
| 137 | + |
| 138 | + // Load the initial text domain |
| 139 | + $this->loadTextdomain( $this->getDomain() ); |
| 140 | + |
| 141 | + // Load fallbacks |
| 142 | + $this->loadFallbacks(); |
| 143 | + |
| 144 | + // Load names |
| 145 | + $this->loadNames(); |
| 146 | + |
| 147 | + // Initialize language choise |
| 148 | + $this->initLangSelect(); |
| 149 | + |
| 150 | + } |
| 151 | + |
| 152 | + |
| 153 | + /* Get/Set variables |
| 154 | + * ------------------------------------------------- */ |
| 155 | + |
| 156 | + public function getLang(){ |
| 157 | + return $this->currentLanguage; |
| 158 | + } |
| 159 | + |
| 160 | + /** |
| 161 | + * Set the current language which will be used when requesting messages etc. |
| 162 | + * @return true |
| 163 | + */ |
| 164 | + public function setLang( $lang ) { |
| 165 | + $this->currentLanguage = $lang; |
| 166 | + return true; |
| 167 | + } |
| 168 | + |
| 169 | + /** |
| 170 | + * Get an array of common locale values for setlocale() for |
| 171 | + * the current language. |
| 172 | + * |
| 173 | + * @param $lang string (optional) Pass a language code. Defaults to current language. |
| 174 | + * @return array |
| 175 | + */ |
| 176 | + public function getLocale( $lang = null, $utf8 = true ) { |
| 177 | + $suffixes = $utf8 ? array( '.UTF-8', '.UTF-8', '.utf8' ) : array( '' ); |
| 178 | + $normal = isset( $lang ) ? $lang : $this->getLang(); |
| 179 | + $normalUC = strtoupper( $normal ); |
| 180 | + |
| 181 | + // Get 'foo' from 'foo-bar' |
| 182 | + $parts = explode( '-', $normal ); |
| 183 | + $short = $parts[0]; |
| 184 | + $shortUC = strtoupper( $short ); |
| 185 | + |
| 186 | + $versions = array( |
| 187 | + $normal, // foo-br or en |
| 188 | + $normalUC, // FOO-BR or EN |
| 189 | + $short.'_'.$shortUC, // foo_FOO or en_EN |
| 190 | + $short, // foo or en |
| 191 | + $shortUC, // FOO or EN |
| 192 | + ); |
| 193 | + $return = array(); |
| 194 | + foreach ( $versions as $version ) { |
| 195 | + foreach( $suffixes as $suffix ) { |
| 196 | + $return[] = $version.$suffix; |
| 197 | + } |
| 198 | + } |
| 199 | + return array_values( array_unique( $return ) ); |
| 200 | + } |
| 201 | + |
| 202 | + public function getDomain(){ |
| 203 | + return $this->currentTextdomain; |
| 204 | + } |
| 205 | + |
| 206 | + /** |
| 207 | + * Set the current textdomain which will be used when requesting messages etc. |
| 208 | + * @return true |
| 209 | + */ |
| 210 | + public function setDomain( $domain ) { |
| 211 | + $this->currentTextdomain = $domain; |
| 212 | + return true; |
| 213 | + } |
| 214 | + |
| 215 | + /** |
| 216 | + * Cookie names may change over time, don't depend on them. |
| 217 | + * Each cookie-name has an alias (eg. 'userlang' instead of 'TsIntuition-pref_userlang') |
| 218 | + * Use getCookieName() if you only need a single value. |
| 219 | + * |
| 220 | + * @return array An array of aliases as keys and actual cookienames as values |
| 221 | + */ |
| 222 | + public function getCookieNames(){ |
| 223 | + return $this->cookieNames; |
| 224 | + } |
| 225 | + |
| 226 | + public function getCookieName( $name ) { |
| 227 | + return $this->cookieNames[$name]; |
| 228 | + } |
| 229 | + |
| 230 | + /** |
| 231 | + * Parameter names may change over time, don't depend on them. |
| 232 | + * Each paramter-name has an alias (so far the same as the actual value) |
| 233 | + * Use getParamName() if you only need a single value. |
| 234 | + * |
| 235 | + * @return array An array of aliases as keys and actual parameter names as values. |
| 236 | + */ |
| 237 | + public function getParamNames(){ |
| 238 | + return $this->paramNames; |
| 239 | + } |
| 240 | + |
| 241 | + public function getParamName( $name ) { |
| 242 | + return $this->paramNames[$name]; |
| 243 | + } |
| 244 | + |
| 245 | + /** |
| 246 | + * Whether or not the userlang-parameter is used to determine the |
| 247 | + * userlanguage during initialization. |
| 248 | + * |
| 249 | + * @return boolean |
| 250 | + */ |
| 251 | + public function getUseRequestParam(){ |
| 252 | + return $this->useRequestParam; |
| 253 | + } |
| 254 | + |
| 255 | + /** |
| 256 | + * Overwrite the setting to use or ignore the userlang-parameter. |
| 257 | + * Note that it's likely the language intitialization/detection has already |
| 258 | + * been ran. Call refreshLang() if you want it to re-check the cookies, |
| 259 | + * parameters, overwrites etc. |
| 260 | + * |
| 261 | + * @param $bool boolean True if you want it to use the parameter, false otherwise. |
| 262 | + * @return boolean False if the passed argument wasn't a boolean, true otherwise. |
| 263 | + */ |
| 264 | + public function setUseRequestParam( $bool ) { |
| 265 | + if ( is_bool( $bool ) ) { |
| 266 | + $this->useRequestParam = $bool; |
| 267 | + return true; |
| 268 | + } |
| 269 | + return false; |
| 270 | + } |
| 271 | + |
| 272 | + |
| 273 | + /* Message functions |
| 274 | + * ------------------------------------------------- */ |
| 275 | + |
| 276 | + /** |
| 277 | + * Get a message from the message blob |
| 278 | + * |
| 279 | + * @param $key string Message key to retrieve a message for. |
| 280 | + * @param $options mixed (optional) A textdomain-name or an array with one or more |
| 281 | + * of the following options: |
| 282 | + * - domain: overrides the currently selected textdomain, and if needed loads it from disk |
| 283 | + * - lang: overrides the currently selected language |
| 284 | + * - variables: numerical array to do variable replacements ($1> var[0], $2> var[1], etc.) |
| 285 | + * - raw-variables: boolean to determine whether the variables should be escaped as well |
| 286 | + * - escape: Optionally the return can be escaped. By default this takes place after variable |
| 287 | + * replacement. Set 'raw-variables' to true if you just want the raw message |
| 288 | + * to be escaped and have escaped the variables already. |
| 289 | + * - * 'plain' |
| 290 | + * - * 'html' (<>"& escaped) |
| 291 | + * - * 'htmlspecialchars' (alias of 'html') |
| 292 | + * - * 'htmlentities' (foreign/UTF-8 chars converted as well) |
| 293 | + * |
| 294 | + */ |
| 295 | + public function msg( $key = 0, $options = array() ) { |
| 296 | + |
| 297 | + // Make sure a proper key was passed. |
| 298 | + if ( !TsIntuitionUtil::nonEmptyStr( $key ) ) { |
| 299 | + return $this->bracketMsg( $key ); |
| 300 | + } |
| 301 | + |
| 302 | + $defaultOptions = array( |
| 303 | + 'domain' => $this->getDomain(), |
| 304 | + 'lang' => $this->getLang(), |
| 305 | + 'variables' => array(), |
| 306 | + 'raw-variables' => false, |
| 307 | + 'escape' => 'plain', |
| 308 | + ); |
| 309 | + |
| 310 | + // If $options was a domain string, convert it now. |
| 311 | + if ( TsIntuitionUtil::nonEmptyStr( $options ) ) { |
| 312 | + $options = array( 'domain' => $options ); |
| 313 | + } |
| 314 | + |
| 315 | + // If $options is still not an array, ignore it and use default |
| 316 | + // Otherwise merge the options with the defaults. |
| 317 | + if ( !is_array( $options ) ) { |
| 318 | + $options = $defaultOptions; |
| 319 | + } else { |
| 320 | + $options = array_merge( $defaultOptions, $options ); |
| 321 | + } |
| 322 | + |
| 323 | + // First character of the message-key is case-insensitive. |
| 324 | + $key = trim( lcfirst( $key ) ); |
| 325 | + |
| 326 | + // Load if not already loaded |
| 327 | + $this->loadTextdomain( $options['domain'] ); |
| 328 | + |
| 329 | + // In case the domainname was invalid or inexistant |
| 330 | + if ( !isset( $this->messageBlob[$options['domain']] ) ) { |
| 331 | + return $this->bracketMsg( $key ); |
| 332 | + } |
| 333 | + |
| 334 | + // Use fallback if this message doesn't exist in the current language |
| 335 | + $lang = $this->getLangForTextdomain( $options['lang'], $options['domain'], $key ); |
| 336 | + |
| 337 | + // Just in case, one last check: |
| 338 | + if ( isset( $this->messageBlob[$options['domain']][$lang][$key] ) ) { |
| 339 | + // We're ok, let's grab it |
| 340 | + $msg = $this->messageBlob[$options['domain']][$lang][$key]; |
| 341 | + } else { |
| 342 | + // Fall back to a simple [keyname] |
| 343 | + return $this->bracketMsg( $key ); |
| 344 | + } |
| 345 | + |
| 346 | + /* Now that we've got the message, do post-processing. */ |
| 347 | + |
| 348 | + $escapeDone = false; |
| 349 | + |
| 350 | + // Escape now or do it after variable replacement ? |
| 351 | + if ( $options['raw-variables'] === true ) { |
| 352 | + $msg = TsIntuitionUtil::strEscape( $msg, $options['escape'] ); |
| 353 | + $escapeDone = true; |
| 354 | + } |
| 355 | + |
| 356 | + // Variable replacements |
| 357 | + foreach ( $options['variables'] as $i => $val ) { |
| 358 | + $n = $i + 1; |
| 359 | + $msg = str_replace( "\$$n", $val, $msg ); |
| 360 | + } |
| 361 | + |
| 362 | + // If not already escaped, do it now |
| 363 | + if ( !$escapeDone ) { |
| 364 | + $escapeDone = true; |
| 365 | + $msg = TsIntuitionUtil::strEscape( $msg, $options['escape'] ); |
| 366 | + } |
| 367 | + |
| 368 | + // Finally |
| 369 | + return $msg; |
| 370 | + |
| 371 | + } |
| 372 | + |
| 373 | + /** |
| 374 | + * Don't show [brackets] when suppressing errors. |
| 375 | + * In that case there could be message files missing and invalid language codes chosen. |
| 376 | + * Just return a somewhat readable string. |
| 377 | + * We use square brackets for simplicity sake, using inequality brackets (< >) may cause |
| 378 | + * conflicts with HTML when used wrong. |
| 379 | + */ |
| 380 | + public function bracketMsg( $key ) { |
| 381 | + if ( $this->suppresserrors ) { |
| 382 | + return ucfirst( $key ); // Keyname |
| 383 | + } |
| 384 | + return "[$key]"; // [keyname] |
| 385 | + } |
| 386 | + |
| 387 | + /** |
| 388 | + * Adds or overwrites a message in the blob. |
| 389 | + * This function is public so tools can use it while testing their tools |
| 390 | + * and don't need a message to exist in TranslateWiki yet, but don't want to see [msgkey] either. |
| 391 | + * See also addMsgs() for registering multiple messages. |
| 392 | + * |
| 393 | + * First two parameters are required. Others (domain, language) default to current environment. |
| 394 | + */ |
| 395 | + public function setMsg( $key, $message, $domain = 0, $lang = 0 ) { |
| 396 | + |
| 397 | + if ( !TsIntuitionUtil::nonEmptyStr( $domain ) ) { |
| 398 | + $domain = $this->getDomain(); |
| 399 | + } |
| 400 | + if ( !TsIntuitionUtil::nonEmptyStr( $lang ) ) { |
| 401 | + $lang = $this->getLang(); |
| 402 | + } |
| 403 | + $this->messageBlob[$domain][$lang][$key] = $message; |
| 404 | + } |
| 405 | + |
| 406 | + /** |
| 407 | + * Set multiple messages in the blob. |
| 408 | + * |
| 409 | + * First parameter is required. Others (domain, language) default to current environment. |
| 410 | + */ |
| 411 | + public function setMsgs( $messagesByKeys, $domain = 0, $lang = 0 ) { |
| 412 | + foreach ( $messagesByKeys as $key => $message ) { |
| 413 | + $this->setMsg( $key, $message, $domain, $lang); |
| 414 | + } |
| 415 | + } |
| 416 | + |
| 417 | + |
| 418 | + /* Lang functions |
| 419 | + * ------------------------------------------------- */ |
| 420 | + |
| 421 | + /** |
| 422 | + * Calculate which language can be used for the message |
| 423 | + * in the given domain. If possible, returns the $lang |
| 424 | + * passed right away, otherwise it looks for a suitable falback |
| 425 | + * |
| 426 | + * @param $lang string Preferred language |
| 427 | + * @param $domain string Domain to search within (the existance of this domain should be checked |
| 428 | + * before calling this function). |
| 429 | + * @param $key string Key of the wanted message |
| 430 | + * @return string Language code |
| 431 | + */ |
| 432 | + private function getLangForTextdomain( $lang, $domain, $key ) { |
| 433 | + $msgDomain = $this->messageBlob[$domain]; |
| 434 | + |
| 435 | + // If it's available, just use it |
| 436 | + if ( isset( $msgDomain[$lang] ) && isset( $msgDomain[$lang][$key] ) ) { |
| 437 | + return $lang; |
| 438 | + } |
| 439 | + |
| 440 | + // Otherwise use the fallback |
| 441 | + $lang = $this->getLangFallback( $lang ); |
| 442 | + if ( isset( $msgDomain[$lang] ) && isset( $msgDomain[$lang][$key] ) ) { |
| 443 | + return $lang; |
| 444 | + } |
| 445 | + |
| 446 | + // Otherwise use the fallback's fallback |
| 447 | + $lang = $this->getLangFallback( $lang ); |
| 448 | + if ( isset( $msgDomain[$lang] ) && isset( $msgDomain[$lang][$key] ) ) { |
| 449 | + return $lang; |
| 450 | + } |
| 451 | + |
| 452 | + // Otherwise default to English |
| 453 | + return 'en'; |
| 454 | + } |
| 455 | + |
| 456 | + /** |
| 457 | + * Return the fallback language for the given language (if available) |
| 458 | + * returns 'en' otherwise. |
| 459 | + * |
| 460 | + * @param $lang string Language code of language to get fallback for. |
| 461 | + * @return string |
| 462 | + */ |
| 463 | + public function getLangFallback( $lang ) { |
| 464 | + |
| 465 | + return isset( $this->langFallbacks[$lang] ) ? $this->langFallbacks[$lang] : 'en'; |
| 466 | + } |
| 467 | + |
| 468 | + /** |
| 469 | + * Return the language name in the native language. |
| 470 | + * @param $lang string Language code |
| 471 | + * @return string |
| 472 | + */ |
| 473 | + public function getLangName( $lang ) { |
| 474 | + |
| 475 | + return isset( $this->langNames[$lang] ) ? $this->langNames[$lang] : ''; |
| 476 | + } |
| 477 | + |
| 478 | + /** |
| 479 | + * Return all known languages. |
| 480 | + * @return array |
| 481 | + */ |
| 482 | + public function getLangNames() { |
| 483 | + |
| 484 | + return is_array( $this->langNames ) ? $this->langNames : array(); |
| 485 | + } |
| 486 | + |
| 487 | + |
| 488 | + /* Textdomain functions |
| 489 | + * ------------------------------------------------- */ |
| 490 | + |
| 491 | + public function loadTextdomain( $domain ) { |
| 492 | + |
| 493 | + // Generally validate input and protect against path traversal |
| 494 | + if ( !TsIntuitionUtil::nonEmptyStr( $domain ) || $domain !== trim( strtolower( $domain ) ) || strcspn( $domain, ":/\\\000" ) !== strlen( $domain ) ) { |
| 495 | + $this->errTrigger( "Invalid textdomain \"$domain\"", __METHOD__, E_NOTICE ); |
| 496 | + return false; |
| 497 | + } |
| 498 | + |
| 499 | + // Already loaded ? |
| 500 | + if ( in_array( $domain, $this->loadedTextdomains ) ) { |
| 501 | + return false; |
| 502 | + } |
| 503 | + |
| 504 | + $this->loadedTextdomains[] = $domain; |
| 505 | + |
| 506 | + // File exists ? |
| 507 | + $displayname = ucfirst( strtolower( $domain ) ); |
| 508 | + $path = $this->localBaseDir . "/language/messages/$displayname.i18n.php"; |
| 509 | + if ( !file_exists( $path ) ) { |
| 510 | + $this->errTrigger( "Textdomain file not found for \"$domain\" at $path. Ignoring", __METHOD__, E_NOTICE, __FILE__, __LINE__ ); |
| 511 | + return false; |
| 512 | + } |
| 513 | + |
| 514 | + // Load it |
| 515 | + $load = $this->loadTextdomainFromFile( $path, $domain ); |
| 516 | + |
| 517 | + return !!$load; |
| 518 | + |
| 519 | + } |
| 520 | + |
| 521 | + public function loadTextdomainFromFile( $filePath = '', $domain = '' ) { |
| 522 | + if ( !TsIntuitionUtil::nonEmptyStrs( $filePath, $domain ) ) { |
| 523 | + $this->errTrigger( 'One or more arguments are missing', __METHOD__, E_NOTICE, __FILE__, __LINE__ ); |
| 524 | + return false; |
| 525 | + } |
| 526 | + |
| 527 | + // Load it |
| 528 | + include( $filePath ); |
| 529 | + |
| 530 | + // Parse it |
| 531 | + $compact = compact( $this->includeVariables ); |
| 532 | + $this->parseTextdomain( $compact, $domain, $filePath ); |
| 533 | + return true; |
| 534 | + } |
| 535 | + |
| 536 | + private function parseTextdomain( $data, $domain, $filePath ) { |
| 537 | + if ( !is_array( $data ) ) { |
| 538 | + $this->errTrigger( 'Invalid $data passed to ' . __FUNCTION__, __METHOD__, E_ERROR, __FILE__, __LINE__ ); |
| 539 | + } |
| 540 | + // Were there any message defined in the textdomain file ? |
| 541 | + if ( !isset( $data['messages'] ) || !is_array( $data['messages'] ) ) { |
| 542 | + $this->errTrigger( 'No $messages array found', __METHOD__ , E_ERROR, $filePath ); |
| 543 | + } |
| 544 | + // Load the message into the blob |
| 545 | + // overwrites the existing array of messages if it already existed |
| 546 | + // If you need to add or overwrite some messages temporarily, use Itui::setMsg() or Itui::setMsgs() instead |
| 547 | + foreach ( $data['messages'] as $langcode => $messages ) { |
| 548 | + $this->availableLanguages[$langcode] = true; |
| 549 | + $this->messageBlob[$domain][$langcode] = (array)$messages; |
| 550 | + } |
| 551 | + |
| 552 | + |
| 553 | + return true; |
| 554 | + } |
| 555 | + |
| 556 | + |
| 557 | + /* Cookie functions |
| 558 | + * ------------------------------------------------- */ |
| 559 | + |
| 560 | + /** |
| 561 | + * Set a cookie. |
| 562 | + * |
| 563 | + * @param $name string Canonical name of the cookie. |
| 564 | + * @param $val string Value to be set. |
| 565 | + * @param $lifetime int Lifetime in seconds from now. |
| 566 | + * |
| 567 | + * @return boolean |
| 568 | + */ |
| 569 | + public function setCookie( $name, $val, $lifetime = 2592000 /* 30 days */, $track = true ) { |
| 570 | + // Validate cookie name |
| 571 | + $name = $this->getCookieName( $name ); |
| 572 | + if ( !$name ) { |
| 573 | + return false; |
| 574 | + } |
| 575 | + $val = strval( $val ); |
| 576 | + $lifetime = intval( $lifetime ); |
| 577 | + $expire = time() + $lifetime; |
| 578 | + |
| 579 | + // Set a 30-day domain-wide cookie |
| 580 | + setcookie( $name, $val, $expire, '/', '.toolserver.org' ); |
| 581 | + |
| 582 | + // In order to keep track of the expiration date, we set another cookie |
| 583 | + if ( $track ) { |
| 584 | + $this->setExpiryTrackerCookie( $lifetime ); |
| 585 | + } |
| 586 | + |
| 587 | + return true; |
| 588 | + } |
| 589 | + |
| 590 | + /** |
| 591 | + * @DOCME |
| 592 | + */ |
| 593 | + private function setExpiryTrackerCookie( $lifetime ) { |
| 594 | + $expire = time() + intval( $lifetime ); |
| 595 | + setcookie( $this->getCookieName( 'track-expire' ), $expire, $expire, '/', '.toolserver.org' ); |
| 596 | + return true; |
| 597 | + } |
| 598 | + |
| 599 | + /** |
| 600 | + * Renew all cookies |
| 601 | + */ |
| 602 | + public function renewCookies( $lifetime = 2592000 /* 30 days */ ) { |
| 603 | + foreach( $this->getCookieNames() as $name ) { |
| 604 | + $this->setCookie( $name, $_COOKIE[$name], $lifetime, false ); |
| 605 | + } |
| 606 | + $this-setExpiryTrackerCookie(); |
| 607 | + return true; |
| 608 | + } |
| 609 | + |
| 610 | + /** |
| 611 | + * Delete all TsIntuition cookies. |
| 612 | + * It's recommended to redirectTo() directly after this. |
| 613 | + * @return boolean |
| 614 | + */ |
| 615 | + public function wipeCookies(){ |
| 616 | + $week = 7*24*3600; |
| 617 | + foreach( $this->getCookieNames() as $name ) { |
| 618 | + setcookie( $name, '', time()-$week, '/', '.toolserver.org' ); |
| 619 | + unset( $_COOKIE[$name] ); |
| 620 | + } |
| 621 | + return true; |
| 622 | + } |
| 623 | + |
| 624 | + /** |
| 625 | + * Get expiration timestamp. |
| 626 | + * @return integer Unix timestamp of expiration date or 0 if not available. |
| 627 | + */ |
| 628 | + public function getCookieExpiration(){ |
| 629 | + $name = $this->getCookieName( 'track-expire' ); |
| 630 | + $expire = isset( $_COOKIE[$name] ) ? intval( $_COOKIE[$name] ) : 0; |
| 631 | + return $expire; |
| 632 | + } |
| 633 | + |
| 634 | + /** |
| 635 | + * Get expected lifetime left in seconds. |
| 636 | + * Returns 0 if expired or unavailable. |
| 637 | + */ |
| 638 | + public function getCookieLifetime(){ |
| 639 | + $expire = $this->getCookieExpiration(); |
| 640 | + $lifetime = $expire - time(); |
| 641 | + // If already expired (-xxx), return 0 |
| 642 | + return $lifetime < 0 ? 0 : $lifetime; |
| 643 | + } |
| 644 | + |
| 645 | + |
| 646 | + /* Other functions |
| 647 | + * ------------------------------------------------- */ |
| 648 | + |
| 649 | + /** |
| 650 | + * Redirect or refrsh to url. |
| 651 | + * |
| 652 | + * @return false on failure. |
| 653 | + */ |
| 654 | + public function redirectTo( $url = 0, $code = 302 ) { |
| 655 | + if ( !is_string( $url ) || !is_int( $code ) ) { |
| 656 | + return false; |
| 657 | + } |
| 658 | + header( 'Content-Type: text/html; charset=utf-8' ); |
| 659 | + header( "Location: $url", true, $code ); |
| 660 | + exit; |
| 661 | + } |
| 662 | + |
| 663 | + /** |
| 664 | + * Get a localized date. Pass a format, time or both. |
| 665 | + * Defaults to the current timestamp in the language's default date format. |
| 666 | + * |
| 667 | + * @param $format string Date format compatible with strftime() |
| 668 | + * @param $timestamp mixed Timestamp (seconds since unix epoch) or string (ie. "2011-12-31") |
| 669 | + * @param $lang string Language code. Defaults to current langauge (through getLocale() ) |
| 670 | + * |
| 671 | + * @return string |
| 672 | + */ |
| 673 | + public function dateFormatted( $first = null, $second = null, $lang = null ) { |
| 674 | + |
| 675 | + // One argument or less |
| 676 | + if ( is_null( $second ) ) { |
| 677 | + |
| 678 | + // No arguments |
| 679 | + if ( is_null( $first ) ) { |
| 680 | + $format = $this->msg( 'dateformat', 'general' ); |
| 681 | + $timestamp = time(); |
| 682 | + |
| 683 | + // Timestamp only |
| 684 | + } elseif ( is_int( $first ) ) { |
| 685 | + $format = $this->msg( 'dateformat', 'general' ); |
| 686 | + $timestamp = $first; |
| 687 | + |
| 688 | + // Date string only |
| 689 | + } elseif ( strtotime( $first ) ) { |
| 690 | + $format = $this->msg( 'dateformat', 'general' ); |
| 691 | + $timestamp = strtotime( $first ); |
| 692 | + |
| 693 | + // Format only |
| 694 | + } else { |
| 695 | + $format = $first; |
| 696 | + $timestamp = time(); |
| 697 | + } |
| 698 | + |
| 699 | + // Two arguments |
| 700 | + } else { |
| 701 | + $format = $first; |
| 702 | + $timestamp = is_int( $second ) ? $second : strtotime( $second ); |
| 703 | + } |
| 704 | + |
| 705 | + // Save current setlocale |
| 706 | + $saved = setlocale( LC_ALL, 0 ); |
| 707 | + |
| 708 | + // Overwrite for current language |
| 709 | + setlocale( LC_ALL, $this->getLocale( $lang ) ); |
| 710 | + $return = strftime( $format, $timestamp ); |
| 711 | + |
| 712 | + // Reset back to what it was |
| 713 | + setlocale( LC_ALL, $saved ); |
| 714 | + |
| 715 | + return $return; |
| 716 | + |
| 717 | + } |
| 718 | + |
| 719 | + /** |
| 720 | + * Load fallbacks |
| 721 | + * |
| 722 | + * @private |
| 723 | + * |
| 724 | + * @return true |
| 725 | + */ |
| 726 | + private function loadFallbacks(){ |
| 727 | + |
| 728 | + // Don't load twice |
| 729 | + if ( is_array( $this->langFallbacks ) ) { |
| 730 | + return false; |
| 731 | + } |
| 732 | + |
| 733 | + $path = $this->localBaseDir . '/language/Fallbacks.php'; |
| 734 | + if ( !file_exists( $path ) ) { |
| 735 | + $this->errTrigger( 'Fallbacks.php is missing', __METHOD__, E_NOTICE, __FILE__, __LINE__ ); |
| 736 | + return false; |
| 737 | + } |
| 738 | + |
| 739 | + // Load it |
| 740 | + $fallbacks = array(); |
| 741 | + include( $path ); |
| 742 | + $this->langFallbacks = $fallbacks; |
| 743 | + |
| 744 | + return true; |
| 745 | + } |
| 746 | + |
| 747 | + /** |
| 748 | + * Load names |
| 749 | + * |
| 750 | + * @private |
| 751 | + * |
| 752 | + * @return true |
| 753 | + */ |
| 754 | + private function loadNames(){ |
| 755 | + |
| 756 | + // Don't load twice |
| 757 | + if ( is_array( $this->langNames ) ) { |
| 758 | + return false; |
| 759 | + } |
| 760 | + |
| 761 | + $path = $this->localBaseDir . '/language/Names.php'; |
| 762 | + if ( !file_exists( $path ) ) { |
| 763 | + $this->errTrigger( 'Names.php is missing', __METHOD__, E_NOTICE, __FILE__, __LINE__ ); |
| 764 | + return false; |
| 765 | + } |
| 766 | + |
| 767 | + // Load it |
| 768 | + $wgLanguageNames = array(); |
| 769 | + include( $path ); |
| 770 | + $this->langNames = $wgLanguageNames; |
| 771 | + |
| 772 | + return true; |
| 773 | + } |
| 774 | + |
| 775 | + /** |
| 776 | + * Check language choise tree in the following order: |
| 777 | + * - First: Construct override |
| 778 | + * - Second: Parameter override |
| 779 | + * - Third: Saved cookie |
| 780 | + * - Fourth: Nothing (default stays) |
| 781 | + * |
| 782 | + * @private |
| 783 | + * |
| 784 | + * @return true |
| 785 | + */ |
| 786 | + private function initLangSelect() { |
| 787 | + $set = false; |
| 788 | + if ( $this->constructLang ) { |
| 789 | + $set = $this->setLang( $this->constructLang ); |
| 790 | + } |
| 791 | + if ( !$set && $this->getUseRequestParam() === true && isset( $_GET[ $this->paramNames['userlang'] ] ) ) { |
| 792 | + $set = $this->setLang( $_GET[ $this->paramNames['userlang'] ] ); |
| 793 | + } |
| 794 | + if ( !$set && isset( $_COOKIE[ $this->cookieNames['userlang'] ] ) ) { |
| 795 | + $set = $this->setLang( $_COOKIE[ $this->cookieNames['userlang'] ] ); |
| 796 | + } |
| 797 | + return $set; |
| 798 | + } |
| 799 | + |
| 800 | + /** |
| 801 | + * Redo language init |
| 802 | + * Use this when you've messaged with the cookies and don't want to refresh |
| 803 | + * for it to be applied |
| 804 | + * @return true |
| 805 | + */ |
| 806 | + public function refreshLang(){ |
| 807 | + $this->initLangSelect(); |
| 808 | + return true; |
| 809 | + } |
| 810 | + |
| 811 | + private function errMsg( $msg, $context ) { |
| 812 | + return htmlentities( "[$context] $msg", ENT_QUOTES, 'UTF-8' ); |
| 813 | + } |
| 814 | + |
| 815 | + // Custom version of trigger_error() that can be passed a custom filename and line number |
| 816 | + private function errTrigger( $msg, $context, $level = E_WARNING, $file = '', $line = '' ) { |
| 817 | + $die = false; |
| 818 | + $error = false; |
| 819 | + $notice = false; |
| 820 | + switch ( $level ) { |
| 821 | + // Fatal |
| 822 | + case E_ERROR: |
| 823 | + case E_CORE_ERROR: |
| 824 | + case E_COMPILE_ERROR: |
| 825 | + case E_USER_ERROR: |
| 826 | + case E_RECOVERABLE_ERROR: |
| 827 | + $code = 'Fatal error: '; |
| 828 | + $error = true; |
| 829 | + $die = true; |
| 830 | + break; |
| 831 | + |
| 832 | + // Warning |
| 833 | + case E_WARNING: |
| 834 | + case E_CORE_WARNING: |
| 835 | + case E_COMPILE_WARNING: |
| 836 | + case E_USER_WARNING: |
| 837 | + $code = 'Warning: '; |
| 838 | + $error = true; |
| 839 | + break; |
| 840 | + |
| 841 | + // Notice |
| 842 | + case E_NOTICE: |
| 843 | + $code = 'Notice: '; |
| 844 | + $notice = true; |
| 845 | + break; |
| 846 | + |
| 847 | + // Unknown |
| 848 | + default: |
| 849 | + $code = 'Unknown error: '; |
| 850 | + } |
| 851 | + |
| 852 | + if ( $error && $this->suppresserrors ) { |
| 853 | + return; |
| 854 | + } |
| 855 | + if ( $notice && $this->suppressnotices ) { |
| 856 | + return; |
| 857 | + } |
| 858 | + |
| 859 | + echo "\n<strong>$code</strong>" . $this->errMsg( $msg, $context ) . ( $file != '' ? " in <strong>$file</strong>" : '' ) . ( $line != '' ? " on line <strong>$line</strong>" : '' ) . '.' ; |
| 860 | + |
| 861 | + if ( $die && !$this->stayalive ) { |
| 862 | + die; |
| 863 | + } else { |
| 864 | + echo "<br />\n"; |
| 865 | + } |
| 866 | + } |
| 867 | +} |
Property changes on: trunk/tools/ToolserverI18N/TsIntuition.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 868 | + native |
Index: trunk/tools/ToolserverI18N/ToolStart.php |
— | — | @@ -0,0 +1,18 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * |
| 5 | + * Created on March 23, 2011 |
| 6 | + * |
| 7 | + * @package TsIntuition |
| 8 | + */ |
| 9 | + |
| 10 | +/** |
| 11 | + * This file loads everything the individual tools need. |
| 12 | + */ |
| 13 | + |
| 14 | +// This is a valid entry, define true |
| 15 | +define( 'TS_INTUITION', true ); |
| 16 | + |
| 17 | +// Files |
| 18 | +require_once( __DIR__ . '/TsIntuitionUtil.php' ); |
| 19 | +require_once( __DIR__ . '/TsIntuition.php' ); |
Property changes on: trunk/tools/ToolserverI18N/ToolStart.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 20 | + native |
Added: svn:executable |
2 | 21 | + * |
Index: trunk/tools/ToolserverI18N/public_html/main.css |
— | — | @@ -0,0 +1,66 @@ |
| 2 | +.cookie-health.perfect { |
| 3 | + background: rgb(0, 215, 0); |
| 4 | +} |
| 5 | +.cookie-health.good { |
| 6 | + background: rgb(255, 215, 0); |
| 7 | +} |
| 8 | +.cookie-health.bad { |
| 9 | + background: rgb(255, 165, 0); |
| 10 | +} |
| 11 | +.cookie-health.worst { |
| 12 | + background: rgb(255, 0, 0); |
| 13 | +} |
| 14 | + |
| 15 | + |
| 16 | +/* Clean forms */ |
| 17 | +form.cleanform { |
| 18 | + width: 100% |
| 19 | +} |
| 20 | +form.cleanform fieldset { |
| 21 | + border: 1px solid threedface; |
| 22 | + padding: 10px } |
| 23 | +form.cleanform fieldset legend { |
| 24 | + font-size: 1.1em; |
| 25 | + padding: 0px 5px } |
| 26 | +form.cleanform label { |
| 27 | + display: block; |
| 28 | + float: left; |
| 29 | + margin: 5px 0px 0px; |
| 30 | + padding: 0px; |
| 31 | + text-align: right; |
| 32 | + width: 210px; |
| 33 | +} |
| 34 | +form.cleanform input { |
| 35 | + padding: 5px 8px; |
| 36 | + display: inline-block; |
| 37 | +} |
| 38 | +form.cleanform input, |
| 39 | +form.cleanform select, |
| 40 | +form.cleanform textarea, |
| 41 | +form.cleanform span { |
| 42 | + margin: 5px 0px 3px 10px; |
| 43 | + width: auto; |
| 44 | + padding: 5px 8px; |
| 45 | +} |
| 46 | +form.cleanform input[type=text], |
| 47 | +form.cleanform input[type=password] { |
| 48 | + border: 1px solid #CCC; |
| 49 | + width: 240px; |
| 50 | + font-size: 1.1em; |
| 51 | +} |
| 52 | +form.cleanform select { |
| 53 | + position: relative !important; |
| 54 | +} |
| 55 | +form.cleanform br, |
| 56 | +form.cleanform span { |
| 57 | + clear: both; |
| 58 | +} |
| 59 | +form.cleanform span { |
| 60 | + display: block; |
| 61 | + margin: -3px 0px 3px 160px; |
| 62 | + padding: 0; |
| 63 | + text-align: left; |
| 64 | + font-style: italic; |
| 65 | + font-size: smaller; |
| 66 | + clear: left; |
| 67 | +} |
Property changes on: trunk/tools/ToolserverI18N/public_html/main.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 68 | + native |
Index: trunk/tools/ToolserverI18N/public_html/index.php |
— | — | @@ -0,0 +1,162 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * |
| 5 | + * Created on March 24, 2011 |
| 6 | + * |
| 7 | + * Copyright 2011 Krinkle <krinklemail@gmail.com> |
| 8 | + * |
| 9 | + * This file is licensed under |
| 10 | + * the Creative Commons Attribution 3.0 Unported License |
| 11 | + * <http://creativecommons.org/licenses/by/3.0/> |
| 12 | + * |
| 13 | + * @package TsIntuition |
| 14 | + */ |
| 15 | + |
| 16 | +/** |
| 17 | + * This file outputs the interface to set settings for TsIntuition |
| 18 | + * @TODO: Make this nicer, for now just a quick hack to make |
| 19 | + * setting cookies work. |
| 20 | + */ |
| 21 | + |
| 22 | + |
| 23 | +/** |
| 24 | + * Localization |
| 25 | + * ------------------------------------------------- |
| 26 | + */ |
| 27 | +require_once( '/home/krinkle/TsIntuition/ToolStart.php' ); // to be moved to p_i18n |
| 28 | +$opts = array( |
| 29 | + 'domain' => 'tsintuition', |
| 30 | + 'suppressnotices' => false, // DEBUG |
| 31 | +); |
| 32 | +$I18N = new TsIntuition( $opts ); |
| 33 | + |
| 34 | +/** |
| 35 | + * Configuration |
| 36 | + * ------------------------------------------------- |
| 37 | + */ |
| 38 | +require_once( '/home/krinkle/common/InitTool.php' ); |
| 39 | + |
| 40 | +$toolConfig = array( |
| 41 | + 'displayTitle' => _( 'fullname' ), |
| 42 | + 'krinklePrefix' => false, |
| 43 | + 'simplePath' => '/TsIntuition/', |
| 44 | + 'revisionId' => '0.1.0', |
| 45 | + 'revisionDate' => $I18N->dateFormatted( '2011-03-15' ), |
| 46 | + 'styles' => array( 'main.css' ), |
| 47 | +); |
| 48 | + |
| 49 | +$Tool = BaseTool::newFromArray( $toolConfig ); |
| 50 | + |
| 51 | +$Tool->doHtmlHead(); |
| 52 | +$Tool->doStartBodyWrapper(); |
| 53 | + |
| 54 | + |
| 55 | +/** |
| 56 | + * Post actions |
| 57 | + * ------------------------------------------------- |
| 58 | + */ |
| 59 | +if ( isset( $_POST['action'] ) ) { |
| 60 | + |
| 61 | + switch ( $_POST['action'] ) { |
| 62 | + case 'prefset': |
| 63 | + // Set a 30-day, then redirect to index |
| 64 | + $I18N->setCookie( 'userlang', $_POST['fpLang'] ); |
| 65 | + $I18N->redirectTo( $Tool->remoteBasePath, 302 ); |
| 66 | + break; |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | + |
| 71 | +/** |
| 72 | + * Get actions |
| 73 | + * ------------------------------------------------- |
| 74 | + */ |
| 75 | +if ( isset( $_GET['action'] ) ) { |
| 76 | + |
| 77 | + switch ( $_GET['action'] ) { |
| 78 | + case 'clearcookies': |
| 79 | + $I18N->wipeCookies(); |
| 80 | + $I18N->redirectTo( $Tool->remoteBasePath, 302 ); |
| 81 | + break; |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +/** |
| 86 | + * Body (Just a quick hack for proof-of-concept) |
| 87 | + * ------------------------------------------------- |
| 88 | + */ |
| 89 | +$Tool->addOut( _g( 'welcome' ), 'h2' ); |
| 90 | + |
| 91 | +// Cookie has already been set, show "current-settings" box |
| 92 | +if ( isset( $_COOKIE[ $I18N->getCookieName( 'userlang' ) ] ) ) { |
| 93 | + |
| 94 | + $lifetime = $I18N->getCookieLifetime(); |
| 95 | + // 29+ days |
| 96 | + if ( $lifetime > 29*24*3600 ) { |
| 97 | + $class = 'perfect'; |
| 98 | + $time = floor( $lifetime/3600/24/7 ) . '+ ' . _g('weeks'); |
| 99 | + |
| 100 | + // 10+ days |
| 101 | + } elseif ( $lifetime > 10*24*3600 ) { |
| 102 | + $class = 'good'; |
| 103 | + $time = floor( $lifetime/3600/24 ) . '+ ' . _g('days'); |
| 104 | + |
| 105 | + // 1+ day |
| 106 | + } elseif ( $lifetime > 24*3600 ) { |
| 107 | + $class = 'bad'; |
| 108 | + $time = floor( $lifetime/3600/24 ) . '+ ' . _g('days'); |
| 109 | + |
| 110 | + // Less than a day |
| 111 | + } else { |
| 112 | + $class = 'worst'; |
| 113 | + $time = '<' . ceil( $lifetime/3600 ) . ' ' . _g('hours'); |
| 114 | + } |
| 115 | + |
| 116 | + $Tool->addOut( |
| 117 | + '<form class="cleanform"><fieldset>' |
| 118 | + . kfTag( _( 'current-settings' ) . _g( 'colon-separator' ) . ' ', 'legend' ) |
| 119 | + . kfTag( _( 'current-language' ) . _g( 'colon-separator' ) . ' ', 'label' ) |
| 120 | + . kfTag( '', 'input', array( 'value' => $I18N->getLang(), 'readonly' => 'readonly' ) ) |
| 121 | + . ' (' |
| 122 | + . kfTag( _( 'clear-memory'), 'a', array( 'href' => $Tool->generatePermalink( array( 'action' => 'clearcookies' ) ) ) ) |
| 123 | + . ')<br />' |
| 124 | + . kfTag( _( 'cookie-expiration' ) . _g( 'colon-separator' ), 'label' ) . kfTag( '', 'input', array( 'value' => $time, 'class' => "cookie-health $class", 'readonly' => 'readonly' ) ) |
| 125 | + . '</form>' |
| 126 | + ); |
| 127 | + |
| 128 | + |
| 129 | +} |
| 130 | + |
| 131 | +// @TODO: This should be done with TsIntuition::getAvailableLanguages after loadig all domains |
| 132 | +$langs = array( 'en', 'nl', 'de' ); |
| 133 | + |
| 134 | +// XXX: Quick way to build the form |
| 135 | +$dropdown = '<select name="fpLang">'; |
| 136 | +$selected = ' selected="selected"'; |
| 137 | +foreach ( $langs as $lang ) { |
| 138 | + $attr = $lang == $I18N->getLang() ? $selected : ''; |
| 139 | + $dropdown .= '<option value="' . $lang . '"' . $attr . '>' . $I18N->getlangName( $lang ) . '</option>'; |
| 140 | +} |
| 141 | +$dropdown .= '</select>'; |
| 142 | + |
| 143 | +$form = '<form action="' . $Tool->remoteBasePath . '" method="post" class="cleanform"><fieldset> |
| 144 | + <legend>' . _( 'settings-legend' ) . '</legend> |
| 145 | + |
| 146 | + <label>' . _( 'choose-language' ) . _g( 'colon-separator' ) . '</label> |
| 147 | + ' . $dropdown . ' |
| 148 | + <br /> |
| 149 | + |
| 150 | + <input type="hidden" name="action" value="prefset" /> |
| 151 | + <label></label> |
| 152 | + <input type="submit" nof value="' . _g( 'form-submit' ) . '" /> |
| 153 | + <br /> |
| 154 | + |
| 155 | +</fieldset></form>'; |
| 156 | + |
| 157 | +$Tool->addOut( $form ); |
| 158 | + |
| 159 | +/** |
| 160 | + * Close up |
| 161 | + * ------------------------------------------------- |
| 162 | + */ |
| 163 | +$Tool->flushMainOutput(); |
Property changes on: trunk/tools/ToolserverI18N/public_html/index.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 164 | + native |
Index: trunk/tools/ToolserverI18N/language/Rtl.php |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Languag fallbacks for TsIntuition |
| 4 | + * Right-to-left languages. |
5 | 5 | */ |
6 | 6 | |
7 | | -$rtlLanguages = array('ar','arc','dv','fa','he','kk','ks','mzn','ps','sd','ug','ur','ydd','yi'); |
\ No newline at end of file |
| 7 | +$rtlLanguages = array( 'ar', 'arc', 'dv', 'fa', 'he', 'kk', 'ks', 'mzn', 'ps', 'sd', 'ug', 'ur', 'ydd', 'yi' ); |
\ No newline at end of file |
Index: trunk/tools/ToolserverI18N/language/messages/General.i18n.php |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * General purpose messages |
| 4 | + * General purpose messages. |
5 | 5 | */ |
6 | 6 | |
7 | 7 | /** |
— | — | @@ -16,6 +16,22 @@ |
17 | 17 | 'etc' => 'etc.', |
18 | 18 | 'colon-separator' => ':', |
19 | 19 | 'form-submit' => 'Go', |
| 20 | + 'form-reset' => 'Reset', |
| 21 | + 'year' => 'year', |
| 22 | + 'years' => 'years', |
| 23 | + 'month' => 'month', |
| 24 | + 'months' => 'months', |
| 25 | + 'week' => 'week', |
| 26 | + 'weeks' => 'weeks', |
| 27 | + 'day' => 'day', |
| 28 | + 'days' => 'days', |
| 29 | + 'hour' => 'hour', |
| 30 | + 'hours' => 'hours', |
| 31 | + 'minute' => 'minute', |
| 32 | + 'minutes' => 'minutes', |
| 33 | + 'second' => 'second', |
| 34 | + 'seconds' => 'seconds', |
| 35 | + |
20 | 36 | ); |
21 | 37 | |
22 | 38 | /** |
— | — | @@ -29,14 +45,16 @@ |
30 | 46 | 'welcome' => 'A friendly welcome.', |
31 | 47 | 'toolversionstamp' => 'Short sentence about what the last version of this tool is and when this version was uploaded. <code>$1</code> is the version (eg. "1.5.5beta") and <code>$2</code> is the date.', |
32 | 48 | 'etc' => 'Abbreviated form of "et cetera"', |
33 | | - 'colon-seperator' => 'Optional message. Change it only if your language uses another character for ":" or it needs an extra space before the colon.', |
| 49 | + 'colon-separator' => 'Optional message. Change it only if your language uses another character for ":" or it needs an extra space before the colon.', |
34 | 50 | 'form-submit' => 'A general label for a form submission button. Not per se a search form!', |
| 51 | + 'form-reset' => 'A general label for a form reset button. Not per se a search form!', |
35 | 52 | ); |
36 | 53 | |
37 | 54 | /** |
38 | 55 | * Nederlands |
39 | 56 | * |
40 | 57 | * @author Krinkle |
| 58 | + * @author GerardM |
41 | 59 | */ |
42 | 60 | $messages['nl'] = array( |
43 | 61 | 'dateformat' => '%d %B %Y', |
— | — | @@ -45,6 +63,21 @@ |
46 | 64 | 'toolversionstamp' => 'Versie $1 geupload op $2', |
47 | 65 | 'etc' => 'enz.', |
48 | 66 | 'form-submit' => 'OK', |
| 67 | + 'form-reset' => 'Stel opnieuw in', |
| 68 | + 'year' => 'jaar', |
| 69 | + 'years' => 'jaren', |
| 70 | + 'month' => 'maand', |
| 71 | + 'months' => 'maanden', |
| 72 | + 'week' => 'week', |
| 73 | + 'weeks' => 'weken', |
| 74 | + 'day' => 'dag', |
| 75 | + 'days' => 'dagen', |
| 76 | + 'hour' => 'uur', |
| 77 | + 'hours' => 'uren', |
| 78 | + 'minute' => 'minuut', |
| 79 | + 'minutes' => 'minuten', |
| 80 | + 'second' => 'seconde', |
| 81 | + 'seconds' => 'seconden', |
49 | 82 | ); |
50 | 83 | |
51 | 84 | /** |
Index: trunk/tools/ToolserverI18N/language/messages/Getwikiapi.i18n.php |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Interface messages for getWikiAPI |
| 4 | + * Interface messages for tool "getWikiAPI". |
5 | 5 | * |
6 | 6 | * @toolowner krinkle |
7 | 7 | */ |
Index: trunk/tools/ToolserverI18N/language/messages/Svgtranslate.i18n.php |
— | — | @@ -12,15 +12,22 @@ |
13 | 13 | */ |
14 | 14 | $messages['en'] = array( |
15 | 15 | 'title' => 'SVG Translate', // Do not translate |
16 | | - 'error' => '$1 Hit your browser\'s back button to retry', |
| 16 | + 'error-tryagain' => '$1 Hit your browser\'s back button to retry.', |
| 17 | + 'error-nothing' => 'Nothing to translate.', |
| 18 | + 'error-notsvg' => 'Not an SVG file.', |
| 19 | + 'error-unexpected' => 'An unexpected error occured.', |
| 20 | + 'error-notfound' => 'The SVG file could not be retrieved from the URL provided.', |
17 | 21 | 'begin-translation' => 'Begin translation', |
18 | 22 | 'th-original' => 'Original', |
19 | 23 | 'th-translation' => 'Translation', |
| 24 | + 'th-language' => 'Language', |
20 | 25 | 'preview' => 'Preview', |
21 | 26 | 'translate' => 'Translate', |
22 | 27 | 'translate-instructions' => 'Inputs are accepted as either Filenames (eg. "$1") or full-url (eg. "$2"). If the first option is used, Wikimedia Commons will be assumed as source. To translate an SVG from another site or wiki, you must use the full-url format.', |
23 | | - 'format-filename-example' => 'File:Planetary_transit.svg', // Do not translate |
| 28 | + 'format-filename-example' => 'File:Planetary transit.svg', // Do not translate |
24 | 29 | 'format-fullurl-example' => 'http://upload.wikimedia.org/wikipedia/commons/8/8a/Planetary_transit.svg', // Do not translate |
| 30 | + 'svginput-label' => 'SVG File', |
| 31 | + 'stats-footer' => 'This tool has been used to translate approximately $1 files since $2', |
25 | 32 | ); |
26 | 33 | |
27 | 34 | /** |
— | — | @@ -33,12 +40,14 @@ |
34 | 41 | 'title' => "{{Notranslate}}\n\nThe title of the tool.", |
35 | 42 | 'begin-translation' => 'This is the opening heading on the home page of the tool.', |
36 | 43 | 'th-original' => 'Heading of the "Original"-column.', |
37 | | - 'th-original' => 'Heading of the "Translation"-column.', |
| 44 | + 'th-translation' => 'Heading of the "Translation"-column.', |
| 45 | + 'th-language' => 'Label for the language selection dropdown box. {{Identical|Language}}', |
38 | 46 | 'preview' => '{{Identical|Preview}}', |
39 | 47 | 'translate' => '{{Identical|Translate}}', |
40 | 48 | 'translate-instructions' => 'Intro paragraph in the translation process.', |
41 | 49 | 'format-filename-example' => '{{Notranslate}}', |
42 | 50 | 'format-fullurl-example' => '{{Notranslate}}', |
| 51 | + 'svginput-label' => 'The label for main SVG filename input', |
43 | 52 | ); |
44 | 53 | |
45 | 54 | /** |
— | — | @@ -51,6 +60,9 @@ |
52 | 61 | 'begin-translation' => 'Start de vertaling', |
53 | 62 | 'th-original' => 'Origineel', |
54 | 63 | 'th-translation' => 'Vertaling', |
| 64 | + 'th-language' => 'Taal', |
55 | 65 | 'preview' => 'Voorvertoning', |
56 | 66 | 'translate' => 'Vertaal', |
| 67 | + 'translate-instructions' => 'Bestandsnamen (bijv. "$1") of volledige URL (bijv. "$2") invoeren. In het eerste geval wordt Wikimedia Commons als bron aangenomen. Om een SVG van een andere site te vertalen, gebruik dan het tweede formaaat.', |
| 68 | + 'svginput-label' => 'SVG Bestand', |
57 | 69 | ); |
Index: trunk/tools/ToolserverI18N/language/messages/Jarry.i18n.php |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Interface messages for Jarry's general interface for all tools |
| 4 | + * Interface messages for Jarry's general tool interface. |
5 | 5 | * |
6 | 6 | * @toolowner jarry |
7 | 7 | */ |
Index: trunk/tools/ToolserverI18N/language/messages/Tsintuition.i18n.php |
— | — | @@ -1,6 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Interface messages for TsIntuition |
| 4 | + * Interface messages for TsIntuition. |
5 | 5 | * |
6 | 6 | * @toolowner krinkle |
7 | 7 | */ |
— | — | @@ -13,15 +13,16 @@ |
14 | 14 | $messages['en'] = array( |
15 | 15 | 'title' => 'TsIntuition', // Do not translate |
16 | 16 | 'fullname' => 'Internationalization for Toolserver\'s User Interface', |
| 17 | + 'current-settings' => 'Current settings', |
17 | 18 | 'current-language' => 'Currently selected language', |
18 | 19 | 'settings-legend' => 'Settings', |
19 | 20 | 'choose-language' => 'Choose a language', |
| 21 | + 'clear-memory' => 'Clear cookies', |
| 22 | + 'cookie-expiration' => 'Cookie expiration', |
20 | 23 | ); |
21 | 24 | |
22 | 25 | /** |
23 | 26 | * Documentation |
24 | | - * |
25 | | - * @author Krinkle |
26 | 27 | */ |
27 | 28 | $messages['qqq'] = array( |
28 | 29 | ); |
— | — | @@ -33,13 +34,16 @@ |
34 | 35 | */ |
35 | 36 | $messages['nl'] = array( |
36 | 37 | 'fullname' => 'Vertaling voor Toolserver\'s gebruikersinterface', |
| 38 | + 'current-settings' => 'Huidige instellingen', |
37 | 39 | 'current-language' => 'Huidige taal', |
38 | 40 | 'settings-legend' => 'Instellingen', |
39 | 41 | 'choose-language' => 'Kies een taal', |
| 42 | + 'clear-memory' => 'Cookies wissen', |
| 43 | + 'cookie-expiration' => 'Cookie verlooptijd', |
40 | 44 | ); |
41 | 45 | |
42 | 46 | /** |
43 | | - * Nederlands |
| 47 | + * Deutsch |
44 | 48 | * |
45 | 49 | * @author Krinkle |
46 | 50 | */ |
Index: trunk/tools/ToolserverI18N/language/Fallbacks.php |
— | — | @@ -0,0 +1,23 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Language fallbacks. |
| 5 | + */ |
| 6 | + |
| 7 | +// Listed a few examples for now. |
| 8 | +// Perhaps this can be automated in the future via TranslateWiki based on MediaWiki's core fallbacks. |
| 9 | +$fallbacks = array( |
| 10 | + 'ab' => 'ru', |
| 11 | + 'ace' => 'id', |
| 12 | + 'aln' => 'sq', |
| 13 | + 'als' => 'gsw', |
| 14 | + 'an' => 'es', |
| 15 | + 'arn' => 'es', |
| 16 | + 'arz' => 'ar', |
| 17 | + 'as' => 'bn', |
| 18 | + 'av' => 'ru', |
| 19 | + 'ay' => 'es', |
| 20 | + |
| 21 | + 'fy' => 'nl', |
| 22 | + |
| 23 | + 'nds' => 'de', |
| 24 | +); |
Property changes on: trunk/tools/ToolserverI18N/language/Fallbacks.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 25 | + native |
Index: trunk/tools/ToolserverI18N/language/Names.php |
— | — | @@ -1,5 +1,5 @@ |
2 | 2 | <?php |
3 | | -// Source: http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/languages/Names.php?revision=84464 |
| 3 | +// From: http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/languages/Names.php?revision=84464 |
4 | 4 | /** |
5 | 5 | * These determine things like interwikis, language selectors, and so on. |
6 | 6 | * Safe to change without running scripts on the respective sites. |
Index: trunk/tools/ToolserverI18N/TsIntuitionUtil.php |
— | — | @@ -0,0 +1,93 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * |
| 5 | + * Created on March 25, 2011 |
| 6 | + * |
| 7 | + * Copyright 2011 Krinkle <krinklemail@gmail.com> |
| 8 | + * |
| 9 | + * This file is licensed under |
| 10 | + * the Creative Commons Attribution 3.0 Unported License |
| 11 | + * <http://creativecommons.org/licenses/by/3.0/> |
| 12 | + * |
| 13 | + * @package TsIntuition |
| 14 | + */ |
| 15 | + |
| 16 | +// Protect against invalid entry |
| 17 | +if( !defined( 'TS_INTUITION' ) ) { |
| 18 | + echo "This file is part of TsIntuition and is not a valid entry point\n"; |
| 19 | + exit; |
| 20 | +} |
| 21 | + |
| 22 | +/** |
| 23 | + * This class contains the static utility functions for the Itui class. |
| 24 | + */ |
| 25 | +class TsIntuitionUtil { |
| 26 | + |
| 27 | + /** |
| 28 | + * Escapes a string with one of the known method and returns it |
| 29 | + * |
| 30 | + * @param $str string The string to be escaped |
| 31 | + * @param $escape string The name of the escape routine to be used |
| 32 | + * if this is an unknown method name it will be ignored and 'plain' |
| 33 | + * will be used instead. |
| 34 | + * @return string The escaped string. |
| 35 | + */ |
| 36 | + public static function strEscape( $str, $escape = 'plain' ) { |
| 37 | + switch ( $escape ) { |
| 38 | + case 'html' : |
| 39 | + case 'htmlspecialchars' : |
| 40 | + $str = htmlspecialchars( $str ); |
| 41 | + break; |
| 42 | + case 'htmlentities': |
| 43 | + $str = htmlentities( $str, ENT_QUOTES, 'UTF-8' ); |
| 44 | + break; |
| 45 | + // 'plain' or anything else: Do nothing |
| 46 | + } |
| 47 | + return $str; |
| 48 | + } |
| 49 | + |
| 50 | + public static function nonEmptyStr( $var ) { |
| 51 | + if ( is_string( $var ) && $var !== '' ) { |
| 52 | + return true; |
| 53 | + } |
| 54 | + return false; |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Pass one or more arguments which will be checked untill one fails |
| 59 | + * If atleast one argument is not a non-empty string, or if no arguments / NULL passed |
| 60 | + * it will return false, otherwise true; |
| 61 | + */ |
| 62 | + public static function nonEmptyStrs( /* $var .. */ ) { |
| 63 | + $args = func_get_args(); |
| 64 | + if ( !isset( $args[0] ) ) { |
| 65 | + return false; |
| 66 | + } |
| 67 | + foreach ( $args as $arg) { |
| 68 | + if ( !TsIntuitionUtil::nonEmptyStr( $arg ) ) { |
| 69 | + return false; |
| 70 | + } |
| 71 | + } |
| 72 | + // If we're still here, all are good |
| 73 | + return true; |
| 74 | + } |
| 75 | + |
| 76 | + /** |
| 77 | + * A return version of var_dump(). |
| 78 | + * Optionally html-escaped and wrapped in a <pre>-tag. |
| 79 | + * |
| 80 | + * @return string |
| 81 | + */ |
| 82 | + public function return_dump( $var, $html = true) { |
| 83 | + $dump = NULL; |
| 84 | + ob_start(); |
| 85 | + var_dump( $var ); |
| 86 | + $dump = ob_get_contents(); |
| 87 | + ob_end_clean(); |
| 88 | + if ( $html ) { |
| 89 | + return '<pre>' . htmlspecialchars( $dump ) . '</pre>'; |
| 90 | + } |
| 91 | + return $dump; |
| 92 | + } |
| 93 | + |
| 94 | +} |
Property changes on: trunk/tools/ToolserverI18N/TsIntuitionUtil.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 95 | + native |
Index: trunk/tools/ToolserverI18N/Functions.php |
— | — | @@ -0,0 +1,56 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * |
| 5 | + * Created on March 23, 2011 |
| 6 | + * |
| 7 | + * Copyright 2011 Krinkle <krinklemail@gmail.com> |
| 8 | + * |
| 9 | + * This file is licensed under |
| 10 | + * the Creative Commons Attribution 3.0 Unported License |
| 11 | + * <http://creativecommons.org/licenses/by/3.0/> |
| 12 | + * |
| 13 | + * @package TsIntuition |
| 14 | + */ |
| 15 | + |
| 16 | +// Protect against invalid entry |
| 17 | +if( !defined( 'TS_INTUITION' ) ) { |
| 18 | + echo "This file is part of TsIntuition and is not a valid entry point\n"; |
| 19 | + exit; |
| 20 | +} |
| 21 | + |
| 22 | +/** |
| 23 | + * This file contains global functions that will be made available |
| 24 | + * through ToolStart.php. These assume the an instance of the TsIntuition Class |
| 25 | + * is available in the global $I18N variable. These four function are shortcodes |
| 26 | + * for the most common usecases. You can disable them by setting the 'globalfunctions' |
| 27 | + * option to false when constructing the TsIntuition Class. |
| 28 | + */ |
| 29 | + |
| 30 | +// Return a message |
| 31 | +function _( $key, $options = array() ) { |
| 32 | + global $I18N; |
| 33 | + return $I18N->msg( $key, $options ); |
| 34 | +} |
| 35 | + |
| 36 | +// Return a message from the 'general' domain |
| 37 | +function _g( $key, $options = array() ) { |
| 38 | + if ( is_string( $options ) ) { |
| 39 | + $options = array( 'domain' => $options ); |
| 40 | + } |
| 41 | + $options = array_merge( $options, array( 'domain' => 'general' ) ); |
| 42 | + return _( $key, $options ); |
| 43 | +} |
| 44 | + |
| 45 | +// Return a message escaped as html |
| 46 | +function _html( $key, $options = array() ) { |
| 47 | + if ( is_string( $options ) ) { |
| 48 | + $options = array( 'domain' => $options ); |
| 49 | + } |
| 50 | + $options = array_merge( $options, array( 'parse' => 'html' ) ); |
| 51 | + return _( $key, $options ); |
| 52 | +} |
| 53 | + |
| 54 | +// Echo a message |
| 55 | +function _e( $key, $options = array() ) { |
| 56 | + echo _( $key, $options ); |
| 57 | +} |
\ No newline at end of file |
Property changes on: trunk/tools/ToolserverI18N/Functions.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 58 | + native |