%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/Translate/ffs/ |
| Current File : /www/varak.net/wiki.varak.net/extensions/Translate/ffs/JavaScriptFFS.php |
<?php
/**
* Generic file format support for JavaScript formatted files.
* @ingroup FFS
*/
abstract class JavaScriptFFS extends SimpleFFS {
public function getFileExtensions() {
return [ '.js' ];
}
/**
* Message keys format.
*
* @param string $key
*
* @return string
*/
abstract protected function transformKey( $key );
/**
* Header of message file.
*
* @param string $code
* @param string[] $authors
*/
abstract protected function header( $code, array $authors );
/**
* Footer of message file.
*/
abstract protected function footer();
/**
* @param string $data
* @return array Parsed data.
*/
public function readFromVariable( $data ) {
/* Parse authors list */
$authors = preg_replace( "#/\* Translators\:\n(.*?)\n \*/(.*)#s", '$1', $data );
if ( $authors === $data ) {
$authors = [];
} else {
$authors = explode( "\n", $authors );
$count = count( $authors );
for ( $i = 0; $i < $count; $i++ ) {
// Each line should look like " * - Translatorname"
$authors[$i] = substr( $authors[$i], 6 );
}
}
/* Pre-processing of messages */
/**
* Find the start and end of the data section (enclosed in curly braces).
*/
$dataStart = strpos( $data, '{' );
$dataEnd = strrpos( $data, '}' );
/**
* Strip everything outside of the data section.
*/
$data = substr( $data, $dataStart + 1, $dataEnd - $dataStart - 1 );
/**
* Strip comments.
*/
$data = preg_replace( '#^(\s*?)//(.*?)$#m', '', $data );
/**
* Replace message endings with double quotes.
*/
$data = preg_replace( "#\'\,\n#", "\",\n", $data );
/**
* Strip excess whitespace.
*/
$data = trim( $data );
/**
* Per-key message processing.
*/
/**
* Break in to segments.
*/
$data = explode( "\",\n", $data );
$messages = [];
foreach ( $data as $segment ) {
/**
* Add back trailing quote, removed by explosion.
*/
$segment .= '"';
/**
* Concatenate separated strings.
*/
$segment = str_replace( '"+', '" +', $segment );
$segment = explode( '" +', $segment );
$count = count( $segment );
for ( $i = 0; $i < $count; $i++ ) {
$segment[$i] = ltrim( ltrim( $segment[$i] ), '"' );
}
$segment = implode( $segment );
/**
* Remove line breaks between message keys and messages.
*/
$segment = preg_replace( "#\:(\s+)[\\\"\']#", ': "', $segment );
/**
* Break in to key and message.
*/
$segments = explode( ': "', $segment );
/**
* Strip excess whitespace from key and value, then quotation marks.
*/
$key = trim( trim( $segments[0] ), "'\"" );
$value = trim( trim( $segments[1] ), "'\"" );
/**
* Unescape any JavaScript string syntax and append to message array.
*/
$messages[$key] = self::unescapeJsString( $value );
}
$messages = $this->group->getMangler()->mangle( $messages );
return [
'AUTHORS' => $authors,
'MESSAGES' => $messages
];
}
/**
* @param MessageCollection $collection
* @return string
*/
public function writeReal( MessageCollection $collection ) {
$header = $this->header( $collection->code, $collection->getAuthors() );
$mangler = $this->group->getMangler();
/**
* Get and write messages.
*/
$body = '';
/**
* @var TMessage $message
*/
foreach ( $collection as $message ) {
if ( strlen( $message->translation() ) === 0 ) {
continue;
}
$key = $mangler->unmangle( $message->key() );
$key = $this->transformKey( self::escapeJsString( $key ) );
$translation = self::escapeJsString( $message->translation() );
$body .= "\t{$key}: \"{$translation}\",\n";
}
if ( strlen( $body ) === 0 ) {
return false;
}
/**
* Strip last comma, re-add trailing newlines.
*/
$body = substr( $body, 0, -2 );
$body .= "\n";
return $header . $body . $this->footer();
}
/**
* @param string[] $authors
* @return string
*/
protected function authorsList( array $authors ) {
if ( $authors === [] ) {
return '';
}
$authorsList = '';
foreach ( $authors as $author ) {
$authorsList .= " * - $author\n";
}
// Remove trailing newline, and return.
return substr( " * Translators:\n$authorsList", 0, -1 );
}
// See ECMA 262 section 7.8.4 for string literal format
private static $pairs = [
"\\" => "\\\\",
"\"" => "\\\"",
"'" => "\\'",
"\n" => "\\n",
"\r" => "\\r",
// To avoid closing the element or CDATA section.
'<' => "\\x3c",
'>' => "\\x3e",
// To avoid any complaints about bad entity refs.
'&' => "\\x26",
/*
* Work around https://bugzilla.mozilla.org/show_bug.cgi?id=274152
* Encode certain Unicode formatting chars so affected
* versions of Gecko do not misinterpret our strings;
* this is a common problem with Farsi text.
*/
"\xe2\x80\x8c" => "\\u200c", // ZERO WIDTH NON-JOINER
"\xe2\x80\x8d" => "\\u200d", // ZERO WIDTH JOINER
];
/**
* @param string $string
* @return string
*/
protected static function escapeJsString( $string ) {
return strtr( $string, self::$pairs );
}
/**
* @param string $string
* @return string
*/
protected static function unescapeJsString( $string ) {
return strtr( $string, array_flip( self::$pairs ) );
}
}
/**
* File format support for Shapado, which uses JavaScript based format.
* @ingroup FFS
*/
class ShapadoJsFFS extends JavaScriptFFS {
/**
* @param string $key
*
* @return string
*/
protected function transformKey( $key ) {
return $key;
}
/**
* @param string $code
* @param string[] $authors
* @return string
*/
protected function header( $code, array $authors ) {
global $wgSitename;
$name = TranslateUtils::getLanguageName( $code );
$native = TranslateUtils::getLanguageName( $code, $code );
$authorsList = $this->authorsList( $authors );
/** @cond doxygen_bug */
return <<<EOT
/** Messages for $name ($native)
* Exported from $wgSitename
*
{$authorsList}
*/
var I18n = {
EOT;
/** @endcond */
}
/**
* @return string
*/
protected function footer() {
return "};\n\n";
}
}