summaryrefslogtreecommitdiff
path: root/extensions/LocalisationUpdate/LocalisationUpdate.class.php
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2014-01-28 09:50:25 -0500
committerLuke Shumaker <LukeShu@sbcglobal.net>2014-01-28 09:50:25 -0500
commit5744df39e15f85c6cc8a9faf8924d77e76d2b216 (patch)
treea8c8dd40a94d1fa0d5377566aa5548ae55a163da /extensions/LocalisationUpdate/LocalisationUpdate.class.php
parent4bb2aeca1d198391ca856aa16c40b8559c68daec (diff)
parent224b22a051051f6c2e494c3a2fb4adb42898e2d1 (diff)
Merge branch 'archwiki'
Conflicts: extensions/FluxBBAuthPlugin.php extensions/SyntaxHighlight_GeSHi/README extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.i18n.php extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php extensions/SyntaxHighlight_GeSHi/geshi/docs/CHANGES extensions/SyntaxHighlight_GeSHi/geshi/docs/THANKS extensions/SyntaxHighlight_GeSHi/geshi/docs/TODO extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constant.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constructor.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Destructor.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Function.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Global.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/I.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Index.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/L.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lminus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lplus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Method.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateVariable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticVariable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/T.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tminus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tplus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Variable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/blank.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/class_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/file.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/function_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button_disabled.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button_disabled.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/private_class_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/up_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.html extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.txt extensions/SyntaxHighlight_GeSHi/geshi/geshi.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/4cs.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502acme.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502kickass.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502tasm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/68000devpac.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/abap.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript3.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ada.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/algol68.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/apache.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/applescript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/apt_sources.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/asm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/asp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoconf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autohotkey.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoit.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/avisynth.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/awk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bascomavr.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bash.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/basic4gl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bibtex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/blitzbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bnf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/boo.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_loadrunner.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_mac.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/caddcl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cadlisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfdg.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/chaiscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cil.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/clojure.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cmake.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cobol.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/coffeescript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp-qt.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/csharp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/css.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cuesheet.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/d.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dcs.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/delphi.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/diff.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/div.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dos.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dot.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/e.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ecmascript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/eiffel.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/email.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/epc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/erlang.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/euphoria.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/f1.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/falcon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fo.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fortran.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/freebasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fsharp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gambas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gdb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/genero.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/genie.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gettext.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/glsl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gnuplot.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/go.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/groovy.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gwbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/haskell.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/hicest.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/hq9plus.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/html4strict.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/html5.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/icon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/idl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ini.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/inno.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/intercal.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/io.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/j.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/java.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/java5.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/javascript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/jquery.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/kixtart.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonec.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonecpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/latex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/llvm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/locobasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/logtalk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lolcode.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusformulas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lsl2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lua.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/m68k.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/magiksf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/make.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mapbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/matlab.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mirc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mmix.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula3.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mpasm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mxml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mysql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/newlisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/nsis.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oberon2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/objc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/objeck.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml-brief.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oobas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle11.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle8.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oxygene.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oz.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pascal.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pcre.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/per.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl6.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/php-brief.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/php.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pic16.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pike.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pixelbender.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pli.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/plsql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/postgresql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/povray.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/powerbuilder.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/powershell.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/proftpd.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/progress.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/prolog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/properties.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/providex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/purebasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pycon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/python.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/q.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/qbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rails.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rebol.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/reg.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/robots.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rpmspec.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rsplus.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ruby.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scala.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scheme.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scilab.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sdlbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/smalltalk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/smarty.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/systemverilog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/tcl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/teraterm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/text.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/thinbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/tsql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/typoscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/unicon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/uscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vala.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vbnet.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/verilog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vhdl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vim.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualfoxpro.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualprolog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/whitespace.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/whois.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/winbatch.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xorg_conf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/yaml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/z80.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/zxbasic.php
Diffstat (limited to 'extensions/LocalisationUpdate/LocalisationUpdate.class.php')
-rw-r--r--extensions/LocalisationUpdate/LocalisationUpdate.class.php596
1 files changed, 596 insertions, 0 deletions
diff --git a/extensions/LocalisationUpdate/LocalisationUpdate.class.php b/extensions/LocalisationUpdate/LocalisationUpdate.class.php
new file mode 100644
index 00000000..66b63232
--- /dev/null
+++ b/extensions/LocalisationUpdate/LocalisationUpdate.class.php
@@ -0,0 +1,596 @@
+<?php
+
+/**
+ * Class for localization updates.
+ *
+ * TODO: refactor code to remove duplication
+ */
+class LocalisationUpdate {
+
+ private static $newHashes = null;
+ private static $filecache = array();
+
+ /**
+ * LocalisationCacheRecache hook handler.
+ *
+ * @param $lc LocalisationCache
+ * @param $langcode String
+ * @param $cache Array
+ *
+ * @return true
+ */
+ public static function onRecache( LocalisationCache $lc, $langcode, array &$cache ) {
+ // Handle fallback sequence and load all fallback messages from the cache
+ $codeSequence = array_merge( array( $langcode ), $cache['fallbackSequence'] );
+ // Iterate over the fallback sequence in reverse, otherwise the fallback
+ // language will override the requested language
+ foreach ( array_reverse( $codeSequence ) as $code ) {
+ if ( $code == 'en' ) {
+ // Skip English, otherwise we end up trying to read
+ // the nonexistent cache file for en a couple hundred times
+ continue;
+ }
+
+ $cache['messages'] = array_merge(
+ $cache['messages'],
+ self::readFile( $code )
+ );
+
+ $cache['deps'][] = new FileDependency(
+ self::filename( $code )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Called from the cronjob to fetch new messages from SVN.
+ *
+ * @param $options Array
+ *
+ * @return true
+ */
+ public static function updateMessages( array $options ) {
+ global $wgLocalisationUpdateDirectory, $wgLocalisationUpdateCoreURL,
+ $wgLocalisationUpdateExtensionURL, $wgLocalisationUpdateSVNURL;
+
+ $verbose = !isset( $options['quiet'] );
+ $all = isset( $options['all'] );
+ $skipCore = isset( $options['skip-core'] );
+ $skipExtensions = isset( $options['skip-extensions'] );
+
+ if( isset( $options['outdir'] ) ) {
+ $wgLocalisationUpdateDirectory = $options['outdir'];
+ }
+
+ $coreUrl = $wgLocalisationUpdateCoreURL;
+ $extUrl = $wgLocalisationUpdateExtensionURL;
+
+ // Some ugly BC
+ if ( $wgLocalisationUpdateSVNURL ) {
+ $coreUrl = $wgLocalisationUpdateSVNURL . '/phase3/$2';
+ $extUrl = $wgLocalisationUpdateSVNURL . '/extensions/$1/$2';
+ }
+
+ // Some more ugly BC
+ if ( isset( $options['svnurl'] ) ) {
+ $coreUrl = $options['svnurl'] . '/phase3/$2';
+ $extUrl = $options['svnurl'] . '/extensions/$1/$2';
+ }
+
+ $result = 0;
+
+ // Update all MW core messages.
+ if( !$skipCore ) {
+ $result = self::updateMediawikiMessages( $verbose, $coreUrl );
+ }
+
+ // Update all Extension messages.
+ if( !$skipExtensions ) {
+ if( $all ) {
+ global $IP;
+ $extFiles = array();
+
+ // Look in extensions/ for all available items...
+ // TODO: add support for $wgExtensionAssetsPath
+ $dirs = new RecursiveDirectoryIterator( "$IP/extensions/" );
+
+ // I ain't kidding... RecursiveIteratorIterator.
+ foreach( new RecursiveIteratorIterator( $dirs ) as $pathname => $item ) {
+ $filename = basename( $pathname );
+ $matches = array();
+ if( preg_match( '/^(.*)\.i18n\.php$/', $filename, $matches ) ) {
+ $group = $matches[1];
+ $extFiles[$group] = $pathname;
+ }
+ }
+ } else {
+ global $wgExtensionMessagesFiles;
+ $extFiles = $wgExtensionMessagesFiles;
+ }
+ foreach ( $extFiles as $extension => $locFile ) {
+ $result += self::updateExtensionMessages( $locFile, $extension, $verbose, $extUrl );
+ }
+ }
+
+ self::writeHashes();
+
+ // And output the result!
+ self::myLog( "Updated {$result} messages in total" );
+ self::myLog( "Done" );
+
+ return true;
+ }
+
+ /**
+ * Update Extension Messages.
+ *
+ * @param $file String
+ * @param $extension String
+ * @param $verbose Boolean
+ *
+ * @return Integer: the amount of updated messages
+ */
+ public static function updateExtensionMessages( $file, $extension, $verbose, $extUrl ) {
+ $match = array();
+ $ok = preg_match( '~^.*/extensions/([^/]+)/(.*)$~U', $file, $match );
+ if ( !$ok ) {
+ return null;
+ }
+
+ $ext = $match[1];
+ $extFile = $match[2];
+
+ // Create a full path.
+ $svnfile = str_replace(
+ array( '$1', '$2', '$3', '$4' ),
+ array( $ext, $extFile, urlencode( $ext ), urlencode( $extFile ) ),
+ $extUrl
+ );
+
+ // Compare the 2 files.
+ $result = self::compareExtensionFiles( $extension, $svnfile, $file, $verbose );
+
+ return $result;
+ }
+
+ /**
+ * Update the MediaWiki Core Messages.
+ *
+ * @param $verbose Boolean
+ *
+ * @return Integer: the amount of updated messages
+ */
+ public static function updateMediawikiMessages( $verbose, $coreUrl ) {
+ // Find the changed English strings (as these messages won't be updated in ANY language).
+ $localUrl = Language::getMessagesFileName( 'en' );
+ $repoUrl = str_replace(
+ array( '$2', '$4' ),
+ array( 'languages/messages/MessagesEn.php', 'languages%2Fmessages%2FMessagesEn.php' ),
+ $coreUrl
+ );
+ $changedEnglishStrings = self::compareFiles( $repoUrl, $localUrl, $verbose );
+
+ // Count the changes.
+ $changedCount = 0;
+
+ $languages = Language::fetchLanguageNames( null, 'mwfile' );
+ foreach ( array_keys( $languages ) as $code ) {
+ $localUrl = Language::getMessagesFileName( $code );
+ // Not prefixed with $IP
+ $filename = Language::getFilename( 'languages/messages/Messages', $code );
+ $repoUrl = str_replace(
+ array( '$2', '$4' ),
+ array( $filename, urlencode( $filename ) ),
+ $coreUrl
+ );
+
+ // Compare the files.
+ $changedCount += self::compareFiles( $repoUrl, $localUrl, $verbose, $changedEnglishStrings, false, true );
+ }
+
+ // Log some nice info.
+ self::myLog( "{$changedCount} MediaWiki messages are updated" );
+
+ return $changedCount;
+ }
+
+ /**
+ * Removes all unneeded content from a file and returns it.
+ *
+ * @param $contents String
+ *
+ * @return String
+ */
+ public static function cleanupFile( $contents ) {
+ // We don't need any PHP tags.
+ $contents = strtr( $contents,
+ array(
+ '<?php' => '',
+ '?' . '>' => ''
+ )
+ );
+
+ $results = array();
+
+ // And we only want message arrays.
+ preg_match_all( '/\$messages(.*\s)*?\);/', $contents, $results );
+
+ // But we want them all in one string.
+ if( !empty( $results[0] ) && is_array( $results[0] ) ) {
+ $contents = implode( "\n\n", $results[0] );
+ } else {
+ $contents = '';
+ }
+
+ // And we hate the windows vs linux linebreaks.
+ $contents = preg_replace( '/\r\n?/', "\n", $contents );
+
+ return $contents;
+ }
+
+ /**
+ * Returns the contents of a file or false on failiure.
+ *
+ * @param $file String
+ *
+ * @return string or false
+ */
+ public static function getFileContents( $file ) {
+ global $wgLocalisationUpdateRetryAttempts;
+
+ $attempts = 0;
+ $filecontents = '';
+
+ // Use cURL to get the SVN contents.
+ if ( preg_match( "/^http/", $file ) ) {
+ while( !$filecontents && $attempts <= $wgLocalisationUpdateRetryAttempts ) {
+ if( $attempts > 0 ) {
+ $delay = 1;
+ self::myLog( 'Failed to download ' . $file . "; retrying in ${delay}s..." );
+ sleep( $delay );
+ }
+
+ $filecontents = Http::get( $file );
+ $attempts++;
+ }
+ if ( !$filecontents ) {
+ self::myLog( 'Cannot get the contents of ' . $file . ' (curl)' );
+ return false;
+ }
+ } else {// otherwise try file_get_contents
+ if ( !( $filecontents = file_get_contents( $file ) ) ) {
+ self::myLog( 'Cannot get the contents of ' . $file );
+ return false;
+ }
+ }
+
+ return $filecontents;
+ }
+
+ /**
+ * Returns a pair of arrays containing the messages from two files, or
+ * a pair of nulls if the files don't need to be checked.
+ *
+ * @param $tag String
+ * @param $file1 String
+ * @param $file2 String
+ * @param $verbose Boolean
+ * @param $alwaysGetResult Boolean
+ *
+ * @return array
+ */
+ public static function loadFilesToCompare( $tag, $file1, $file2, $verbose, $alwaysGetResult = true ) {
+ $file1contents = self::getFileContents( $file1 );
+ if ( $file1contents === false || $file1contents === '' ) {
+ self::myLog( "Failed to read $file1" );
+ return array( null, null );
+ }
+
+ $file2contents = self::getFileContents( $file2 );
+ if ( $file2contents === false || $file2contents === '' ) {
+ self::myLog( "Failed to read $file2" );
+ return array( null, null );
+ }
+
+ // Only get the part we need.
+ $file1contents = self::cleanupFile( $file1contents );
+ $file1hash = md5( $file1contents );
+
+ $file2contents = self::cleanupFile( $file2contents );
+ $file2hash = md5( $file2contents );
+
+ // Check if the file has changed since our last update.
+ if ( !$alwaysGetResult ) {
+ if ( !self::checkHash( $file1, $file1hash ) && !self::checkHash( $file2, $file2hash ) ) {
+ self::myLog( "Skipping {$tag} since the files haven't changed since our last update", $verbose );
+ return array( null, null );
+ }
+ }
+
+ // Get the array with messages.
+ $messages1 = self::parsePHP( $file1contents, 'messages' );
+ if ( !is_array( $messages1 ) ) {
+ if ( strpos( $file1contents, '$messages' ) === false ) {
+ // No $messages array. This happens for some languages that only have a fallback
+ $messages1 = array();
+ } else {
+ // Broken file? Report and bail
+ self::myLog( "Failed to parse $file1" );
+ return array( null, null );
+ }
+ }
+
+ $messages2 = self::parsePHP( $file2contents, 'messages' );
+ if ( !is_array( $messages2 ) ) {
+ // Broken file? Report and bail
+ if ( strpos( $file2contents, '$messages' ) === false ) {
+ // No $messages array. This happens for some languages that only have a fallback
+ $messages2 = array();
+ } else {
+ self::myLog( "Failed to parse $file2" );
+ return array( null, null );
+ }
+ }
+
+ self::saveHash( $file1, $file1hash );
+ self::saveHash( $file2, $file2hash );
+
+ return array( $messages1, $messages2 );
+ }
+
+ /**
+ * Compare new and old messages lists, and optionally save the new
+ * messages if they've changed.
+ *
+ * @param $langcode String
+ * @param $old_messages Array
+ * @param $new_messages Array
+ * @param $verbose Boolean
+ * @param $forbiddenKeys Array
+ * @param $saveResults Boolean
+ *
+ * @return array|int
+ */
+ private static function compareLanguageArrays( $langcode, $old_messages, $new_messages, $verbose, $forbiddenKeys, $saveResults ) {
+ // Get the currently-cached messages, if any
+ $cur_messages = self::readFile( $langcode );
+
+ // Update the messages lists with the cached messages
+ $old_messages = array_merge( $old_messages, $cur_messages );
+ $new_messages = array_merge( $cur_messages, $new_messages );
+
+ // Use the old/cached version for any forbidden keys
+ if ( count( $forbiddenKeys ) ) {
+ $new_messages = array_merge(
+ array_diff_key( $new_messages, $forbiddenKeys ),
+ array_intersect_key( $old_messages, $forbiddenKeys )
+ );
+ }
+
+
+ if ( $saveResults ) {
+ // If anything has changed from the saved version, save the new version
+ if ( $new_messages != $cur_messages ) {
+ // Count added, updated, and deleted messages:
+ // diff( new, cur ) gives added + updated, and diff( cur, new )
+ // gives deleted + updated.
+ $changed = array_diff_assoc( $new_messages, $cur_messages ) +
+ array_diff_assoc( $cur_messages, $new_messages );
+ $updates = count( $changed );
+ self::myLog( "{$updates} messages updated for {$langcode}.", $verbose );
+ self::writeFile( $langcode, $new_messages );
+ } else {
+ $updates = 0;
+ }
+ return $updates;
+ } else {
+ // Find all deleted or changed messages
+ $changedStrings = array_diff_assoc( $old_messages, $new_messages );
+ return $changedStrings;
+ }
+ }
+
+ /**
+ * Returns an array containing the differences between the files.
+ *
+ * @param $newfile String
+ * @param $oldfile String
+ * @param $verbose Boolean
+ * @param $forbiddenKeys Array
+ * @param $alwaysGetResult Boolean
+ * @param $saveResults Boolean
+ *
+ * @return array|int
+ */
+ public static function compareFiles( $newfile, $oldfile, $verbose, array $forbiddenKeys = array(), $alwaysGetResult = true, $saveResults = false ) {
+ // Get the languagecode.
+ $langcode = Language::getCodeFromFileName( $newfile, 'Messages' );
+
+ list( $new_messages, $old_messages ) = self::loadFilesToCompare(
+ $langcode, $newfile, $oldfile, $verbose, $alwaysGetResult
+ );
+ if ( $new_messages === null || $old_messages === null ) {
+ return $saveResults ? 0 : array();
+ }
+
+ return self::compareLanguageArrays( $langcode, $old_messages, $new_messages, $verbose, $forbiddenKeys, $saveResults );
+ }
+
+ /**
+ *
+ * @param $extension String
+ * @param $newfile String
+ * @param $oldfile String
+ * @param $verbose Boolean
+ * @param $alwaysGetResult Boolean
+ * @param $saveResults Boolean
+ *
+ * @return Integer: the amount of updated messages
+ */
+ public static function compareExtensionFiles( $extension, $newfile, $oldfile, $verbose ) {
+ list( $new_messages, $old_messages ) = self::loadFilesToCompare(
+ $extension, $newfile, $oldfile, $verbose, false
+ );
+ if ( $new_messages === null || $old_messages === null ) {
+ return 0;
+ }
+
+ // Update counter.
+ $updates = 0;
+
+ if ( empty( $new_messages['en'] ) ) {
+ $new_messages['en'] = array();
+ }
+
+ if ( empty( $old_messages['en'] ) ) {
+ $old_messages['en'] = array();
+ }
+
+ // Find the changed english strings.
+ $forbiddenKeys = self::compareLanguageArrays( 'en', $old_messages['en'], $new_messages['en'], $verbose, array(), false );
+
+ // Do an update for each language.
+ foreach ( $new_messages as $language => $messages ) {
+ if ( $language == 'en' ) { // Skip english.
+ continue;
+ }
+
+ if ( !isset( $old_messages[$language] ) ) {
+ $old_messages[$language] = array();
+ }
+
+ $updates += self::compareLanguageArrays( $language, $old_messages[$language], $messages, $verbose, $forbiddenKeys, true );
+ }
+
+ // And log some stuff.
+ self::myLog( "Updated " . $updates . " messages for the '{$extension}' extension", $verbose );
+
+ return $updates;
+ }
+
+ /**
+ * Checks whether a messages file has a certain hash.
+ *
+ * TODO: Swap return values, this is insane
+ *
+ * @param $file string Filename
+ * @param $hash string Hash
+ *
+ * @return bool True if $file does NOT have hash $hash, false if it does
+ */
+ public static function checkHash( $file, $hash ) {
+ $hashes = self::readFile( 'hashes' );
+ return @$hashes[$file] !== $hash;
+ }
+
+ /**
+ * @param $file
+ * @param $hash
+ */
+ public static function saveHash( $file, $hash ) {
+ if ( is_null( self::$newHashes ) ) {
+ self::$newHashes = self::readFile( 'hashes' );
+ }
+
+ self::$newHashes[$file] = $hash;
+ }
+
+ public static function writeHashes() {
+ self::writeFile( 'hashes', self::$newHashes );
+ }
+
+ /**
+ * Logs a message.
+ *
+ * @param $log String
+ * @param bool $verbose
+ */
+ public static function myLog( $log, $verbose = true ) {
+ if ( !$verbose ) {
+ return;
+ }
+ if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
+ wfDebug( $log . "\n" );
+ } else {
+ print( $log . "\n" );
+ }
+ }
+
+ /**
+ * @param $php
+ * @param $varname
+ * @return bool|array
+ */
+ public static function parsePHP( $php, $varname ) {
+ try {
+ $reader = new QuickArrayReader("<?php $php");
+ return $reader->getVar( $varname );
+ } catch( Exception $e ) {
+ self::myLog( "Failed to read file: " . $e );
+ return false;
+ }
+ }
+
+ /**
+ * @param $lang
+ * @return string
+ * @throws MWException
+ */
+ public static function filename( $lang ) {
+ global $wgLocalisationUpdateDirectory, $wgCacheDirectory;
+
+ $dir = $wgLocalisationUpdateDirectory ?
+ $wgLocalisationUpdateDirectory :
+ $wgCacheDirectory;
+
+ if ( !$dir ) {
+ throw new MWException( 'No cache directory configured' );
+ }
+
+ return "$dir/l10nupdate-$lang.cache";
+ }
+
+ /**
+ * @param $lang
+ * @return mixed
+ */
+ public static function readFile( $lang ) {
+ if ( !isset( self::$filecache[$lang] ) ) {
+ $file = self::filename( $lang );
+ $contents = @file_get_contents( $file );
+
+ if ( $contents === false ) {
+ wfDebug( "Failed to read file '$file'\n" );
+ $retval = array();
+ } else {
+ $retval = unserialize( $contents );
+
+ if ( $retval === false ) {
+ wfDebug( "Corrupted data in file '$file'\n" );
+ $retval = array();
+ }
+ }
+ self::$filecache[$lang] = $retval;
+ }
+
+ return self::$filecache[$lang];
+ }
+
+ /**
+ * @param $lang
+ * @param $var
+ * @throws MWException
+ */
+ public static function writeFile( $lang, $var ) {
+ $file = self::filename( $lang );
+
+ if ( !@file_put_contents( $file, serialize( $var ) ) ) {
+ throw new MWException( "Failed to write to file '$file'" );
+ }
+
+ self::$filecache[$lang] = $var;
+ }
+
+}