Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
YamlFormat
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 8
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getFileExtensions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 readFromVariable
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 writeReal
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
30
 doHeader
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 doAuthors
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 isContentEqual
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExtraSchema
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\FileFormatSupport;
5
6use FileBasedMessageGroup;
7use MediaWiki\Extension\Translate\MessageGroupConfiguration\MetaYamlSchemaExtender;
8use MediaWiki\Extension\Translate\MessageLoading\Message;
9use MediaWiki\Extension\Translate\MessageLoading\MessageCollection;
10use MediaWiki\Extension\Translate\MessageProcessing\ArrayFlattener;
11use MediaWiki\Extension\Translate\Utilities\Utilities;
12use MediaWiki\Extension\Translate\Utilities\Yaml;
13
14/**
15 * Implements support for message storage in YAML format.
16 *
17 * This class adds new key into FILES section: \c codeAsRoot.
18 * If it is set to true, all messages will under language code.
19 * @ingroup FileFormatSupport
20 */
21class YamlFormat extends SimpleFormat implements MetaYamlSchemaExtender {
22    private ArrayFlattener $flattener;
23
24    public function __construct( FileBasedMessageGroup $group ) {
25        parent::__construct( $group );
26
27        // Obtains object used to flatten and unflatten arrays. In this implementation
28        // we use the ArrayFlattener class which also supports CLDR pluralization rules.
29        $this->flattener = new ArrayFlattener(
30            $this->extra['nestingSeparator'] ?? '.',
31            $this->extra['parseCLDRPlurals'] ?? false
32        );
33    }
34
35    public function getFileExtensions(): array {
36        return [ '.yaml', '.yml' ];
37    }
38
39    /** @inheritDoc */
40    public function readFromVariable( string $data ): array {
41        // Authors first.
42        $matches = [];
43        preg_match_all( '/^#\s*Author:\s*(.*)$/m', $data, $matches );
44        $authors = $matches[1];
45
46        // Then messages.
47        $messages = Yaml::loadString( $data );
48
49        // Some groups have messages under language code
50        if ( isset( $this->extra['codeAsRoot'] ) ) {
51            $messages = array_shift( $messages ) ?? [];
52        }
53
54        $messages = $this->flattener->flatten( $messages );
55        $messages = $this->group->getMangler()->mangleArray( $messages );
56        foreach ( $messages as &$value ) {
57            $value = rtrim( $value, "\n" );
58        }
59
60        return [
61            'AUTHORS' => $authors,
62            'MESSAGES' => $messages,
63        ];
64    }
65
66    protected function writeReal( MessageCollection $collection ): string {
67        $output = $this->doHeader( $collection );
68        $output .= $this->doAuthors( $collection );
69
70        $mangler = $this->group->getMangler();
71
72        $messages = [];
73
74        /** @var Message $m */
75        foreach ( $collection as $key => $m ) {
76            $key = $mangler->unmangle( $key );
77            $value = $m->translation();
78            $value = str_replace( TRANSLATE_FUZZY, '', $value );
79
80            if ( $value === '' ) {
81                continue;
82            }
83
84            $messages[$key] = $value;
85        }
86
87        if ( !count( $messages ) ) {
88            return '';
89        }
90        $messages = $this->flattener->unflatten( $messages );
91
92        // Some groups have messages under language code.
93        if ( isset( $this->extra['codeAsRoot'] ) ) {
94            $code = $this->group->mapCode( $collection->code );
95            $messages = [ $code => $messages ];
96        }
97
98        $output .= Yaml::dump( $messages );
99
100        return $output;
101    }
102
103    private function doHeader( MessageCollection $collection ): string {
104        global $wgSitename;
105        global $wgTranslateYamlLibrary;
106
107        $code = $collection->code;
108        $name = Utilities::getLanguageName( $code );
109        $native = Utilities::getLanguageName( $code, $code );
110        $output = "# Messages for $name ($native)\n";
111        $output .= "# Exported from $wgSitename\n";
112
113        if ( isset( $wgTranslateYamlLibrary ) ) {
114            $output .= "# Export driver: $wgTranslateYamlLibrary\n";
115        }
116
117        return $output;
118    }
119
120    private function doAuthors( MessageCollection $collection ): string {
121        $output = '';
122        $authors = $collection->getAuthors();
123        $authors = $this->filterAuthors( $authors, $collection->code );
124
125        foreach ( $authors as $author ) {
126            $output .= "# Author: $author\n";
127        }
128
129        return $output;
130    }
131
132    public function isContentEqual( ?string $a, ?string $b ): bool {
133        return $this->flattener->compareContent( $a, $b );
134    }
135
136    public static function getExtraSchema(): array {
137        return [
138            'root' => [
139                '_type' => 'array',
140                '_children' => [
141                    'FILES' => [
142                        '_type' => 'array',
143                        '_children' => [
144                            'codeAsRoot' => [
145                                '_type' => 'boolean',
146                            ],
147                            'nestingSeparator' => [
148                                '_type' => 'text',
149                            ],
150                            'parseCLDRPlurals' => [
151                                '_type' => 'boolean',
152                            ]
153                        ]
154                    ]
155                ]
156            ]
157        ];
158    }
159}
160
161class_alias( YamlFormat::class, 'YamlFFS' );