17use UtfNormal\Validator;
37 private const RECORD_SEPARATOR =
"\0";
38 private const PART_SEPARATOR =
"\0\0\0\0";
42 $conf = $group->getConfiguration();
43 $this->extra = $conf[
'FILES'];
48 $this->group = $group;
58 $this->writePath = $writePath;
63 return $this->writePath;
76 public function exists( $code =
false ) {
77 if ( $code ===
false ) {
78 $code = $this->group->getSourceLanguage();
81 $filename = $this->group->getSourceFilePath( $code );
82 if ( $filename ===
null ) {
86 return file_exists( $filename );
97 public function read( $code ) {
102 if ( !$this->
exists( $code ) ) {
106 $filename = $this->group->getSourceFilePath( $code );
107 $input = file_get_contents( $filename );
108 if ( $input ===
false ) {
109 throw new MWException(
"Unable to read file $filename." );
112 if ( !StringUtils::isUtf8( $input ) ) {
113 throw new MWException(
"Contents of $filename are not valid utf-8." );
116 $input = Validator::cleanUp( $input );
119 $input = ltrim( $input,
"\u{FEFF}" );
123 }
catch ( Exception $e ) {
124 throw new MWException(
"Parsing $filename failed: " . $e->getMessage() );
137 $parts = explode( self::PART_SEPARATOR, $data );
139 if ( count( $parts ) !== 2 ) {
140 throw new MWException(
'Wrong number of parts.' );
143 list( $authorsPart, $messagesPart ) = $parts;
144 $authors = explode( self::RECORD_SEPARATOR, $authorsPart );
147 foreach ( explode( self::RECORD_SEPARATOR, $messagesPart ) as $line ) {
148 if ( $line ===
'' ) {
152 $lineParts = explode(
'=', $line, 2 );
154 if ( count( $lineParts ) !== 2 ) {
155 throw new MWException(
"Wrong number of parts in line $line." );
158 list( $key, $message ) = $lineParts;
160 $messages[$key] = $message;
163 $messages = $this->group->getMangler()->mangleArray( $messages );
166 'AUTHORS' => $authors,
167 'MESSAGES' => $messages,
178 $writePath = $this->writePath;
180 if ( $writePath ===
null ) {
181 throw new MWException(
'Write path is not set.' );
184 if ( !file_exists( $writePath ) ) {
185 throw new MWException(
"Write path '$writePath' does not exist." );
188 if ( !is_writable( $writePath ) ) {
189 throw new MWException(
"Write path '$writePath' is not writable." );
192 $targetFile = $writePath .
'/' . $this->group->getTargetFilename( $collection->code );
194 $targetFileExists = file_exists( $targetFile );
196 if ( $targetFileExists ) {
199 $sourceFile = $this->group->getSourceFilePath( $collection->code );
203 $output = $this->
writeReal( $collection );
211 if ( $targetFileExists ) {
218 wfMkdirParents( dirname( $targetFile ),
null, __METHOD__ );
219 file_put_contents( $targetFile, $output );
229 $sourceFile = $this->group->getSourceFilePath( $collection->code );
243 $authors = $this->
filterAuthors( $authors, $collection->code );
245 $output .= implode( self::RECORD_SEPARATOR, $authors );
246 $output .= self::PART_SEPARATOR;
248 $mangler = $this->group->getMangler();
251 foreach ( $collection as $key => $m ) {
252 $key = $mangler->unmangle( $key );
253 $trans = $m->translation();
254 $output .=
"$key=$trans" . self::RECORD_SEPARATOR;
278 if ( $sourceText !==
false ) {
281 if ( isset( $sourceData[
'AUTHORS'] ) ) {
302 if ( !file_exists( $filename ) ) {
306 if ( !is_readable( $filename ) ) {
307 throw new MWException(
"File $filename is not readable." );
310 $data = file_get_contents( $filename );
311 if ( $data ===
false ) {
312 throw new MWException(
"Unable to read file $filename." );
326 $groupId = $this->group->getId();
327 $configHelper = Services::getInstance()->getConfigHelper();
329 foreach ( $authors as $i => $v ) {
330 if ( $configHelper->isAuthorExcluded( $groupId, $code, $v ) ) {
331 unset( $authors[$i] );
335 return array_values( $authors );
346 $data = str_replace(
"\r\n",
"\n", $data );
347 $data = str_replace(
"\r",
"\n", $data );
368 $ffs = $this->group->getFFS();
369 }
catch ( RunTimeException $e ) {
370 if ( $e->getCode() === FileBasedMessageGroup::NO_FFS_CLASS ) {
377 return get_class( $ffs ) === get_class( $this );
This class implements default behavior for file based message groups.
Core message collection class.
getAuthors()
Lists all translators that have contributed to the latest revisions of each translation.
addCollectionAuthors( $authors, $mode='append')
Add external authors (usually from the file).
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...
static fixNewLines( $data)
Replaces all Windows and Mac line endings with Unix line endings.
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.