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