PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/mediawiki-integration/source/php/mediawiki/maintenance/language/languages.inc

https://code.google.com/
PHP | 396 lines | 243 code | 21 blank | 132 comment | 42 complexity | ded10407a96db1df6687b07e9087eb2c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0
  1. <?php
  2. /**
  3. * Handle messages in the language files.
  4. *
  5. * @package MediaWiki
  6. * @subpackage Maintenance
  7. */
  8. require_once( 'messageTypes.inc' );
  9. class languages {
  10. private $mLanguages; # List of languages
  11. private $mRawMessages; # Raw list of the messages in each language
  12. private $mMessages; # Messages in each language (except for English), divided to groups
  13. private $mGeneralMessages; # General messages in English, divided to groups
  14. private $mIgnoredMessages; # All the messages which should be exist only in the English file
  15. private $mOptionalMessages; # All the messages which may be translated or not, depending on the language
  16. /**
  17. * Load the list of languages: all the Messages*.php
  18. * files in the languages directory.
  19. *
  20. * @param $exif Treat the EXIF messages?
  21. */
  22. function __construct( $exif = true ) {
  23. global $wgIgnoredMessages, $wgOptionalMessages, $wgEXIFMessages;
  24. $this->mIgnoredMessages = $wgIgnoredMessages;
  25. if ( $exif ) {
  26. $this->mOptionalMessages = array_merge( $wgOptionalMessages );
  27. } else {
  28. $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages );
  29. }
  30. $this->mLanguages = array_keys( Language::getLanguageNames( true ) );
  31. sort( $this->mLanguages );
  32. }
  33. /**
  34. * Get the language list.
  35. *
  36. * @return The language list.
  37. */
  38. public function getLanguages() {
  39. return $this->mLanguages;
  40. }
  41. /**
  42. * Get the ignored messages list.
  43. *
  44. * @return The ignored messages list.
  45. */
  46. public function getIgnoredMessages() {
  47. return $this->mIgnoredMessages;
  48. }
  49. /**
  50. * Get the optional messages list.
  51. *
  52. * @return The optional messages list.
  53. */
  54. public function getOptionalMessages() {
  55. return $this->mOptionalMessages;
  56. }
  57. /**
  58. * Load the raw messages for a specific langauge from the messages file.
  59. *
  60. * @param $code The langauge code.
  61. */
  62. private function loadRawMessages( $code ) {
  63. if ( isset( $this->mRawMessages[$code] ) ) {
  64. return;
  65. }
  66. $filename = Language::getMessagesFileName( $code );
  67. if ( file_exists( $filename ) ) {
  68. require( $filename );
  69. if ( isset( $messages ) ) {
  70. $this->mRawMessages[$code] = $messages;
  71. } else {
  72. $this->mRawMessages[$code] = array();
  73. }
  74. } else {
  75. $this->mRawMessages[$code] = array();
  76. }
  77. }
  78. /**
  79. * Load the messages for a specific language (which is not English) and divide them to groups:
  80. * all - all the messages.
  81. * required - messages which should be translated in order to get a complete translation.
  82. * optional - messages which can be translated, the fallback translation is used if not translated.
  83. * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
  84. * translated - messages which are either required or optional, but translated from English and needed.
  85. *
  86. * @param $code The language code.
  87. */
  88. private function loadMessages( $code ) {
  89. if ( isset( $this->mMessages[$code] ) ) {
  90. return;
  91. }
  92. $this->loadRawMessages( $code );
  93. $this->loadGeneralMessages();
  94. $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
  95. $this->mMessages[$code]['required'] = array();
  96. $this->mMessages[$code]['optional'] = array();
  97. $this->mMessages[$code]['obsolete'] = array();
  98. $this->mMessages[$code]['translated'] = array();
  99. foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
  100. if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
  101. $this->mMessages[$code]['required'][$key] = $value;
  102. $this->mMessages[$code]['translated'][$key] = $value;
  103. } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
  104. $this->mMessages[$code]['optional'][$key] = $value;
  105. $this->mMessages[$code]['translated'][$key] = $value;
  106. } else {
  107. $this->mMessages[$code]['obsolete'][$key] = $value;
  108. }
  109. }
  110. }
  111. /**
  112. * Load the messages for English and divide them to groups:
  113. * all - all the messages.
  114. * required - messages which should be translated to other languages in order to get a complete translation.
  115. * optional - messages which can be translated to other languages, but it's not required for a complete translation.
  116. * ignored - messages which should not be translated to other languages.
  117. * translatable - messages which are either required or optional, but can be translated from English.
  118. */
  119. private function loadGeneralMessages() {
  120. if ( isset( $this->mGeneralMessages ) ) {
  121. return;
  122. }
  123. $this->loadRawMessages( 'en' );
  124. $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
  125. $this->mGeneralMessages['required'] = array();
  126. $this->mGeneralMessages['optional'] = array();
  127. $this->mGeneralMessages['ignored'] = array();
  128. $this->mGeneralMessages['translatable'] = array();
  129. foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
  130. if ( in_array( $key, $this->mIgnoredMessages ) ) {
  131. $this->mGeneralMessages['ignored'][$key] = $value;
  132. } else if ( in_array( $key, $this->mOptionalMessages ) ) {
  133. $this->mGeneralMessages['optional'][$key] = $value;
  134. $this->mGeneralMessages['translatable'][$key] = $value;
  135. } else {
  136. $this->mGeneralMessages['required'][$key] = $value;
  137. $this->mGeneralMessages['translatable'][$key] = $value;
  138. }
  139. }
  140. }
  141. /**
  142. * Get all the messages for a specific langauge (not English), without the
  143. * fallback language messages, divided to groups:
  144. * all - all the messages.
  145. * required - messages which should be translated in order to get a complete translation.
  146. * optional - messages which can be translated, the fallback translation is used if not translated.
  147. * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
  148. * translated - messages which are either required or optional, but translated from English and needed.
  149. *
  150. * @param $code The langauge code.
  151. *
  152. * @return The messages in this language.
  153. */
  154. public function getMessages( $code ) {
  155. $this->loadMessages( $code );
  156. return $this->mMessages[$code];
  157. }
  158. /**
  159. * Get all the general English messages, divided to groups:
  160. * all - all the messages.
  161. * required - messages which should be translated to other languages in order to get a complete translation.
  162. * optional - messages which can be translated to other languages, but it's not required for a complete translation.
  163. * ignored - messages which should not be translated to other languages.
  164. * translatable - messages which are either required or optional, but can be translated from English.
  165. *
  166. * @return The general English messages.
  167. */
  168. public function getGeneralMessages() {
  169. $this->loadGeneralMessages();
  170. return $this->mGeneralMessages;
  171. }
  172. /**
  173. * Get the untranslated messages for a specific language.
  174. *
  175. * @param $code The langauge code.
  176. *
  177. * @return The untranslated messages for this language.
  178. */
  179. public function getUntranslatedMessages( $code ) {
  180. $this->loadGeneralMessages();
  181. $this->loadMessages( $code );
  182. $requiredGeneralMessages = array_keys( $this->mGeneralMessages['required'] );
  183. $requiredMessages = array_keys( $this->mMessages[$code]['required'] );
  184. $untranslatedMessages = array();
  185. foreach ( array_diff( $requiredGeneralMessages, $requiredMessages ) as $key ) {
  186. $untranslatedMessages[$key] = $this->mGeneralMessages['required'][$key];
  187. }
  188. return $untranslatedMessages;
  189. }
  190. /**
  191. * Get the duplicate messages for a specific language.
  192. *
  193. * @param $code The langauge code.
  194. *
  195. * @return The duplicate messages for this language.
  196. */
  197. public function getDuplicateMessages( $code ) {
  198. $this->loadGeneralMessages();
  199. $this->loadMessages( $code );
  200. $duplicateMessages = array();
  201. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  202. if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
  203. $duplicateMessages[$key] = $value;
  204. }
  205. }
  206. return $duplicateMessages;
  207. }
  208. /**
  209. * Get the messages which do not use some variables.
  210. *
  211. * @param $code The langauge code.
  212. *
  213. * @return The messages which do not use some variables in this language.
  214. */
  215. public function getMessagesWithoutVariables( $code ) {
  216. $this->loadGeneralMessages();
  217. $this->loadMessages( $code );
  218. $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
  219. $messagesWithoutVariables = array();
  220. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  221. $missing = false;
  222. foreach ( $variables as $var ) {
  223. if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
  224. !preg_match( "/$var/sU", $value ) ) {
  225. $missing = true;
  226. }
  227. }
  228. if ( $missing ) {
  229. $messagesWithoutVariables[$key] = $value;
  230. }
  231. }
  232. return $messagesWithoutVariables;
  233. }
  234. /**
  235. * Get the empty messages.
  236. *
  237. * @param $code The langauge code.
  238. *
  239. * @return The empty messages for this language.
  240. */
  241. public function getEmptyMessages( $code ) {
  242. $this->loadGeneralMessages();
  243. $this->loadMessages( $code );
  244. $emptyMessages = array();
  245. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  246. if ( $value === '' || $value === '-' ) {
  247. $emptyMessages[$key] = $value;
  248. }
  249. }
  250. return $emptyMessages;
  251. }
  252. /**
  253. * Get the messages with trailing whitespace.
  254. *
  255. * @param $code The langauge code.
  256. *
  257. * @return The messages with trailing whitespace in this language.
  258. */
  259. public function getMessagesWithWhitespace( $code ) {
  260. $this->loadGeneralMessages();
  261. $this->loadMessages( $code );
  262. $messagesWithWhitespace = array();
  263. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  264. if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
  265. $messagesWithWhitespace[$key] = $value;
  266. }
  267. }
  268. return $messagesWithWhitespace;
  269. }
  270. /**
  271. * Get the non-XHTML messages.
  272. *
  273. * @param $code The langauge code.
  274. *
  275. * @return The non-XHTML messages for this language.
  276. */
  277. public function getNonXHTMLMessages( $code ) {
  278. $this->loadGeneralMessages();
  279. $this->loadMessages( $code );
  280. $wrongPhrases = array(
  281. '<hr *\\?>',
  282. '<br *\\?>',
  283. '<hr/>',
  284. '<br/>',
  285. );
  286. $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
  287. $nonXHTMLMessages = array();
  288. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  289. if ( preg_match( $wrongPhrases, $value ) ) {
  290. $nonXHTMLMessages[$key] = $value;
  291. }
  292. }
  293. return $nonXHTMLMessages;
  294. }
  295. /**
  296. * Get the messages which include wrong characters.
  297. *
  298. * @param $code The langauge code.
  299. *
  300. * @return The messages which include wrong characters in this language.
  301. */
  302. public function getMessagesWithWrongChars( $code ) {
  303. $this->loadGeneralMessages();
  304. $this->loadMessages( $code );
  305. $wrongChars = array(
  306. '[LRM]' => "\xE2\x80\x8E",
  307. '[RLM]' => "\xE2\x80\x8F",
  308. '[LRE]' => "\xE2\x80\xAA",
  309. '[RLE]' => "\xE2\x80\xAB",
  310. '[POP]' => "\xE2\x80\xAC",
  311. '[LRO]' => "\xE2\x80\xAD",
  312. '[RLO]' => "\xE2\x80\xAB",
  313. '[ZWSP]'=> "\xE2\x80\x8B",
  314. '[NBSP]'=> "\xC2\xA0",
  315. '[WJ]' => "\xE2\x81\xA0",
  316. '[BOM]' => "\xEF\xBB\xBF",
  317. '[FFFD]'=> "\xEF\xBF\xBD",
  318. );
  319. $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
  320. $wrongCharsMessages = array();
  321. foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
  322. if ( preg_match( $wrongRegExp, $value ) ) {
  323. foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
  324. $value = str_replace( $hiddenChar, $viewableChar, $value );
  325. }
  326. $wrongCharsMessages[$key] = $value;
  327. }
  328. }
  329. return $wrongCharsMessages;
  330. }
  331. /**
  332. * Output a messages list
  333. *
  334. * @param $messages The messages list
  335. * @param $code The language code
  336. * @param $text The text to show before the list (optional)
  337. * @param $level The display level (optional)
  338. * @param $links Show links (optional)
  339. * @param $wikilang The langauge of the wiki to display the list in, for the links (optional)
  340. */
  341. public function outputMessagesList( $messages, $code, $text = '', $level = 2, $links = false, $wikilang = null ) {
  342. if ( count( $messages ) == 0 ) {
  343. return;
  344. }
  345. if ( $text ) {
  346. echo "$text\n";
  347. }
  348. if ( $level == 1 ) {
  349. echo "[messages are hidden]\n";
  350. } else {
  351. foreach ( $messages as $key => $value ) {
  352. if ( $links ) {
  353. $displayKey = ucfirst( $key );
  354. if ( !isset( $wikilang ) ) {
  355. global $wgContLang;
  356. $wikilang = $wgContLang->getCode();
  357. }
  358. if ( $code == $wikilang ) {
  359. $displayKey = "[[MediaWiki:$displayKey|$key]]";
  360. } else {
  361. $displayKey = "[[MediaWiki:$displayKey/$code|$key]]";
  362. }
  363. } else {
  364. $displayKey = $key;
  365. }
  366. if ( $level == 2 ) {
  367. echo "* $displayKey\n";
  368. } else {
  369. echo "* $displayKey: '$value'\n";
  370. }
  371. }
  372. }
  373. }
  374. }
  375. ?>