18use UtfNormal\Validator;
38 private const RECORD_SEPARATOR =
"\0";
39 private const PART_SEPARATOR =
"\0\0\0\0";
43 $conf = $group->getConfiguration();
44 $this->extra = $conf[
'FILES'];
49 $this->group = $group;
59 $this->writePath = $writePath;
64 return $this->writePath;
77 public function exists( $code =
false ) {
78 if ( $code ===
false ) {
79 $code = $this->group->getSourceLanguage();
82 $filename = $this->group->getSourceFilePath( $code );
83 if ( $filename ===
null ) {
87 return file_exists( $filename );
98 public function read( $code ) {
103 if ( !$this->
exists( $code ) ) {
107 $filename = $this->group->getSourceFilePath( $code );
108 $input = file_get_contents( $filename );
109 if ( $input ===
false ) {
110 throw new MWException(
"Unable to read file $filename." );
113 if ( !StringUtils::isUtf8( $input ) ) {
114 throw new MWException(
"Contents of $filename are not valid utf-8." );
117 $input = Validator::cleanUp( $input );
120 $input = ltrim( $input,
"\u{FEFF}" );
124 }
catch ( Exception $e ) {
125 throw new MWException(
"Parsing $filename failed: " . $e->getMessage() );
138 $parts = explode( self::PART_SEPARATOR, $data );
140 if ( count( $parts ) !== 2 ) {
141 throw new MWException(
'Wrong number of parts.' );
144 list( $authorsPart, $messagesPart ) = $parts;
145 $authors = explode( self::RECORD_SEPARATOR, $authorsPart );
148 foreach ( explode( self::RECORD_SEPARATOR, $messagesPart ) as $line ) {
149 if ( $line ===
'' ) {
153 $lineParts = explode(
'=', $line, 2 );
155 if ( count( $lineParts ) !== 2 ) {
156 throw new MWException(
"Wrong number of parts in line $line." );
159 list( $key, $message ) = $lineParts;
161 $messages[$key] = $message;
164 $messages = $this->group->getMangler()->mangleArray( $messages );
167 'AUTHORS' => $authors,
168 'MESSAGES' => $messages,
179 $writePath = $this->writePath;
181 if ( $writePath ===
null ) {
182 throw new MWException(
'Write path is not set.' );
185 if ( !file_exists( $writePath ) ) {
186 throw new MWException(
"Write path '$writePath' does not exist." );
189 if ( !is_writable( $writePath ) ) {
190 throw new MWException(
"Write path '$writePath' is not writable." );
193 $targetFile = $writePath .
'/' . $this->group->getTargetFilename( $collection->code );
195 $targetFileExists = file_exists( $targetFile );
197 if ( $targetFileExists ) {
200 $sourceFile = $this->group->getSourceFilePath( $collection->code );
204 $output = $this->
writeReal( $collection );
212 if ( $targetFileExists ) {
219 wfMkdirParents( dirname( $targetFile ),
null, __METHOD__ );
220 file_put_contents( $targetFile, $output );
230 $sourceFile = $this->group->getSourceFilePath( $collection->code );
244 $authors = $this->
filterAuthors( $authors, $collection->code );
246 $output .= implode( self::RECORD_SEPARATOR, $authors );
247 $output .= self::PART_SEPARATOR;
249 $mangler = $this->group->getMangler();
252 foreach ( $collection as $key => $m ) {
253 $key = $mangler->unmangle( $key );
254 $trans = $m->translation();
255 $output .=
"$key=$trans" . self::RECORD_SEPARATOR;
279 if ( $sourceText !==
false ) {
282 if ( isset( $sourceData[
'AUTHORS'] ) ) {
303 if ( !file_exists( $filename ) ) {
307 if ( !is_readable( $filename ) ) {
308 throw new MWException(
"File $filename is not readable." );
311 $data = file_get_contents( $filename );
312 if ( $data ===
false ) {
313 throw new MWException(
"Unable to read file $filename." );
327 $groupId = $this->group->getId();
328 $configHelper = Services::getInstance()->getConfigHelper();
330 foreach ( $authors as $i => $v ) {
331 if ( $configHelper->isAuthorExcluded( $groupId, $code, $v ) ) {
332 unset( $authors[$i] );
336 return array_values( $authors );
355 $ffs = $this->group->getFFS();
356 }
catch ( RunTimeException $e ) {
357 if ( $e->getCode() === FileBasedMessageGroup::NO_FFS_CLASS ) {
364 return get_class( $ffs ) === get_class( $this );
This class implements default behavior for file based message groups.
filterAuthors(array $authors, $code)
Remove excluded authors.
exists( $code=false)
Returns true if the file for this message group in a given language exists.
isGroupFfsReadable()
Check if the file format of the current group is readable by the file format system.
tryReadSource( $filename, MessageCollection $collection)
This tries to pick up external authors in the source files so that they are not lost if those authors...
shouldOverwrite( $a, $b)
Allows to skip writing the export output into a file.
isContentEqual( $a, $b)
Checks whether two strings are equal.
supportsFuzzy()
Query the capabilities of this FFS.
writeReal(MessageCollection $collection)
read( $code)
Reads messages from the file in a given language and returns an array of AUTHORS, MESSAGES and possib...
$extra
Stores the FILES section of the YAML configuration, which can be accessed for extra FFS class specifi...
writeIntoVariable(MessageCollection $collection)
Read a collection and return it as a SimpleFFS formatted string.
getFileExtensions()
Return the commonly used file extensions for these formats.
setGroup(FileBasedMessageGroup $group)
write(MessageCollection $collection)
Write the collection to file.
setWritePath( $writePath)
readFromVariable( $data)
Parse the message data given as a string in the SimpleFFS format and return it as an array of AUTHORS...
tryReadFile( $filename)
Read the contents of $filename and return it as a string.
Interface for file system support classes.