Index: trunk/extensions/Translate/FFS.php |
— | — | @@ -363,83 +363,163 @@ |
364 | 364 | } |
365 | 365 | } |
366 | 366 | |
367 | | -class JavaScriptFFS extends SimpleFFS { |
368 | | - private function leftTrim( $string ) { |
369 | | - $string = ltrim( $string ); |
370 | | - $string = ltrim( $string, '"' ); |
| 367 | +abstract class JavaScriptFFS extends SimpleFFS { |
371 | 368 | |
372 | | - return $string; |
373 | | - } |
| 369 | + /** |
| 370 | + * Message keys format. |
| 371 | + */ |
| 372 | + abstract protected function transformKey( $key ); |
374 | 373 | |
| 374 | + /** |
| 375 | + * Header of message file. |
| 376 | + */ |
| 377 | + abstract protected function header( $code, $authors ); |
| 378 | + |
| 379 | + /** |
| 380 | + * Footer of message file. |
| 381 | + */ |
| 382 | + abstract protected function footer(); |
| 383 | + |
375 | 384 | public function readFromVariable( $data ) { |
376 | | - // Add trailing comma to last key pair. |
377 | | - $data = str_replace( "\"\n};", "\",\n};", $data ); |
378 | 385 | |
379 | | - // Just get relevant data. |
| 386 | + /* Pre-processing */ |
| 387 | + |
| 388 | + // Find the start and end of the data section (enclosed in curly braces). |
380 | 389 | $dataStart = strpos( $data, '{' ); |
381 | 390 | $dataEnd = strrpos( $data, '}' ); |
| 391 | + // Strip everything outside of the data section. |
382 | 392 | $data = substr( $data, $dataStart + 1, $dataEnd - $dataStart - 1 ); |
| 393 | + |
383 | 394 | // Strip comments. |
384 | 395 | $data = preg_replace( '#^(\s*?)//(.*?)$#m', '', $data ); |
385 | | - // Break in to message segements for further parsing. |
386 | | - $data = explode( '",', $data ); |
387 | 396 | |
| 397 | + // Replace message endings with double quotes. |
| 398 | + $data = preg_replace( "#\'\,\n#", "\",\n", $data ); |
| 399 | + |
| 400 | + // Strip excess whitespace. |
| 401 | + $data = trim( $data ); |
| 402 | + |
| 403 | + /* Per-key message */ |
| 404 | + |
| 405 | + // Break in to segments. |
| 406 | + $data = explode( "\",\n", $data ); |
| 407 | + |
388 | 408 | $messages = array(); |
389 | | - // Process each segment. |
390 | | - foreach ( $data as $segment ) { |
391 | | - // Remove excess quote mark at beginning. |
392 | | - $segment = substr( $segment, 1 ); |
393 | | - // Add back trailing quote. |
| 409 | + foreach( $data as $segment ) { |
| 410 | + // Add back trailing quote, removed by explosion. |
394 | 411 | $segment .= '"'; |
395 | | - // Concatenate seperate strings. |
| 412 | + |
| 413 | + // Concatenate separate strings. |
396 | 414 | $segment = explode( '" +', $segment ); |
397 | | - $segment = array_map( array( $this, 'leftTrim' ), $segment ); |
| 415 | + for( $i = 0; $i < count( $segment ); $i++ ) { |
| 416 | + $segment[$i] = ltrim( $segment[$i] ); |
| 417 | + $segment[$i] = ltrim( $segment[$i], '"' ); |
| 418 | + } |
398 | 419 | $segment = implode( $segment ); |
399 | | - # $segment = preg_replace( '#\" \+(.*?)\"#m', '', $segment ); |
| 420 | + |
| 421 | + // Remove line breaks between message keys and messages. |
| 422 | + $segment = preg_replace( "#\:(\s+)[\\\"\']#", ': "', $segment ); |
| 423 | + |
400 | 424 | // Break in to key and message. |
401 | | - $segments = explode( '\':', $segment ); |
| 425 | + $segments = explode( ': "', $segment ); |
402 | 426 | $key = $segments[ 0 ]; |
403 | | - unset( $segments[ 0 ] ); |
404 | | - $value = implode( $segments ); |
405 | | - // Strip excess whitespace from both. |
| 427 | + $value = $segments[1]; |
| 428 | + |
| 429 | + // Strip excess whitespace from key and value. |
406 | 430 | $key = trim( $key ); |
407 | 431 | $value = trim( $value ); |
408 | | - // Remove quotation marks and syntax. |
409 | | - $key = substr( $key, 1 ); |
410 | | - $value = substr( $value, 1, - 1 ); |
| 432 | + |
| 433 | + // Strip quotation marks. |
| 434 | + $key = trim( $key, '\'"' ); |
| 435 | + $value = trim( $value, '\'"' ); |
| 436 | + |
| 437 | + // Unescape any JavaScript and append to message array. |
411 | 438 | $messages[ $key ] = self::unescapeJsString( $value ); |
412 | 439 | } |
413 | 440 | |
414 | | - // Remove extraneous key that is sometimes present. |
415 | | - unset( $messages[ 0 ] ); |
416 | | - |
417 | 441 | return array( 'MESSAGES' => $messages ); |
418 | 442 | } |
419 | 443 | |
420 | | - // Quick shortcut for getting the plain exported data |
421 | 444 | public function writeIntoVariable( MessageCollection $collection ) { |
422 | | - $code = $collection->code; |
| 445 | + $r = $this->header( $collection->code, $collection->getAuthors() ); |
| 446 | + |
| 447 | + // Get and write messages. |
| 448 | + foreach ( $collection as $message ) { |
| 449 | + $key = $this->transformKey( Xml::escapeJsString( $message->key() ) ); |
| 450 | + $value = Xml::escapeJsString( $message->translation() ); |
| 451 | + |
| 452 | + $r .= " {$key}: \"{$value}\",\n\n"; |
| 453 | + } |
| 454 | + |
| 455 | + // Strip last comma, re-add trailing newlines. |
| 456 | + $r = substr( $r, 0, - 3 ); |
| 457 | + $r .= "\n\n"; |
| 458 | + |
| 459 | + return $r . $this->footer(); |
| 460 | + } |
| 461 | + |
| 462 | + protected function authorsList( $authors ) { |
| 463 | + if( count( $authors ) > 0 ) { |
| 464 | + foreach ( $authors as $author ) { |
| 465 | + $authorsList .= " * - $author\n"; |
| 466 | + } |
| 467 | + return <<<EOT |
| 468 | +/* Translators: |
| 469 | +$authorsList */ |
| 470 | + |
| 471 | + |
| 472 | +EOT; |
| 473 | + } else { |
| 474 | + return ''; |
| 475 | + } |
| 476 | + } |
| 477 | + |
| 478 | + private static function unescapeJsString( $string ) { |
| 479 | + // See ECMA 262 section 7.8.4 for string literal format |
| 480 | + $pairs = array( |
| 481 | + "\\" => "\\\\", |
| 482 | + "\"" => "\\\"", |
| 483 | + '\'' => '\\\'', |
| 484 | + "\n" => "\\n", |
| 485 | + "\r" => "\\r", |
| 486 | + |
| 487 | + # To avoid closing the element or CDATA section |
| 488 | + "<" => "\\x3c", |
| 489 | + ">" => "\\x3e", |
| 490 | + |
| 491 | + # To avoid any complaints about bad entity refs |
| 492 | + "&" => "\\x26", |
| 493 | + |
| 494 | + # Work around https://bugzilla.mozilla.org/show_bug.cgi?id=274152 |
| 495 | + # Encode certain Unicode formatting chars so affected |
| 496 | + # versions of Gecko don't misinterpret our strings; |
| 497 | + # this is a common problem with Farsi text. |
| 498 | + "\xe2\x80\x8c" => "\\u200c", // ZERO WIDTH NON-JOINER |
| 499 | + "\xe2\x80\x8d" => "\\u200d", // ZERO WIDTH JOINER |
| 500 | + ); |
| 501 | + $pairs = array_flip( $pairs ); |
| 502 | + |
| 503 | + return strtr( $string, $pairs ); |
| 504 | + } |
| 505 | +} |
| 506 | + |
| 507 | +class OpenLayersFFS extends JavaScriptFFS { |
| 508 | + protected function transformKey( $key ) { |
| 509 | + return "'$key'"; |
| 510 | + } |
| 511 | + |
| 512 | + protected function header( $code, $authors ) { |
423 | 513 | $names = Language::getLanguageNames(); |
424 | 514 | $name = $names[ $code ]; |
425 | 515 | |
426 | | - // Generate list of authors for comment. |
427 | | - $authors = $collection->getAuthors(); |
428 | | - $authorList = ''; |
| 516 | + $authorsList = $this->authorsList( $authors ); |
429 | 517 | |
430 | | - foreach ( $authors as $author ) { |
431 | | - $authorList .= " * - $author\n"; |
432 | | - } |
433 | | - |
434 | | - // Generate header and write. |
435 | | - $r = <<<EOT |
| 518 | + return <<<EOT |
436 | 519 | /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD |
437 | 520 | * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
438 | 521 | * full text of the license. */ |
439 | 522 | |
440 | | -/* Translators (2009 onwards): |
441 | | -$authorList */ |
442 | | - |
443 | | -/** |
| 523 | +$authorsList/** |
444 | 524 | * @requires OpenLayers/Lang.js |
445 | 525 | */ |
446 | 526 | |
— | — | @@ -451,25 +531,33 @@ |
452 | 532 | */ |
453 | 533 | OpenLayers.Lang["$code"] = OpenLayers.Util.applyDefaults({ |
454 | 534 | |
455 | | - |
456 | 535 | EOT; |
| 536 | + } |
457 | 537 | |
458 | | - // Get and write messages. |
459 | | - foreach ( $collection as $message ) { |
460 | | - $key = Xml::escapeJsString( $message->key() ); |
461 | | - $value = Xml::escapeJsString( $message->translation() ); |
| 538 | + protected function footer() { |
| 539 | + return '});'; |
| 540 | + } |
| 541 | +} |
462 | 542 | |
463 | | - $line = " '{$message->key()}': \"{$value}\",\n\n"; |
464 | | - $r .= $line; |
465 | | - } |
| 543 | +class ShapadoJsFFS extends JavaScriptFFS { |
| 544 | + protected function transformKey( $key ) { |
| 545 | + return $key; |
| 546 | + } |
466 | 547 | |
467 | | - // Strip last comma. |
468 | | - $r = substr( $r, 0, - 3 ); |
469 | | - $r .= "\n\n"; |
| 548 | + protected function header( $code, $authors ) { |
470 | 549 | |
471 | | - // File terminator. |
472 | | - return $r . '});'; |
| 550 | + $authorsList = $this->authorsList( $authors ); |
| 551 | + |
| 552 | + return <<<EOT |
| 553 | +{$authorsList}var I18n = { |
| 554 | + |
| 555 | + |
| 556 | +EOT; |
473 | 557 | } |
| 558 | + |
| 559 | + protected function footer() { |
| 560 | + return '};'; |
| 561 | + } |
474 | 562 | } |
475 | 563 | |
476 | 564 | class YamlFFS extends SimpleFFS { |
Index: trunk/extensions/Translate/groups/Shapado/Shapado.yml |
— | — | @@ -466,3 +466,17 @@ |
467 | 467 | |
468 | 468 | MANGLER: |
469 | 469 | prefix: wiki- |
| 470 | + |
| 471 | +--- |
| 472 | +BASIC: |
| 473 | + id: out-shapado-js |
| 474 | + label: Shapado (JavaScript) |
| 475 | + description: "{{int:bw-desc-shapado-js}}" |
| 476 | + namespace: NS_SHAPADO |
| 477 | + display: out/shapado/js |
| 478 | + class: FileBasedMessageGroup |
| 479 | + |
| 480 | +FILES: |
| 481 | + class: ShapadoJsFFS |
| 482 | + sourcePattern: %GROUPROOT%/shapado/public/javascripts/i18n/%CODE%.js |
| 483 | + targetPattern: shapado/public/javascripts/i18n/%CODE%.js |
Index: trunk/extensions/Translate/groups/OpenLayers/OpenLayers.yml |
— | — | @@ -8,8 +8,8 @@ |
9 | 9 | class: FileBasedMessageGroup |
10 | 10 | |
11 | 11 | FILES: |
12 | | - class: JavaScriptFFS |
13 | | - sourcePattern: %GROUPROOT%/Lang/%CODE%.js |
| 12 | + class: OpenLayersFFS |
| 13 | + sourcePattern: %GROUPROOT%/openlayers/%CODE%.js |
14 | 14 | targetPattern: openlayers/%CODE%.js |
15 | 15 | codeMap: |
16 | 16 | cs: cs-CZ |
Index: trunk/extensions/Translate/_autoload.php |
— | — | @@ -128,6 +128,8 @@ |
129 | 129 | $wgAutoloadClasses['YamlFFS'] = $dir . 'FFS.php'; |
130 | 130 | $wgAutoloadClasses['RubyYamlFFS'] = $dir . 'FFS.php'; |
131 | 131 | $wgAutoloadClasses['JavaScriptFFS'] = $dir . 'FFS.php'; |
| 132 | +$wgAutoloadClasses['OpenLayersFFS'] = $dir . 'FFS.php'; |
| 133 | +$wgAutoloadClasses['ShapadoJsFFS'] = $dir . 'FFS.php'; |
132 | 134 | $wgAutoloadClasses['GettextFFS'] = $dir . '/ffs/Gettext.php'; |
133 | 135 | |
134 | 136 | $wgAutoloadClasses['HtmlTag'] = $dir . 'utils/Html.php'; |