Merge "Remove redirectToFragment() from wikibits.js"
[mediawiki.git] / maintenance / language / writeMessagesArray.inc
blob7c880b2f9fa045cf07e3f0aa7e86e98bb4eb1013
1 <?php
2 /**
3  * Write a messages array as a PHP text.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup MaintenanceLanguage
22  */
24 /**
25  * @ingroup MaintenanceLanguage
26  */
27 class MessageWriter {
28         protected static $optionalComment =
29                 'only translate this message to other languages if you have to change it';
30         protected static $ignoredComment = "do not translate or duplicate this message to other languages";
32         protected static $messageStructure;
33         protected static $blockComments;
34         protected static $ignoredMessages;
35         protected static $optionalMessages;
37         /**
38          * Write a messages array as a PHP text and write it to the messages file.
39          *
40          * @param $messages Array: the messages array.
41          * @param $code String: the language code.
42          * @param $write Boolean: write to the messages file?
43          * @param $listUnknown Boolean: list the unknown messages?
44          * @param $removeUnknown Boolean: whether to remove unkown messages
45          * @param $messagesFolder String: path to a folder to store the MediaWiki messages.
46          *        Defaults to the current install.
47          */
48         public static function writeMessagesToFile( $messages, $code, $write, $listUnknown,
49                 $removeUnknown, $messagesFolder = false
50         ) {
51                 # Rewrite the messages array
52                 $messages = self::writeMessagesArray( $messages, $code == 'en', false, $removeUnknown );
53                 $messagesText = $messages[0];
54                 $sortedMessages = $messages[1];
56                 # Write to the file
57                 if ( $messagesFolder ) {
58                         $filename = Language::getFileName( "$messagesFolder/Messages", $code );
59                 } else {
60                         $filename = Language::getMessagesFileName( $code );
61                 }
63                 if ( file_exists( $filename ) ) {
64                         $contents = file_get_contents( $filename );
65                 } else {
66                         $contents = '<?php
67 $messages = array(
70                 }
72                 if ( strpos( $contents, '$messages' ) !== false ) {
73                         $contents = explode( '$messages', $contents );
74                         if ( $messagesText == '$messages' . $contents[1] ) {
75                                 echo "Generated messages for language $code. Same as the current file.\n";
76                         } else {
77                                 if ( $write ) {
78                                         $new = $contents[0];
79                                         $new .= $messagesText;
80                                         file_put_contents( $filename, $new );
81                                         echo "Generated and wrote messages for language $code.\n";
82                                 } else {
83                                         echo "Generated messages for language $code.\n" .
84                                                 "Please run the script again (without the parameter \"dry-run\") " .
85                                                 "to write the array to the file.\n";
86                                 }
87                         }
88                         if ( $listUnknown && isset( $sortedMessages['unknown'] ) &&
89                                 !empty( $sortedMessages['unknown'] )
90                         ) {
91                                 if ( $removeUnknown ) {
92                                         echo "\nThe following " . count( $sortedMessages['unknown'] ) .
93                                                 " unknown messages have been removed:\n";
94                                 } else {
95                                         echo "\nThere are " . count( $sortedMessages['unknown'] ) .
96                                                 " unknown messages, please check them:\n";
97                                 }
98                                 foreach ( $sortedMessages['unknown'] as $key => $value ) {
99                                         echo "* " . $key . "\n";
100                                 }
101                         }
102                 } else {
103                         echo "Generated messages for language $code. There seem to be no messages array in the file.\n";
104                 }
105         }
107         /**
108          * Write a messages array as a PHP text.
109          *
110          * @param $messages Array: the messages array.
111          * @param $ignoredComments Boolean: show comments about ignored and optional
112          *                         messages? (For English.)
113          * @param $prefix String: base path for messages.inc and messageTypes.inc files
114          *                or false for default path (this directory)
115          * @param $removeUnknown Boolean: whether to remove unkown messages
116          *
117          * @return Array of the PHP text and the sorted messages array.
118          */
119         public static function writeMessagesArray( $messages, $ignoredComments = false,
120                 $prefix = false, $removeUnknown = false
121         ) {
122                 # Load messages
123                 $dir = $prefix ? $prefix : __DIR__;
125                 require $dir . '/messages.inc';
126                 self::$messageStructure = $wgMessageStructure;
127                 self::$blockComments = $wgBlockComments;
129                 require $dir . '/messageTypes.inc';
130                 self::$ignoredMessages = $wgIgnoredMessages;
131                 self::$optionalMessages = $wgOptionalMessages;
133                 # Sort messages to blocks
134                 $sortedMessages['unknown'] = $messages;
135                 foreach ( self::$messageStructure as $blockName => $block ) {
136                         /**
137                          * @var $block array
138                          */
139                         foreach ( $block as $key ) {
140                                 if ( array_key_exists( $key, $sortedMessages['unknown'] ) ) {
141                                         $sortedMessages[$blockName][$key] = $sortedMessages['unknown'][$key];
142                                         unset( $sortedMessages['unknown'][$key] );
143                                 }
144                         }
145                 }
147                 # Write all the messages
148                 $messagesText = "\$messages = array(
150                 foreach ( $sortedMessages as $block => $messages ) {
151                         # Skip if it's the block of unknown messages - handle that in the end of file
152                         if ( $block == 'unknown' ) {
153                                 continue;
154                         }
156                         if ( $ignoredComments ) {
157                                 $ignored = self::$ignoredMessages;
158                                 $optional = self::$optionalMessages;
159                         } else {
160                                 $ignored = array();
161                                 $optional = array();
162                         }
163                         $comments = self::makeComments( array_keys( $messages ), $ignored, $optional );
165                         # Write the block
166                         $messagesText .= self::writeMessagesBlock( self::$blockComments[$block], $messages, $comments );
167                 }
169                 # Write the unknown messages, alphabetically sorted.
170                 # Of course, we don't have any comments for them, because they are unknown.
171                 if ( !$removeUnknown ) {
172                         ksort( $sortedMessages['unknown'] );
173                         $messagesText .= self::writeMessagesBlock( 'Unknown messages', $sortedMessages['unknown'] );
174                 }
175                 $messagesText .= ");
178                 return array( $messagesText, $sortedMessages );
179         }
181         /**
182          * Generates an array of comments for messages.
183          *
184          * @param $messages Array: key of messages.
185          * @param $ignored Array: list of ingored message keys.
186          * @param $optional Array: list of optional message keys.
187          * @return array
188          */
189         public static function makeComments( $messages, $ignored, $optional ) {
190                 # Comment collector
191                 $commentArray = array();
193                 # List of keys only
194                 foreach ( $messages as $key ) {
195                         if ( in_array( $key, $ignored ) ) {
196                                 $commentArray[$key] = ' # ' . self::$ignoredComment;
197                         } elseif ( in_array( $key, $optional ) ) {
198                                 $commentArray[$key] = ' # ' . self::$optionalComment;
199                         }
200                 }
202                 return $commentArray;
203         }
205         /**
206          * Write a block of messages to PHP.
207          *
208          * @param $blockComment String: the comment of whole block.
209          * @param $messages Array: the block messages.
210          * @param $messageComments Array: optional comments for messages in this block.
211          * @param $prefix String: prefix for every line, for indenting purposes.
212          *
213          * @return string The block, formatted in PHP.
214          */
215         public static function writeMessagesBlock( $blockComment, $messages,
216                 $messageComments = array(), $prefix = '' ) {
218                 $blockText = '';
220                 # Skip the block if it includes no messages
221                 if ( empty( $messages ) ) {
222                         return '';
223                 }
225                 # Format the block comment (if exists); check for multiple lines comments
226                 if ( !empty( $blockComment ) ) {
227                         if ( strpos( $blockComment, "\n" ) === false ) {
228                                 $blockText .= "$prefix# $blockComment
230                         } else {
231                                 $blockText .= "$prefix/*
232 $blockComment
235                         }
236                 }
238                 # Get max key length
239                 $maxKeyLength = max( array_map( 'strlen', array_keys( $messages ) ) );
241                 # Format the messages
242                 foreach ( $messages as $key => $value ) {
243                         # Add the key name
244                         $blockText .= "$prefix'$key'";
246                         # Add the appropriate block whitespace
247                         $blockText .= str_repeat( ' ', $maxKeyLength - strlen( $key ) );
249                         # Refer to the value
250                         $blockText .= ' => ';
252                         # Check for the appropriate apostrophe and add the value
253                         # Quote \ here, because it needs always escaping
254                         $value = addcslashes( $value, '\\' );
256                         # For readability
257                         $single = "'";
258                         $double = '"';
260                         if ( strpos( $value, $single ) === false ) {
261                                 # Nothing ugly, just use '
262                                 $blockText .= $single . $value . $single;
263                         } elseif ( strpos( $value, $double ) === false &&
264                                 !preg_match( '/\$[a-zA-Z_\x7f-\xff]/', $value )
265                         ) {
266                                 # No "-quotes, no variables that need quoting, use "
267                                 $blockText .= $double . $value . $double;
268                         } else {
269                                 # Something needs quoting, pick the quote which causes less quoting
271                                 if ( substr_count( $value, $double ) + substr_count( $value, '$' ) >=
272                                         substr_count( $value, $single )
273                                 ) {
274                                         $quote = $single;
275                                 } else {
276                                         $quote = $double;
277                                 }
279                                 if ( $quote === $double ) {
280                                         $extra = '$';
281                                 } else {
282                                         $extra = '';
283                                 }
284                                 $blockText .= $quote . addcslashes( $value, $quote . $extra ) . $quote;
285                         }
287                         # Comma
288                         $blockText .= ',';
290                         # Add comments, if there is any
291                         if ( array_key_exists( $key, $messageComments ) ) {
292                                 $blockText .= $messageComments[$key];
293                         }
295                         # Newline
296                         $blockText .= "
298                 }
300                 # Newline to end the block
301                 $blockText .= "
304                 return $blockText;
305         }