summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/ExternalData
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
committerYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
commitfc7369835258467bf97eb64f184b93691f9a9fd5 (patch)
treedaabd60089d2dd76d9f5fb416b005fbe159c799d /www/wiki/extensions/ExternalData
first commit
Diffstat (limited to 'www/wiki/extensions/ExternalData')
-rw-r--r--www/wiki/extensions/ExternalData/COPYING339
-rw-r--r--www/wiki/extensions/ExternalData/ExternalData.hooks.php27
-rw-r--r--www/wiki/extensions/ExternalData/ExternalData.i18n.alias.php14
-rw-r--r--www/wiki/extensions/ExternalData/ExternalData.i18n.magic.php233
-rw-r--r--www/wiki/extensions/ExternalData/ExternalData.php64
-rw-r--r--www/wiki/extensions/ExternalData/Gruntfile.js21
-rw-r--r--www/wiki/extensions/ExternalData/README107
-rw-r--r--www/wiki/extensions/ExternalData/composer.json16
-rw-r--r--www/wiki/extensions/ExternalData/extension.json55
-rw-r--r--www/wiki/extensions/ExternalData/i18n/af.json12
-rw-r--r--www/wiki/extensions/ExternalData/i18n/aln.json17
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ar.json25
-rw-r--r--www/wiki/extensions/ExternalData/i18n/arz.json10
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ast.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ba.json23
-rw-r--r--www/wiki/extensions/ExternalData/i18n/be-tarask.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/br.json22
-rw-r--r--www/wiki/extensions/ExternalData/i18n/bs.json17
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ca.json13
-rw-r--r--www/wiki/extensions/ExternalData/i18n/cs.json25
-rw-r--r--www/wiki/extensions/ExternalData/i18n/cy.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/da.json10
-rw-r--r--www/wiki/extensions/ExternalData/i18n/de.json27
-rw-r--r--www/wiki/extensions/ExternalData/i18n/dsb.json18
-rw-r--r--www/wiki/extensions/ExternalData/i18n/el.json25
-rw-r--r--www/wiki/extensions/ExternalData/i18n/en.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/eo.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/es.json28
-rw-r--r--www/wiki/extensions/ExternalData/i18n/et.json10
-rw-r--r--www/wiki/extensions/ExternalData/i18n/eu.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/fa.json22
-rw-r--r--www/wiki/extensions/ExternalData/i18n/fi.json23
-rw-r--r--www/wiki/extensions/ExternalData/i18n/fr.json26
-rw-r--r--www/wiki/extensions/ExternalData/i18n/frp.json16
-rw-r--r--www/wiki/extensions/ExternalData/i18n/gl.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/gsw.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/gu.json11
-rw-r--r--www/wiki/extensions/ExternalData/i18n/he.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/hsb.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/hu.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/hy.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ia.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/id.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ilo.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/it.json22
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ja.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ka.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/km.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/kn.json15
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ko.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ksh.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/lb.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/lt.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/lv.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/mk.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ms.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/myv.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/nb.json25
-rw-r--r--www/wiki/extensions/ExternalData/i18n/nl.json23
-rw-r--r--www/wiki/extensions/ExternalData/i18n/nn.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/oc.json17
-rw-r--r--www/wiki/extensions/ExternalData/i18n/or.json10
-rw-r--r--www/wiki/extensions/ExternalData/i18n/pl.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/pms.json20
-rw-r--r--www/wiki/extensions/ExternalData/i18n/pt-br.json23
-rw-r--r--www/wiki/extensions/ExternalData/i18n/pt.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/qqq.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ro.json17
-rw-r--r--www/wiki/extensions/ExternalData/i18n/roa-tara.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ru.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sah.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sco.json21
-rw-r--r--www/wiki/extensions/ExternalData/i18n/si.json14
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sk.json17
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sr-ec.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sr-el.json18
-rw-r--r--www/wiki/extensions/ExternalData/i18n/sv.json27
-rw-r--r--www/wiki/extensions/ExternalData/i18n/ta.json12
-rw-r--r--www/wiki/extensions/ExternalData/i18n/te.json10
-rw-r--r--www/wiki/extensions/ExternalData/i18n/tl.json19
-rw-r--r--www/wiki/extensions/ExternalData/i18n/tr.json13
-rw-r--r--www/wiki/extensions/ExternalData/i18n/uk.json24
-rw-r--r--www/wiki/extensions/ExternalData/i18n/vep.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/vi.json11
-rw-r--r--www/wiki/extensions/ExternalData/i18n/yi.json8
-rw-r--r--www/wiki/extensions/ExternalData/i18n/zh-hans.json23
-rw-r--r--www/wiki/extensions/ExternalData/i18n/zh-hant.json22
-rw-r--r--www/wiki/extensions/ExternalData/includes/ED_GetData.php75
-rw-r--r--www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php663
-rw-r--r--www/wiki/extensions/ExternalData/includes/ED_Utils.php1071
-rw-r--r--www/wiki/extensions/ExternalData/package.json11
-rw-r--r--www/wiki/extensions/ExternalData/sql/ExternalData.sql9
92 files changed, 4126 insertions, 0 deletions
diff --git a/www/wiki/extensions/ExternalData/COPYING b/www/wiki/extensions/ExternalData/COPYING
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/www/wiki/extensions/ExternalData/ExternalData.hooks.php b/www/wiki/extensions/ExternalData/ExternalData.hooks.php
new file mode 100644
index 00000000..7bd254b7
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/ExternalData.hooks.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Hook functions for the External Data extension.
+ *
+ * @file
+ * @ingroup ExternalData
+ * @author Yaron Koren
+ */
+class ExternalDataHooks {
+
+ public static function registerParser( &$parser ) {
+ $parser->setFunctionHook( 'get_web_data', array( 'EDParserFunctions', 'doGetWebData' ) );
+ $parser->setFunctionHook( 'get_file_data', array( 'EDParserFunctions', 'doGetFileData' ) );
+ $parser->setFunctionHook( 'get_soap_data', array( 'EDParserFunctions', 'doGetSOAPData' ) );
+ $parser->setFunctionHook( 'get_ldap_data', array( 'EDParserFunctions', 'doGetLDAPData' ) );
+ $parser->setFunctionHook( 'get_db_data', array( 'EDParserFunctions', 'doGetDBData' ) );
+ $parser->setFunctionHook( 'external_value', array( 'EDParserFunctions', 'doExternalValue' ) );
+ $parser->setFunctionHook( 'for_external_table', array( 'EDParserFunctions', 'doForExternalTable' ) );
+ $parser->setFunctionHook( 'display_external_table', array( 'EDParserFunctions', 'doDisplayExternalTable' ) );
+ $parser->setFunctionHook( 'store_external_table', array( 'EDParserFunctions', 'doStoreExternalTable' ) );
+ $parser->setFunctionHook( 'clear_external_data', array( 'EDParserFunctions', 'doClearExternalData' ) );
+
+ return true; // always return true, in order not to stop MW's hook processing!
+ }
+
+}
diff --git a/www/wiki/extensions/ExternalData/ExternalData.i18n.alias.php b/www/wiki/extensions/ExternalData/ExternalData.i18n.alias.php
new file mode 100644
index 00000000..c440c345
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/ExternalData.i18n.alias.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Aliases for special pages
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = array(
+ 'GetData' => array( 'GetData' ),
+);
diff --git a/www/wiki/extensions/ExternalData/ExternalData.i18n.magic.php b/www/wiki/extensions/ExternalData/ExternalData.i18n.magic.php
new file mode 100644
index 00000000..ddca6441
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/ExternalData.i18n.magic.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ *
+ */
+
+$magicWords = array();
+
+/** English (English) */
+$magicWords['en'] = array(
+ 'get_web_data' => array( 0, 'get_web_data' ),
+ 'get_file_data' => array( 0, 'get_file_data' ),
+ 'get_soap_data' => array( 0, 'get_soap_data' ),
+ 'get_ldap_data' => array( 0, 'get_ldap_data' ),
+ 'get_db_data' => array( 0, 'get_db_data' ),
+ 'external_value' => array( 0, 'external_value' ),
+ 'for_external_table' => array( 0, 'for_external_table' ),
+ 'display_external_table' => array( 0, 'display_external_table' ),
+ 'store_external_table' => array( 0, 'store_external_table' ),
+ 'clear_external_data' => array( 0, 'clear_external_data' ),
+);
+
+/** Arabic (العربية) */
+$magicWords['ar'] = array(
+ 'get_web_data' => array( 0, 'عرض_بيانات_الويب' ),
+ 'get_file_data' => array( 0, 'عرض_بيانات_الملف' ),
+ 'get_soap_data' => array( 0, 'عرض_بيانات_السوب' ),
+ 'get_ldap_data' => array( 0, 'عرض_بيانات_لداب' ),
+ 'get_db_data' => array( 0, 'عرض_بيانات_قب' ),
+ 'external_value' => array( 0, 'قيمة_خارجية' ),
+ 'for_external_table' => array( 0, 'لجدول_خارجي' ),
+ 'display_external_table' => array( 0, 'عرض_جدول_خارجي' ),
+ 'store_external_table' => array( 0, 'تخزين_جدول_خارجي' ),
+ 'clear_external_data' => array( 0, 'إزالة_بيانات_خارجية' ),
+);
+
+/** Egyptian Arabic (مصرى) */
+$magicWords['arz'] = array(
+ 'get_web_data' => array( 0, 'عرض_بيانات_الويب' ),
+ 'get_ldap_data' => array( 0, 'عرض_بيانات_لداب' ),
+ 'get_db_data' => array( 0, 'عرض_بيانات_قب' ),
+ 'external_value' => array( 0, 'قيمه_خارجيه' ),
+ 'for_external_table' => array( 0, 'لجدول_خارجي' ),
+ 'display_external_table' => array( 0, 'عرض_جدول_خارجى' ),
+ 'store_external_table' => array( 0, 'تخزين_جدول_خارجى', 'تخزين_جدول_خارجي' ),
+ 'clear_external_data' => array( 0, 'مسح_بيانات_خارجيه' ),
+);
+
+/** Chechen (нохчийн) */
+$magicWords['ce'] = array(
+ 'get_ldap_data' => array( 0, 'схьаэца_хаамаш_ldap', 'получить_данные_ldap' ),
+ 'get_db_data' => array( 0, 'схьаэца_хаамаш_db', 'получить_данные_db' ),
+ 'external_value' => array( 0, 'архьара_дозалла', 'внешнее_значение' ),
+ 'for_external_table' => array( 0, 'оцу_архьара_тебалецlаш', 'для_внешней_таблицы' ),
+);
+
+/** German (Deutsch) */
+$magicWords['de'] = array(
+ 'get_web_data' => array( 0, 'hole_webdaten' ),
+ 'get_ldap_data' => array( 0, 'hole_ldapdaten' ),
+ 'get_db_data' => array( 0, 'hole_dbdaten' ),
+ 'external_value' => array( 0, 'externer_wert' ),
+ 'for_external_table' => array( 0, 'für_externe_tabelle' ),
+ 'display_external_table' => array( 0, 'zeige_externe_tabelle' ),
+ 'store_external_table' => array( 0, 'speichere_externe_tabelle' ),
+ 'clear_external_data' => array( 0, 'leere_externe_tabelle' ),
+);
+
+/** Greek (Ελληνικά) */
+$magicWords['el'] = array(
+ 'get_web_data' => array( 0, 'λήψη_δεδομένων_ιστού' ),
+ 'get_ldap_data' => array( 0, 'λήψη_δεδομένων_ldap' ),
+ 'get_db_data' => array( 0, 'λήψη_δεδομένων_βδ' ),
+ 'external_value' => array( 0, 'εξωτερική_τιμή' ),
+ 'for_external_table' => array( 0, 'για_εξωτερικό_πίνακα' ),
+ 'display_external_table' => array( 0, 'προβολή_εξωτερικού_πίνακα' ),
+ 'store_external_table' => array( 0, 'αποθήκευση_εξωτερικού_πίνακα' ),
+ 'clear_external_data' => array( 0, 'εκκαθάριση_εξωτερικών_δεδομένων' ),
+);
+
+/** Spanish (español) */
+$magicWords['es'] = array(
+ 'get_db_data' => array( 0, 'obtener_datos_db' ),
+ 'external_value' => array( 0, 'valor_externo' ),
+);
+
+/** Persian (فارسی) */
+$magicWords['fa'] = array(
+ 'get_web_data' => array( 0, 'گرفتن_داده_وب' ),
+);
+
+/** Western Frisian (Frysk) */
+$magicWords['fy'] = array(
+ 'external_value' => array( 0, 'eksterne_wearde' ),
+);
+
+/** Japanese (日本語) */
+$magicWords['ja'] = array(
+ 'get_ldap_data' => array( 0, 'ldapデータ取得' ),
+ 'get_db_data' => array( 0, 'dbデータ取得' ),
+ 'external_value' => array( 0, '外部値' ),
+ 'for_external_table' => array( 0, '外部テーブル用' ),
+ 'store_external_table' => array( 0, '外部テーブル格納' ),
+);
+
+/** Korean (한국어) */
+$magicWords['ko'] = array(
+ 'get_web_data' => array( 0, '웹_데이터_얻기' ),
+ 'get_file_data' => array( 0, '파일_데이터_얻기' ),
+ 'get_soap_data' => array( 0, 'soap_데이터_얻기' ),
+ 'get_ldap_data' => array( 0, 'ldap_데이터_얻기' ),
+ 'get_db_data' => array( 0, 'db_데이터_얻기' ),
+ 'external_value' => array( 0, '바깥_값' ),
+ 'for_external_table' => array( 0, '바깥_표_대해' ),
+ 'display_external_table' => array( 0, '바깥_표_보기' ),
+ 'store_external_table' => array( 0, '바깥_표_저장' ),
+ 'clear_external_data' => array( 0, '바깥_데이터_지우기' ),
+);
+
+/** Macedonian (македонски) */
+$magicWords['mk'] = array(
+ 'get_web_data' => array( 0, 'преземи_семрежни_податоци' ),
+ 'get_file_data' => array( 0, 'преземи_податотечни_податоци' ),
+ 'get_soap_data' => array( 0, 'преземи_soap_податоци' ),
+ 'get_ldap_data' => array( 0, 'преземи_ldap_податоци' ),
+ 'get_db_data' => array( 0, 'преземи_db_податоци' ),
+ 'external_value' => array( 0, 'надворешна_вредност' ),
+ 'for_external_table' => array( 0, 'за_надворешна_табела' ),
+ 'display_external_table' => array( 0, 'прикажи_надворешна_табела' ),
+ 'store_external_table' => array( 0, 'складирај_надворешна_табела' ),
+ 'clear_external_data' => array( 0, 'исчисти_надворешни_податоци' ),
+);
+
+/** Malayalam (മലയാളം) */
+$magicWords['ml'] = array(
+ 'get_web_data' => array( 0, 'വെബ്_വിവരങ്ങൾ_എടുക്കുക' ),
+ 'external_value' => array( 0, 'ബാഹ്യ_മൂല്യം' ),
+);
+
+/** Marathi (मराठी) */
+$magicWords['mr'] = array(
+ 'get_ldap_data' => array( 0, 'मिळवा__एलडॅप_विदा' ),
+ 'for_external_table' => array( 0, 'बाह्य_सारणी_करिता' ),
+);
+
+/** Low Saxon (Netherlands) (Nedersaksies) */
+$magicWords['nds-nl'] = array(
+ 'get_web_data' => array( 0, 'webgegevens_ophaolen' ),
+ 'get_ldap_data' => array( 0, 'ldap-gegevens_ophaolen' ),
+ 'get_db_data' => array( 0, 'db-gegevens_ophaolen' ),
+ 'external_value' => array( 0, 'externe_weerde' ),
+ 'for_external_table' => array( 0, 'veur_externe_tabel' ),
+ 'store_external_table' => array( 0, 'opslaon_externe_tabel' ),
+);
+
+/** Dutch (Nederlands) */
+$magicWords['nl'] = array(
+ 'get_web_data' => array( 0, 'webgegevens_ophalen' ),
+ 'get_file_data' => array( 0, 'bestandsgegevens_ophalen' ),
+ 'get_soap_data' => array( 0, 'soapgegevens_ophalen' ),
+ 'get_ldap_data' => array( 0, 'ldap_gegevens_ophalen' ),
+ 'get_db_data' => array( 0, 'db_gegevens_ophalen' ),
+ 'external_value' => array( 0, 'externe_waarde' ),
+ 'for_external_table' => array( 0, 'voor_externe_tabel' ),
+ 'display_external_table' => array( 0, 'externe_tabel_weergeven' ),
+ 'store_external_table' => array( 0, 'opslaan_externe_tabel' ),
+ 'clear_external_data' => array( 0, 'externe_gegevens_opschonen' ),
+);
+
+/** Russian (русский) */
+$magicWords['ru'] = array(
+ 'get_ldap_data' => array( 0, 'получить_данные_ldap' ),
+ 'get_db_data' => array( 0, 'получить_данные_db' ),
+ 'external_value' => array( 0, 'внешнее_значение' ),
+ 'for_external_table' => array( 0, 'для_внешней_таблицы' ),
+ 'store_external_table' => array( 0, 'внешняя_таблица_хранения' ),
+);
+
+/** Serbian (Cyrillic script) (српски (ћирилица)‎) */
+$magicWords['sr-ec'] = array(
+ 'get_web_data' => array( 0, 'добави_веб_податке' ),
+ 'get_ldap_data' => array( 0, 'добави_лдап_податке' ),
+ 'get_db_data' => array( 0, 'добави_податке_базе' ),
+ 'external_value' => array( 0, 'спољна_вредност' ),
+ 'for_external_table' => array( 0, 'за_спољну_табелу' ),
+ 'store_external_table' => array( 0, 'смести_спољну_табелу' ),
+);
+
+/** Serbian (Latin script) (srpski (latinica)‎) */
+$magicWords['sr-el'] = array(
+ 'get_web_data' => array( 0, 'dobavi_mrežne_podatke' ),
+ 'get_ldap_data' => array( 0, 'dobavi_ldap_podatke' ),
+ 'get_db_data' => array( 0, 'dobavi_podatke_baze' ),
+ 'external_value' => array( 0, 'spoljna_vrednost' ),
+ 'for_external_table' => array( 0, 'za_spoljnu_tabelu' ),
+ 'store_external_table' => array( 0, 'smesti_spoljnu_tabelu' ),
+ 'clear_external_data' => array( 0, 'očisti_spoljne_podatke' ),
+);
+
+/** Ukrainian (українська) */
+$magicWords['uk'] = array(
+ 'get_ldap_data' => array( 0, 'отримати_дані_ldap' ),
+ 'get_db_data' => array( 0, 'отримати_дані_db' ),
+ 'external_value' => array( 0, 'зовнішнє_значення' ),
+ 'for_external_table' => array( 0, 'для_зовнішньої_таблиці' ),
+ 'store_external_table' => array( 0, 'зовнішня_таблиця_зберігання' ),
+);
+
+/** Simplified Chinese (中文(简体)‎) */
+$magicWords['zh-hans'] = array(
+ 'get_web_data' => array( 0, '获取网络数据' ),
+ 'get_file_data' => array( 0, '获取文件数据' ),
+ 'get_soap_data' => array( 0, '获取soap数据' ),
+ 'get_ldap_data' => array( 0, '获取ldap数据' ),
+ 'get_db_data' => array( 0, '获取数据库数据' ),
+ 'external_value' => array( 0, '外部取值' ),
+ 'for_external_table' => array( 0, '用于外部表单' ),
+ 'display_external_table' => array( 0, '显示外部表单' ),
+ 'store_external_table' => array( 0, '存储外部表单' ),
+ 'clear_external_data' => array( 0, '清空外部数据' ),
+);
+
+/** Traditional Chinese (中文(繁體)‎) */
+$magicWords['zh-hant'] = array(
+ 'get_web_data' => array( 0, '取得網路數據' ),
+ 'get_file_data' => array( 0, '取得檔案數據' ),
+ 'get_soap_data' => array( 0, '取得soap數據' ),
+ 'get_ldap_data' => array( 0, '取得ldap數據' ),
+ 'get_db_data' => array( 0, '取得資料庫數據' ),
+ 'for_external_table' => array( 0, '用於外部表單' ),
+ 'display_external_table' => array( 0, '顯示外部表單' ),
+ 'store_external_table' => array( 0, '儲存外部表單' ),
+ 'clear_external_data' => array( 0, '清空外部數據' ),
+); \ No newline at end of file
diff --git a/www/wiki/extensions/ExternalData/ExternalData.php b/www/wiki/extensions/ExternalData/ExternalData.php
new file mode 100644
index 00000000..cad5ab7c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/ExternalData.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Initialization file for the External Data extension
+ *
+ * @file
+ * @ingroup ExternalData
+ * @author Yaron Koren
+ */
+
+if ( function_exists( 'wfLoadExtension' ) ) {
+ wfLoadExtension( 'ExternalData' );
+ // Keep i18n globals so mergeMessageFileList.php doesn't break
+ $wgMessagesDirs['ExternalData'] = __DIR__ . '/i18n';
+ $wgExtensionMessagesFiles['ExternalDataMagic'] = __DIR__ . '/ExternalData.i18n.magic.php';
+ /* wfWarn(
+ 'Deprecated PHP entry point used for External Data extension. Please use wfLoadExtension instead, ' .
+ 'see https://www.mediawiki.org/wiki/Extension_registration for more details.'
+ ); */
+ return;
+}
+
+if ( !defined( 'MEDIAWIKI' ) ) die();
+
+$wgExtensionCredits['parserhook'][] = array(
+ 'path' => __FILE__,
+ 'name' => 'External Data',
+ 'version' => '1.9',
+ 'author' => array( 'Yaron Koren', '...' ),
+ 'url' => 'https://www.mediawiki.org/wiki/Extension:External_Data',
+ 'descriptionmsg' => 'externaldata-desc',
+ 'license-name' => 'GPL-2.0-or-later'
+);
+
+$wgHooks['ParserFirstCallInit'][] = 'ExternalDataHooks::registerParser';
+$wgMessagesDirs['ExternalData'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['ExternalDataMagic'] = __DIR__ . '/ExternalData.i18n.magic.php';
+
+// Register all special pages and other classes
+$wgAutoloadClasses['ExternalDataHooks'] = __DIR__ . '/ExternalData.hooks.php';
+$wgAutoloadClasses['EDUtils'] = __DIR__ . '/includes/ED_Utils.php';
+$wgAutoloadClasses['EDParserFunctions'] = __DIR__ . '/includes/ED_ParserFunctions.php';
+$wgSpecialPages['GetData'] = 'EDGetData';
+$wgAutoloadClasses['EDGetData'] = __DIR__ . '/includes/ED_GetData.php';
+
+$edgValues = array();
+$edgStringReplacements = array();
+$edgCacheTable = null;
+$edgAllowSSL = true;
+$edgExternalValueVerbose = true;
+
+// Value is in seconds - set to one week
+$edgCacheExpireTime = 60 * 60 * 24 * 7;
+
+$edgDBServer = array();
+$edgDBServerType = array();
+$edgDBName = array();
+$edgDBUser = array();
+$edgDBPass = array();
+$edgDBDirectory = array();
+$edgDBFlags = array();
+$edgDBTablePrefix = array();
+
+$edgDirectoryPath = array();
+$edgFilePath = array();
diff --git a/www/wiki/extensions/ExternalData/Gruntfile.js b/www/wiki/extensions/ExternalData/Gruntfile.js
new file mode 100644
index 00000000..a45071e1
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/Gruntfile.js
@@ -0,0 +1,21 @@
+/*jshint node:true */
+module.exports = function ( grunt ) {
+ grunt.loadNpmTasks( 'grunt-jsonlint' );
+ grunt.loadNpmTasks( 'grunt-banana-checker' );
+
+ grunt.initConfig( {
+ banana: {
+ all: 'i18n/'
+ },
+ jsonlint: {
+ all: [
+ '**/*.json',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ }
+ } );
+
+ grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] );
+ grunt.registerTask( 'default', 'test' );
+};
diff --git a/www/wiki/extensions/ExternalData/README b/www/wiki/extensions/ExternalData/README
new file mode 100644
index 00000000..72d7a26c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/README
@@ -0,0 +1,107 @@
+External Data extension
+
+ Version 1.9
+ Yaron Koren and (many) others
+
+This is free software licensed under the GNU General Public License. Please
+see http://www.gnu.org/copyleft/gpl.html for further details, including the
+full text and terms of the license.
+
+== Overview ==
+
+External Data is an extension to MediaWiki that allows for retrieving data
+from various sources: external URLs, local wiki pages and files on the
+server (all in CSV, GFF, JSON and XML formats), plus database tables and
+LDAP servers.
+
+The extension defines the following parser functions: #get_web_data,
+#get_soap_data, #get_file_data, #get_db_data, #get_ldap_data,
+#external_value, #for_external_table, #display_external_table,
+#store_external_table and #clear_external_data. They are described below:
+
+* #get_web_data retrieves the data from a URL that holds CSV, GFF,
+JSON or XML, and assigns it to local variables or arrays.
+
+* #get_soap_data retrieves data from a URL via SOAP.
+
+* #get_file_data retrieves data from a local file, which can be in any of
+the same formats that #get_web_data handles.
+
+* #get_db_data retrieves data from a database, using (in most cases)
+SQL-like syntax, and assigns it to local variables or arrays.
+
+* #get_ldap_data retrieves data from an LDAP server and assigns it to
+local variables.
+
+* #external_value displays the value of any retrieved variable, or the
+first value if it's an array.
+
+* #for_external_table applies processing onto multiple rows retrieved by
+any of the #get_*_data functions
+
+* #display_external_table is like #for_external_table, but passes the
+values of each row to a template, which handles the formatting.
+
+* #store_external_table mimics a call to the Semantic MediaWiki
+extension's #subobject parser function onto each row retrieved by
+any of the #get_*_data functions, in order to store the entire array
+of data semantically.
+
+* #clear_external_data erases the current set of retrieved data.
+
+In addition, the extension defines a new special page, 'GetData', which
+exports selected rows from a wiki page that holds CSV data, in a format
+that is readable by #get_web_data.
+
+For more information, see the extension homepage at:
+http://www.mediawiki.org/wiki/Extension:External_Data
+
+== Requirements ==
+
+This version of the External Data extension requires MediaWiki 1.23 or
+higher.
+
+== Installation ==
+
+To install the extension, place the entire 'ExternalData' directory
+within your MediaWiki 'extensions' directory, then add the following
+line to your 'LocalSettings.php' file:
+
+ require_once( "$IP/extensions/ExternalData/ExternalData.php" );
+
+To cache the data from the URLs being accessed, you can call the contents
+of ExternalData.sql in your database, then add the following to
+LocalSettings.php:
+
+ $edgCacheTable = 'ed_url_cache';
+
+You should also add a line like the following, to set the expiration time
+of the cache, in seconds; this line will cache data for a week:
+
+ $edgCacheExpireTime = 7 * 24 * 60 * 60;
+
+You can also set for string replacements to be done on the URLs you call,
+for instance to hide API keys:
+
+ $edgStringReplacements['MY_API_KEY'] = 'abcd1324';
+
+You can create a "whitelist" to allow retrieval of data only from trusted
+sites, in the manner of MediaWiki's $wgAllowExternalImagesFrom - if you
+are hiding API keys, it is very much recommended to create such a
+whitelist, to prevent users from being able to discover their values:
+
+ $edgAllowExternalDataFrom = array('http://example.com/api');
+
+Finally, to use the database or LDAP retrieval capabilities, you need to
+set connection settings as well - see the online documentation for more
+information.
+
+== Contact ==
+
+Most comments, questions, suggestions and bug reports should be sent to
+the main MediaWiki mailing list:
+
+ https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
+
+If possible, please add "[ED]" at the beginning of the subject line, to
+clarify the subject matter.
diff --git a/www/wiki/extensions/ExternalData/composer.json b/www/wiki/extensions/ExternalData/composer.json
new file mode 100644
index 00000000..b071b83c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/composer.json
@@ -0,0 +1,16 @@
+{
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "1.0.0",
+ "jakub-onderka/php-console-highlighter": "0.3.2",
+ "mediawiki/minus-x": "0.3.1"
+ },
+ "scripts": {
+ "test": [
+ "parallel-lint . --exclude vendor --exclude node_modules",
+ "minus-x check ."
+ ],
+ "fix": [
+ "minus-x fix ."
+ ]
+ }
+}
diff --git a/www/wiki/extensions/ExternalData/extension.json b/www/wiki/extensions/ExternalData/extension.json
new file mode 100644
index 00000000..9bc364e5
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/extension.json
@@ -0,0 +1,55 @@
+{
+ "name": "External Data",
+ "version": "1.9",
+ "author": [
+ "Yaron Koren",
+ "..."
+ ],
+ "url": "https://www.mediawiki.org/wiki/Extension:External_Data",
+ "descriptionmsg": "externaldata-desc",
+ "license-name": "GPL-2.0-or-later",
+ "type": "parserhook",
+ "SpecialPages": {
+ "GetData": "EDGetData"
+ },
+ "MessagesDirs": {
+ "ExternalData": [
+ "i18n"
+ ]
+ },
+ "ExtensionMessagesFiles": {
+ "ExternalDataMagic": "ExternalData.i18n.magic.php",
+ "ExternalDataAlias": "ExternalData.i18n.alias.php"
+ },
+ "AutoloadClasses": {
+ "ExternalDataHooks": "ExternalData.hooks.php",
+ "EDUtils": "includes/ED_Utils.php",
+ "EDParserFunctions": "includes/ED_ParserFunctions.php",
+ "EDGetData": "includes/ED_GetData.php"
+ },
+ "Hooks": {
+ "ParserFirstCallInit": [
+ "ExternalDataHooks::registerParser"
+ ]
+ },
+ "config": {
+ "_prefix": "edg",
+ "Values": [],
+ "StringReplacements": [],
+ "CacheTable": null,
+ "AllowSSL": true,
+ "ExternalValueVerbose": true,
+ "CacheExpireTime": 604800,
+ "DBServer": [],
+ "DBServerType ": [],
+ "DBName": [],
+ "DBUser": [],
+ "DBPass": [],
+ "DBDirectory": [],
+ "DBFlags": [],
+ "DBTablePrefix": [],
+ "DirectoryPath": [],
+ "FilePath": []
+ },
+ "manifest_version": 1
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/af.json b/www/wiki/extensions/ExternalData/i18n/af.json
new file mode 100644
index 00000000..168afd48
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/af.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj"
+ ]
+ },
+ "getdata": "Kry data",
+ "externaldata-xml-error": "XML-fout: $1 op reël $2",
+ "externaldata-db-unknown-type": "Fout: onbekende databasistipe.",
+ "externaldata-db-could-not-connect": "Fout: kon nie 'n verbinding met databasis bewerkstellig nie.",
+ "externaldata-db-invalid-query": "Ongeldige navraag."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/aln.json b/www/wiki/extensions/ExternalData/i18n/aln.json
new file mode 100644
index 00000000..a5f23163
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/aln.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mdupont"
+ ]
+ },
+ "getdata": "Merr të dhëna",
+ "externaldata-desc": "Lejon retrieving të dhënat e strukturuar nga URL jashtme, bazat e të dhënave dhe burimet tjera",
+ "externaldata-ldap-unable-to-connect": "Në pamundësi për t'u lidhur tek $1",
+ "externaldata-xml-error": "XML error: $1 tek $2 linjë",
+ "externaldata-db-incomplete-information": "Gabim: informata jo të plota për këtë server të identitetit.",
+ "externaldata-db-could-not-get-url": "Nuk mund te merrni URL pasi $1 {{PLURAL:$1|provoni|përpiqet}}.",
+ "externaldata-db-unknown-type": "Gabim: Lloj i panjohur bazës së të dhënave.",
+ "externaldata-db-could-not-connect": "Gabim: Nuk mund të lidheni me bazën e të dhënave.",
+ "externaldata-db-no-return-values": "Gabim: Nuk ka kthim vlerat e caktuara.",
+ "externaldata-db-invalid-query": "pyetje e pavlefshme."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ar.json b/www/wiki/extensions/ExternalData/i18n/ar.json
new file mode 100644
index 00000000..fac90e73
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ar.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "DRIHEM",
+ "Imksa",
+ "Meno25",
+ "OsamaK",
+ "ديفيد"
+ ]
+ },
+ "getdata": "الحصول على البيانات",
+ "externaldata-desc": "يسمح باسترجاع البيانات الهيكلية من مسارات خارجية، قواعد البيانات ومصادر أخرى",
+ "externaldata-no-param-specified": "خطأ: لم يتم تحديد وسيط \"$1\".",
+ "externaldata-web-invalid-format": "إمتداد خاطئ: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "تعذّر الاتصال ب$1",
+ "externaldata-xml-error": "خطأ XML: $1 عند السطر $2",
+ "externaldata-invalid-json": "خطأ: جسون غير صالح.",
+ "externaldata-db-incomplete-information": "خطأ: معلومات غير كاملة عن هوية هذا الخادوم.",
+ "externaldata-db-could-not-get-url": "تعذّر الحصول على المسار بعد {{PLURAL:$1||محاولة واحدة|محاوتين|$1 محاولات|$1 محاولة }}.",
+ "externaldata-db-unknown-type": "خطأ: نوع قاعدة بيانات غير معروف.",
+ "externaldata-db-could-not-connect": "خطأ: تعذّر الاتصال بقاعدة البيانات.",
+ "externaldata-db-unknown-collection": "خطأ: مجموعة مونغو دي بي غير معروفة.",
+ "externaldata-db-no-return-values": "خطأ: لم تحدد أي قيم عائدة.",
+ "externaldata-db-invalid-query": "استعلام غير صالح."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/arz.json b/www/wiki/extensions/ExternalData/i18n/arz.json
new file mode 100644
index 00000000..7f3f8a12
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/arz.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dudi",
+ "Meno25"
+ ]
+ },
+ "getdata": "الحصول على البيانات",
+ "externaldata-desc": "بيسمح انك تجيب الداتا المتركبه من URLات برّانيه, و قواعد بيانات (databases) و مصادر تانيه"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ast.json b/www/wiki/extensions/ExternalData/i18n/ast.json
new file mode 100644
index 00000000..c5d1975c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ast.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "getdata": "Recuperar datos",
+ "externaldata-desc": "Permite recuperar datos estructuraos de direiciones URL, bases de datos y otres fontes esternes",
+ "externaldata-no-param-specified": "Error: Nun s'especificó dengún parámetru «$1».",
+ "externaldata-web-invalid-format": "Formatu inválidu: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Nun se pudo coneutar con $1",
+ "externaldata-xml-error": "Error XML: $1 na llinia $2",
+ "externaldata-invalid-json": "Error: JSON inválidu",
+ "externaldata-db-incomplete-information": "Error: Información incompleta pa esta ID de sirvidor.",
+ "externaldata-db-could-not-get-url": "Nun se pudo recuperar la URL dempués de $1 {{PLURAL:$1|intentu|intentos}}.",
+ "externaldata-db-unknown-type": "Error: Triba de base de datos desconocida.",
+ "externaldata-db-could-not-connect": "Error: Nun se pudo coneutar cola base de datos.",
+ "externaldata-db-unknown-collection": "Fallu: Coleición MongoDB desconocida.",
+ "externaldata-db-no-return-values": "Error: Nun s'especificaron valores de retornu.",
+ "externaldata-db-invalid-query": "Consulta inválida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ba.json b/www/wiki/extensions/ExternalData/i18n/ba.json
new file mode 100644
index 00000000..c5fd28e0
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ba.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Азат Хәлилов",
+ "Айбикә",
+ "Ләйсән"
+ ]
+ },
+ "getdata": "Мәғлүмәттәр алырға",
+ "externaldata-desc": "Тышҡы адрестарҙан, мәғлүмәттәр базаһынан һәм башҡа сығанаҡтарҙан структураға һалынған мәғлүмәттәр алырға ярҙам итә",
+ "externaldata-no-param-specified": "Хата: «$1» параметры күрһәтелмәгән.",
+ "externaldata-web-invalid-format": "Рөхсәт ителмәгән формат: \"$1\"",
+ "externaldata-ldap-unable-to-connect": " $1 тоташып булмай.",
+ "externaldata-xml-error": "XML хата. $1 $2 юлында",
+ "externaldata-invalid-json": "Хата: Рөхсәт ителмәгән JSON",
+ "externaldata-db-incomplete-information": "Хата: Был ID сервер өсөн мәғлүмәт тулы түгел.",
+ "externaldata-db-could-not-get-url": "$1 {{PLURAL:$1|мөмкинлектән}} һуң URL алып булманы.",
+ "externaldata-db-unknown-type": "ХАТА: Билдәһеҙ мәғлүмәт базаһы.",
+ "externaldata-db-could-not-connect": "ХАТА: Мәғлүмәт базаһы менән бәйләнеш булдырып булмай.",
+ "externaldata-db-unknown-collection": "Хата: Билдәһеҙ коллекция MongoDB.",
+ "externaldata-db-no-return-values": "Хата: Кире ҡайтара торған билдәләр күрһәтелмәгән",
+ "externaldata-db-invalid-query": "Хаталы һорау"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/be-tarask.json b/www/wiki/extensions/ExternalData/i18n/be-tarask.json
new file mode 100644
index 00000000..94add57a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/be-tarask.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Wizardist",
+ "Red Winged Duck"
+ ]
+ },
+ "getdata": "Атрымаць зьвесткі",
+ "externaldata-desc": "Дазваляе атрымліваць структураваныя зьвесткі з вонкавых URL-адрасоў, базаў зьвестак і іншых крыніц",
+ "externaldata-no-param-specified": "Памылка: парамэтар «$1» ня вызначаны.",
+ "externaldata-web-invalid-format": "Няслушны фармат: «$1»",
+ "externaldata-ldap-unable-to-connect": "Немагчыма далучыцца да $1",
+ "externaldata-xml-error": "Памылка XML: $1 у радку $2",
+ "externaldata-invalid-json": "Памылка: няправільны JSON.",
+ "externaldata-db-incomplete-information": "Памылка: Няпоўная інфармацыя для гэтага ідэнтыфікатара сэрвэра.",
+ "externaldata-db-could-not-get-url": "Немагчыма атрымаць URL-адрас пасьля $1 {{PLURAL:$1|спробы|спробаў|спробаў}}.",
+ "externaldata-db-unknown-type": "Памылка: Невядомы тып базы зьвестак.",
+ "externaldata-db-could-not-connect": "Памылка: Немагчыма далучыцца да базы зьвестак.",
+ "externaldata-db-unknown-collection": "Памылка: невядомая калецыя MongoDB.",
+ "externaldata-db-no-return-values": "Памылка: Не пазначаныя выніковыя значэньні.",
+ "externaldata-db-invalid-query": "Няслушны запыт."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/br.json b/www/wiki/extensions/ExternalData/i18n/br.json
new file mode 100644
index 00000000..8835619a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/br.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fohanno",
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "getdata": "Tapout roadennoù",
+ "externaldata-desc": "Talvezout a ra da adtapout roadennoù frammet adalek URLoù diavaez, diazoù titouroù ha mammennoù all.",
+ "externaldata-no-param-specified": "Fazi : an arventenn \"$1\" n'eo ket bet diferet.",
+ "externaldata-web-invalid-format": "Furmad direizh : \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Ne c'haller ket kevreañ ouzh $1",
+ "externaldata-xml-error": "Fazi XML : $1 el linenn $2",
+ "externaldata-invalid-json": "Fazi : JSON direizh",
+ "externaldata-db-incomplete-information": "Fazi : Titouroù diglok evit an ID servijer-mañ.",
+ "externaldata-db-could-not-get-url": "Dibosupl eo tapout an URL goude $1 {{PLURAL:$1|taol-esae|taol-esae}}.",
+ "externaldata-db-unknown-type": "Fazi : Seurt diaz roadennoù dianav",
+ "externaldata-db-could-not-connect": "Fazi : Ne c'haller ket kevreañ ouzh an diaz roadennoù.",
+ "externaldata-db-no-return-values": "Fazi : N'eus bet resisaet talvoud distro ebet.",
+ "externaldata-db-invalid-query": "Reked direizh."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/bs.json b/www/wiki/extensions/ExternalData/i18n/bs.json
new file mode 100644
index 00000000..61bb9373
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/bs.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator"
+ ]
+ },
+ "getdata": "Uzmi podatke",
+ "externaldata-desc": "Omogućuje za preuzimanje strukturnih podataka iz vanjskih URLova, baza podataka i drugih izvora",
+ "externaldata-ldap-unable-to-connect": "Ne može se spojiti na $1",
+ "externaldata-xml-error": "XML greška: $1 na liniji $2",
+ "externaldata-db-incomplete-information": "Greška: Nepotpune informacije za ovaj ID servera.",
+ "externaldata-db-could-not-get-url": "Nije pronađen URL nakon $1 {{PLURAL:$1|pokušaja|pokušaja}}.",
+ "externaldata-db-unknown-type": "Greška: Nepoznat tip baze podataka.",
+ "externaldata-db-could-not-connect": "Greška: Ne može se spojiti na bazu podataka.",
+ "externaldata-db-no-return-values": "Greška: Nije navedena povratna vrijednost.",
+ "externaldata-db-invalid-query": "Nevaljan upit."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ca.json b/www/wiki/extensions/ExternalData/i18n/ca.json
new file mode 100644
index 00000000..731e67ec
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ca.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Paucabot",
+ "Solde"
+ ]
+ },
+ "getdata": "Obtenir dades",
+ "externaldata-xml-error": "Error XML: $1 a la línia $2",
+ "externaldata-db-unknown-type": "Error: Tipus de base de dades desconegut.",
+ "externaldata-db-could-not-connect": "Error: No s'ha pogut connectar a la base de dades.",
+ "externaldata-db-invalid-query": "Consulta no vàlida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/cs.json b/www/wiki/extensions/ExternalData/i18n/cs.json
new file mode 100644
index 00000000..3b155ea8
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/cs.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jkjk",
+ "Matěj Grabovský",
+ "Mormegil",
+ "Reaperman",
+ "XenoPheX"
+ ]
+ },
+ "getdata": "Získat data",
+ "externaldata-desc": "Umožňuje získávání strukturovaných dat z externích webových stránek, databází a jiných zdrojů",
+ "externaldata-no-param-specified": "Chyba: Nebyl zadán parametr „$1“.",
+ "externaldata-web-invalid-format": "Neplatný formát: „$1“",
+ "externaldata-ldap-unable-to-connect": "Nepodařilo se spojit s $1",
+ "externaldata-xml-error": "Chyba XML: $1 na řádku $2",
+ "externaldata-invalid-json": "Chyba: Neplatný JSON.",
+ "externaldata-db-incomplete-information": "Chyba: Nekompletní informace pro toto ID databáze.",
+ "externaldata-db-could-not-get-url": "Nepodařilo se získat URL po $1 {{PLURAL:$1|pokusu|pokusech}}.",
+ "externaldata-db-unknown-type": "Chyba: Neznámý typ databáze.",
+ "externaldata-db-could-not-connect": "Chyba: Nepodařilo se připojit k databázi.",
+ "externaldata-db-unknown-collection": "Chyba: Neznámá kolekce MongoDB.",
+ "externaldata-db-no-return-values": "Chyba: Nebyly zadány návratové hodnoty.",
+ "externaldata-db-invalid-query": "Neplatný požadavek."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/cy.json b/www/wiki/extensions/ExternalData/i18n/cy.json
new file mode 100644
index 00000000..b7167b98
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/cy.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr"
+ ]
+ },
+ "getdata": "Nôl y data",
+ "externaldata-desc": "Yn galluogi nôl data strwythuredig o ffynnonellau allanol megis URLs a chronfeydd data",
+ "externaldata-no-param-specified": "Gwall: Ni phenwyd y paramedr \"$1\".",
+ "externaldata-web-invalid-format": "Fformat annilys: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Ni lwyddwyd i gysylltu â $1",
+ "externaldata-xml-error": "Gwall XML: $1 yn y llinell $2",
+ "externaldata-invalid-json": "Gwall: JSON annilys.",
+ "externaldata-db-incomplete-information": "Gwall: Gwybodaeth anghyflawn i ID y gronfa ddata.",
+ "externaldata-db-could-not-get-url": "Ni chafwyd hyd i'r URL o geisio {{PLURAL:$1||unwaith|dwywaith|teirgwaith|$1 gwaith}}.",
+ "externaldata-db-unknown-type": "Gwall: Math anhysbys i'r gronfa ddata.",
+ "externaldata-db-could-not-connect": "Gwall: Ni lwyddwyd i gysylltu â'r gronfa ddata.",
+ "externaldata-db-unknown-collection": "Gwall: Casgliad MongoDB anhysbys.",
+ "externaldata-db-no-return-values": "Gwall: Ni phenwyd unrhyw werthoedd i'w nôl.",
+ "externaldata-db-invalid-query": "Gofyniad annilys."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/da.json b/www/wiki/extensions/ExternalData/i18n/da.json
new file mode 100644
index 00000000..5f08159c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/da.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tjernobyl",
+ "Saederup92"
+ ]
+ },
+ "externaldata-invalid-json": "Fejl: Ugyldigt JSON.",
+ "externaldata-db-invalid-query": "Ugyldig forespørgsel."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/de.json b/www/wiki/extensions/ExternalData/i18n/de.json
new file mode 100644
index 00000000..a15fd009
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/de.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Imre",
+ "Kghbln",
+ "MF-Warburg",
+ "Merlissimo",
+ "Metalhead64",
+ "Purodha",
+ "Umherirrender"
+ ]
+ },
+ "getdata": "Daten holen",
+ "externaldata-desc": "Ermöglicht das Abrufen strukturierter Daten von externen URLs, Datenbanken und anderen Quellen",
+ "externaldata-no-param-specified": "Fehler: Kein Parameter „$1“ angegeben.",
+ "externaldata-web-invalid-format": "Ungültiges Format: „$1“",
+ "externaldata-ldap-unable-to-connect": "Es konnte keine Verbindung zu $1 hergestellt werden",
+ "externaldata-xml-error": "XML-Fehler: $1 in Zeile $2",
+ "externaldata-invalid-json": "Fehler: Ungültiges JSON",
+ "externaldata-db-incomplete-information": "Fehler: Es liegen nur unvollständige Informationen für diese Serverkennung vor.",
+ "externaldata-db-could-not-get-url": "Die URL konnte mit {{PLURAL:$1|einem Versuch|$1 Versuchen}} nicht abgerufen werden.",
+ "externaldata-db-unknown-type": "Fehler: Es handelt sich um einen unbekannten Datenbanktyp.",
+ "externaldata-db-could-not-connect": "Fehler: Es konnte keine Verbindung zur Datenbank hergestellt werden.",
+ "externaldata-db-unknown-collection": "Fehler: Unbekannte MongoDB-Sammlung",
+ "externaldata-db-no-return-values": "Fehler: Es wurden keine Rückgabewerte festgelegt.",
+ "externaldata-db-invalid-query": "Ungültige Abfrage."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/dsb.json b/www/wiki/extensions/ExternalData/i18n/dsb.json
new file mode 100644
index 00000000..a72319d9
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/dsb.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "getdata": "Daty wobstaraś",
+ "externaldata-desc": "Zmóžnja wótwołowanje strukturěrowanych datow z eksternych URL, datowych bankow a drugich žrědłow",
+ "externaldata-web-invalid-format": "Njepłaśiwy format: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Njemóžno z $1 zwězaś",
+ "externaldata-xml-error": "Zmólka XML: $1 na smužce $2",
+ "externaldata-db-incomplete-information": "'''Zmólka: Njedopołne informacije za toś ten serwerowy ID.'''",
+ "externaldata-db-could-not-get-url": "Njemóžno URL pó $1 {{PLURAL:$1|wopyśe|wopytoma|wopytach|wopytach}} dostaś.",
+ "externaldata-db-unknown-type": "'''Zmólka: Njeznata datowa banka.'''",
+ "externaldata-db-could-not-connect": "'''Zmólka: Njemóžno z datoweju banku zwězaś.'''",
+ "externaldata-db-no-return-values": "'''Zmólka: Žedne gódnoty slědkdaśa pódane.'''",
+ "externaldata-db-invalid-query": "Njepłaśiwe napšašowanje."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/el.json b/www/wiki/extensions/ExternalData/i18n/el.json
new file mode 100644
index 00000000..b18947dc
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/el.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dead3y3",
+ "Glavkos",
+ "Omnipaedista",
+ "Protnet",
+ "ZaDiak"
+ ]
+ },
+ "getdata": "Λήψη δεδομένων",
+ "externaldata-desc": "Επιτρέπει την ανάκτηση δομημένων δεδομένων από εξωτερικά URL, βάσεις δεδομένων και άλλες πηγές",
+ "externaldata-no-param-specified": "Σφάλμα: Δεν καθορίστηκε παράμετρος «$1».",
+ "externaldata-web-invalid-format": "Μη έγκυρη μορφή: «$1».",
+ "externaldata-ldap-unable-to-connect": "Δεν είναι δυνατή η σύνδεση με $1.",
+ "externaldata-xml-error": "Σφάλμα XML: $1 στη γραμμή $2",
+ "externaldata-invalid-json": "Σφάλμα: Μη έγκυρο JSON.",
+ "externaldata-db-incomplete-information": "Σφάλμα: Ελλιπείς πληροφορίες για αυτό το αναγνωριστικό βάσης δεδομένων.",
+ "externaldata-db-could-not-get-url": "Δεν ήταν δυνατή η λήψη του URL μετά από $1 {{PLURAL:$1|προσπάθεια|προσπάθειες}}.",
+ "externaldata-db-unknown-type": "Σφάλμα: Άγνωστος τύπος βάσης δεδομένων.",
+ "externaldata-db-could-not-connect": "Σφάλμα: Αδυναμία σύνδεσης στη βάση δεδομένων.",
+ "externaldata-db-unknown-collection": "Σφάλα: Άγνωστη συλλογή MongoDB.",
+ "externaldata-db-no-return-values": "Σφάλμα: Δεν καθορίστηκαν τιμές επιστροφής.",
+ "externaldata-db-invalid-query": "Μη έγκυρο ερώτημα."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/en.json b/www/wiki/extensions/ExternalData/i18n/en.json
new file mode 100644
index 00000000..081c7f0e
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/en.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yaron Koren"
+ ]
+ },
+ "getdata": "Get data",
+ "externaldata-desc": "Allows for retrieving structured data from external URLs, databases and other sources",
+ "externaldata-no-param-specified": "Error: No \"$1\" parameter specified.",
+ "externaldata-web-invalid-format": "Invalid format: \"$1\".",
+ "externaldata-ldap-unable-to-connect": "Unable to connect to $1.",
+ "externaldata-xml-error": "XML error: $1 at line $2.",
+ "externaldata-invalid-json": "Error: Invalid JSON.",
+ "externaldata-db-incomplete-information": "Error: Incomplete information for this database ID.",
+ "externaldata-db-could-not-get-url": "Could not get URL after $1 {{PLURAL:$1|try|tries}}.",
+ "externaldata-db-unknown-type": "Error: Unknown database type.",
+ "externaldata-db-could-not-connect": "Error: Could not connect to database.",
+ "externaldata-db-unknown-collection": "Error: Unknown MongoDB collection.",
+ "externaldata-db-no-return-values": "Error: No return values specified.",
+ "externaldata-db-invalid-query": "Invalid query."
+} \ No newline at end of file
diff --git a/www/wiki/extensions/ExternalData/i18n/eo.json b/www/wiki/extensions/ExternalData/i18n/eo.json
new file mode 100644
index 00000000..14df5915
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/eo.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yekrats"
+ ]
+ },
+ "externaldata-db-invalid-query": "Malvalida serĉomendo."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/es.json b/www/wiki/extensions/ExternalData/i18n/es.json
new file mode 100644
index 00000000..f150efc1
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/es.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin",
+ "Crazymadlover",
+ "Fitoschido",
+ "Imre",
+ "Manuelt15",
+ "Sanbec",
+ "Translationista",
+ "Indiralena"
+ ]
+ },
+ "getdata": "Obtener datos",
+ "externaldata-desc": "Permite la recuperación de datos estructurados a partir de direcciones URL externas, bases de datos y otras fuentes",
+ "externaldata-no-param-specified": "Error: No se ha especificado el parámetro «$1».",
+ "externaldata-web-invalid-format": "El formato «$1» no es válido.",
+ "externaldata-ldap-unable-to-connect": "No se pudo conectar con $1",
+ "externaldata-xml-error": "Error XML: $1 en línea $2",
+ "externaldata-invalid-json": "Error: JSON no válido",
+ "externaldata-db-incomplete-information": "Error: Información incompleta para este ID de servidor.",
+ "externaldata-db-could-not-get-url": "No se pudo obtener la URL después de $1 {{PLURAL:$1|intento|intentos}}.",
+ "externaldata-db-unknown-type": "Error: Tipo de base de datos desconocido.",
+ "externaldata-db-could-not-connect": "Error: No se pudo lograr conexión con la base de datos.",
+ "externaldata-db-unknown-collection": "Error: colección de MongoDB desconocida.",
+ "externaldata-db-no-return-values": "Error: No se ha especificado valores de retorno.",
+ "externaldata-db-invalid-query": "Consulta no válida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/et.json b/www/wiki/extensions/ExternalData/i18n/et.json
new file mode 100644
index 00000000..9e76879d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/et.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pikne"
+ ]
+ },
+ "externaldata-db-unknown-type": "Tõrge: Tundmatu andmebaasi tüüp.",
+ "externaldata-db-could-not-connect": "Tõrge: Andmebaasiga ei saa ühendust.",
+ "externaldata-db-invalid-query": "Vigane päring."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/eu.json b/www/wiki/extensions/ExternalData/i18n/eu.json
new file mode 100644
index 00000000..094369b6
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/eu.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kobazulo"
+ ]
+ },
+ "getdata": "Datuak eskuratu"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/fa.json b/www/wiki/extensions/ExternalData/i18n/fa.json
new file mode 100644
index 00000000..b89b79b0
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/fa.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392",
+ "Mjbmr"
+ ]
+ },
+ "getdata": "دریافت اطلاعات",
+ "externaldata-desc": "اجازه برای بازیابی اطلاعات ساخته شده از یوآرال‌های خارجی، پایگاه‌های اطلاعاتی و دیگر منابع",
+ "externaldata-no-param-specified": "خطا: هیچ پارامتر \"$1\" تعیین نشده‌است.",
+ "externaldata-web-invalid-format": "فرمت نامعتبر: \"$1\".",
+ "externaldata-ldap-unable-to-connect": "قادر نبودن اتصال به $1",
+ "externaldata-xml-error": "خطای ایکس‌ام‌ال: $1 در خط $2",
+ "externaldata-invalid-json": "خطا: جی‌سون نامعتبر.",
+ "externaldata-db-incomplete-information": "خطا: اطلاعات ناقص برای شناسهٔ این پایگاه اطلاعاتی.",
+ "externaldata-db-could-not-get-url": "پس از $1 {{PLURAL:$1|try|tries}}، یوآرال نتوانست دریافت شود.",
+ "externaldata-db-unknown-type": "خطا: نوع پایگاه اطلاعاتی ناشناخته.",
+ "externaldata-db-could-not-connect": "خطا: نتوانست به پایگاه اطلاعاتی متصل شود.",
+ "externaldata-db-unknown-collection": "خطا: مجموعهٔ مونگودی‌بی ناشناخته.",
+ "externaldata-db-no-return-values": "خطا: بدون بازگشت ارزش‌های تعیین شده.",
+ "externaldata-db-invalid-query": "سوال نامعتبر."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/fi.json b/www/wiki/extensions/ExternalData/i18n/fi.json
new file mode 100644
index 00000000..ca77dcb6
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/fi.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Centerlink",
+ "Crt",
+ "Nedergard",
+ "Silvonen",
+ "Str4nd"
+ ]
+ },
+ "getdata": "Hae data",
+ "externaldata-desc": "Mahdollistaa muotoillun datan noutamisen ulkoisista verkko-osoitteista, tietokannoista ja muista lähteistä.",
+ "externaldata-web-invalid-format": "Virheellinen muoto: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Ei voitu yhdistää palvelimelle $1",
+ "externaldata-xml-error": "XML-virhe: $1 rivillä $2",
+ "externaldata-db-incomplete-information": "Virhe: Vaillinaiset tiedot tälle palvelintunnukselle.",
+ "externaldata-db-could-not-get-url": "Ei voitu hakea verkko-osoitetta $1 {{PLURAL:$1|yrityksen|yrityksen}} jälkeen.",
+ "externaldata-db-unknown-type": "Virhe: Tuntematon tietokantatyyppi.",
+ "externaldata-db-could-not-connect": "Virhe: Ei yhteyttä tietokantaan.",
+ "externaldata-db-unknown-collection": "Virhe: Tuntematon MongoDB-kokoelma.",
+ "externaldata-db-no-return-values": "Virhe: Paluuarvoja ei ole annettu.",
+ "externaldata-db-invalid-query": "Virheellinen kysely."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/fr.json b/www/wiki/extensions/ExternalData/i18n/fr.json
new file mode 100644
index 00000000..552b612f
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/fr.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Crochet.david",
+ "Gomoko",
+ "IAlex",
+ "McDutchie",
+ "PieRRoMaN",
+ "Shirayuki"
+ ]
+ },
+ "getdata": "Obtenir des données",
+ "externaldata-desc": "Permet de récupérer des données structurées à partir d'URL externes, de bases de données et d'autres sources",
+ "externaldata-no-param-specified": "Erreur : Aucun paramètre « $1 » spécifié.",
+ "externaldata-web-invalid-format": "Format invalide: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Impossible de se connecter à $1",
+ "externaldata-xml-error": "Erreur XML : $1 à la ligne $2",
+ "externaldata-invalid-json": "Erreur : JSON non valide",
+ "externaldata-db-incomplete-information": "Erreur : Informations incomplètes pour cet identifiant de serveur.",
+ "externaldata-db-could-not-get-url": "Impossible d'obtenir l'URL après $1 {{PLURAL:$1|essais}}.",
+ "externaldata-db-unknown-type": "ERREUR: Type de base de données inconnu.",
+ "externaldata-db-could-not-connect": "Erreur : Impossible de se connecter à la base de données.",
+ "externaldata-db-unknown-collection": "Erreur: Collection MongoDB inconnue.",
+ "externaldata-db-no-return-values": "Erreur : Aucune valeur de retour n'a été spécifiée.",
+ "externaldata-db-invalid-query": "Requête invalide."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/frp.json b/www/wiki/extensions/ExternalData/i18n/frp.json
new file mode 100644
index 00000000..cf3b5aaf
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/frp.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "getdata": "Avêr des balyês",
+ "externaldata-web-invalid-format": "Format envalido : « $1 »",
+ "externaldata-ldap-unable-to-connect": "Empossiblo de sè branchiér a $1",
+ "externaldata-xml-error": "Èrror XML : $1 a la legne $2",
+ "externaldata-db-could-not-get-url": "Empossiblo d’avêr l’URL aprés $1 tentativ{{PLURAL:$1|a|es}}.",
+ "externaldata-db-unknown-type": "Èrror : tipo de bâsa de balyês encognu.",
+ "externaldata-db-could-not-connect": "Èrror : empossiblo de sè branchiér a la bâsa de balyês.",
+ "externaldata-db-no-return-values": "Èrror : niona valor de retôrn at étâ spècefiâ.",
+ "externaldata-db-invalid-query": "Requéta envalida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/gl.json b/www/wiki/extensions/ExternalData/i18n/gl.json
new file mode 100644
index 00000000..cfabd336
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/gl.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño"
+ ]
+ },
+ "getdata": "Obter os datos",
+ "externaldata-desc": "Permite a recuperación de datos estruturados a partir de enderezos URL externos, bases de datos e outras fontes",
+ "externaldata-no-param-specified": "Erro: Non se especificou ningún parámetro \"$1\".",
+ "externaldata-web-invalid-format": "Formato incorrecto: \"$1\".",
+ "externaldata-ldap-unable-to-connect": "Non se pode conectar con $1.",
+ "externaldata-xml-error": "Erro XML: $1 na liña $2.",
+ "externaldata-invalid-json": "Erro: JSON non válido.",
+ "externaldata-db-incomplete-information": "Erro: Información incompleta para este ID de servidor.",
+ "externaldata-db-could-not-get-url": "Non se puido obter o enderezo URL despois de $1 {{PLURAL:$1|intento|intentos}}.",
+ "externaldata-db-unknown-type": "Erro: Tipo de base de datos descoñecido.",
+ "externaldata-db-could-not-connect": "Erro: Non se puido conectar coa base de datos.",
+ "externaldata-db-unknown-collection": "Erro: Colección MongoDB descoñecida.",
+ "externaldata-db-no-return-values": "Erro: Non se especificou ningún valor de retorno.",
+ "externaldata-db-invalid-query": "A consulta non é válida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/gsw.json b/www/wiki/extensions/ExternalData/i18n/gsw.json
new file mode 100644
index 00000000..66f7cc1a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/gsw.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Chlämens",
+ "Als-Holder"
+ ]
+ },
+ "getdata": "Date hole",
+ "externaldata-desc": "Erlaubt strukturierti Daten abzruefe vu extärne URL un andre Quälle",
+ "externaldata-web-invalid-format": "Ungültigs Format: „$1“",
+ "externaldata-ldap-unable-to-connect": "Cha kei Verbindig härstellen zue $1",
+ "externaldata-xml-error": "XML-Fähler: $1 in dr Zyyle $2",
+ "externaldata-db-incomplete-information": "Fähler: Nit vollständigi Information fir die Server-ID.",
+ "externaldata-db-could-not-get-url": "Cha d URL nit finde no $1 {{PLURAL:$1|Versuech|Versuech}}.",
+ "externaldata-db-unknown-type": "Fähler: Nit bekannte Datebanktyp.",
+ "externaldata-db-could-not-connect": "Fähler: Cha kei Verbindig härstelle zue dr Datebank.",
+ "externaldata-db-no-return-values": "Fähler: Kei Ruckgabewärt spezifiziert.",
+ "externaldata-db-invalid-query": "Nit giltigi Umfrog."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/gu.json b/www/wiki/extensions/ExternalData/i18n/gu.json
new file mode 100644
index 00000000..20c6124d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/gu.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ashok modhvadia",
+ "KartikMistry"
+ ]
+ },
+ "getdata": "માહિતી પ્રાપ્ત કરો",
+ "externaldata-desc": "બાહ્ય કડીઓ, ડેટાબેઝ અને અન્ય સ્રોતોમાંથી માહિતીની પુન:પ્રાપ્તિની છુટ",
+ "externaldata-invalid-json": "ક્ષતિ: અયોગ્ય JSON"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/he.json b/www/wiki/extensions/ExternalData/i18n/he.json
new file mode 100644
index 00000000..3c4b85fb
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/he.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Rotemliss",
+ "YaronSh",
+ "Yona b"
+ ]
+ },
+ "getdata": "קבלת נתונים",
+ "externaldata-desc": "אפשרות לקבלת נתונים במבנים מכתובות חיצוניות, מסדי נתונים ומקורות אחרים",
+ "externaldata-no-param-specified": "שגיאה: נבחר פרמטר \"$1\" מסוים.",
+ "externaldata-web-invalid-format": "תסדיר בלתי־תקין: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "לא ניתן להתחבר ל־$1",
+ "externaldata-xml-error": "שגיאת XML: $1 בשורה $2",
+ "externaldata-invalid-json": "שגיאה: JSON בלתי־תקין",
+ "externaldata-db-incomplete-information": "שגיאה: יש רק מידע חלקי על מספר השרת הזה.",
+ "externaldata-db-could-not-get-url": "לא ניתן לקבל את כתובת ה־URL לאחר {{PLURAL:$1|נסיון אחד|$1 נסיונות}}.",
+ "externaldata-db-unknown-type": "שגיאה: סוג מסד הנתונים אינו מוכר.",
+ "externaldata-db-could-not-connect": "שגיאה: לא ניתן להתחבר אל מסד הנתונים.",
+ "externaldata-db-unknown-collection": "שגיאה: אוסף MongoDB לא ידוע.",
+ "externaldata-db-no-return-values": "שגיאה: לא הוגדרו ערכים להחזרה.",
+ "externaldata-db-invalid-query": "שאילתה בלתי תקינה."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/hsb.json b/www/wiki/extensions/ExternalData/i18n/hsb.json
new file mode 100644
index 00000000..9e181cb2
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/hsb.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "getdata": "Daty wobstarać",
+ "externaldata-desc": "Zmóžnja wotwołowanje strukturowanych datow z eksternych URL, datowych bankow a druhich žórłow",
+ "externaldata-no-param-specified": "Zmylk: Žadyn parameter \"$1\" podaty.",
+ "externaldata-web-invalid-format": "Njepłaćiwy format: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Njemóžno z $1 zwjazać",
+ "externaldata-xml-error": "Zmylk XML: $1 na lince $2",
+ "externaldata-invalid-json": "Zmylk: Njepłaćiwy JSON.",
+ "externaldata-db-incomplete-information": "'''Zmylk: Njedospołne informacije za ID tutoho serwera.'''",
+ "externaldata-db-could-not-get-url": "Njebě móžno URL po $1 {{PLURAL:$1|pospyće|pospytomaj|pospytach|pospytach}} dóstać.",
+ "externaldata-db-unknown-type": "'''Zmylk: Njeznaty typ datoweje banki.'''",
+ "externaldata-db-could-not-connect": "'''Zmylk: Njemóžno z datowej banku zwjazać.'''",
+ "externaldata-db-unknown-collection": "Zmylk: Njeznata MongoDB-zběrka.",
+ "externaldata-db-no-return-values": "'''Zmylk: Žane hódnoty wróćenja podate.'''",
+ "externaldata-db-invalid-query": "Njepłaćiwe naprašowanje."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/hu.json b/www/wiki/extensions/ExternalData/i18n/hu.json
new file mode 100644
index 00000000..7cf3e08f
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/hu.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dj",
+ "Glanthor Reviol"
+ ]
+ },
+ "getdata": "Adatok lekérése",
+ "externaldata-desc": "Strukturált adatok lekérése külső URL-ekről, adatbázisokból vagy más forrásokból",
+ "externaldata-web-invalid-format": "Érvénytelen formátum: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Sikertelen csatlakozás a következőhöz: $1",
+ "externaldata-xml-error": "$1 XML hiba, $2. sor",
+ "externaldata-db-incomplete-information": "Hiba: hiányos információ a szerver azonosítóhoz.",
+ "externaldata-db-could-not-get-url": "Nem sikerült lekérni az URL-t {{PLURAL:$1|egy|$1}} próbálkozás alatt.",
+ "externaldata-db-unknown-type": "Hiba: ismeretlen adatbázis típus.",
+ "externaldata-db-could-not-connect": "Hiba: nem sikerült csatlakozni az adatbázishoz.",
+ "externaldata-db-no-return-values": "Hiba: nem lettek megadva visszatérési értékek.",
+ "externaldata-db-invalid-query": "Érvénytelen lekérdezés."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/hy.json b/www/wiki/extensions/ExternalData/i18n/hy.json
new file mode 100644
index 00000000..60689141
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/hy.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "M hamlet"
+ ]
+ },
+ "externaldata-invalid-json": "Սխալ․ Թերի JSON"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ia.json b/www/wiki/extensions/ExternalData/i18n/ia.json
new file mode 100644
index 00000000..74552c5f
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ia.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "getdata": "Obtener datos",
+ "externaldata-desc": "Permitte recuperar datos structurate ab adresses URL, bases de datos e altere fontes externe",
+ "externaldata-no-param-specified": "Error: Nulle parametro \"$1\" specificate.",
+ "externaldata-web-invalid-format": "Formato invalide: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Impossibile connecter se a $1",
+ "externaldata-xml-error": "Error de XML: $1 al linea $2",
+ "externaldata-invalid-json": "Error: JSON invalide.",
+ "externaldata-db-incomplete-information": "Error: Information incomplete pro iste ID de servitor.",
+ "externaldata-db-could-not-get-url": "Non poteva obtener le URL post $1 {{PLURAL:$1|tentativa|tentativas}}.",
+ "externaldata-db-unknown-type": "Error: Typo de base de datos incognite.",
+ "externaldata-db-could-not-connect": "Error: Impossibile connecter se al base de datos.",
+ "externaldata-db-unknown-collection": "Error: Collection MongoDB incognite.",
+ "externaldata-db-no-return-values": "Error: Nulle valor de retorno specificate.",
+ "externaldata-db-invalid-query": "Consulta invalide."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/id.json b/www/wiki/extensions/ExternalData/i18n/id.json
new file mode 100644
index 00000000..47eb05e9
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/id.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bennylin",
+ "Farras",
+ "IvanLanin",
+ "Iwan Novirion"
+ ]
+ },
+ "getdata": "Ambil data",
+ "externaldata-desc": "Memungkinkan untuk mengambil data terstruktur dari URL eksternal, database dan sumber lainnya",
+ "externaldata-web-invalid-format": "Format salah: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Tidak dapat terhubung ke $1",
+ "externaldata-xml-error": "Galat XML: $1 pada baris $2",
+ "externaldata-db-incomplete-information": "Galat: Informasi tak lengkap untuk ID server ini.",
+ "externaldata-db-could-not-get-url": "Tidak dapat mengambil URL setelah dicoba {{PLURAL:$1||}}$1 kali.",
+ "externaldata-db-unknown-type": "Galat: Jenis basis data tidak diketahui.",
+ "externaldata-db-could-not-connect": "Galat: Tidak dapat terhubung ke basis data.",
+ "externaldata-db-no-return-values": "Galat: Nilai pengembalian tidak dispesifikasi.",
+ "externaldata-db-invalid-query": "Kueri tidak sah."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ilo.json b/www/wiki/extensions/ExternalData/i18n/ilo.json
new file mode 100644
index 00000000..04ea47d0
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ilo.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lam-ang"
+ ]
+ },
+ "getdata": "Agala ti datos",
+ "externaldata-desc": "Mangipalubos para iti panagala ti naestruktura a datos manipud kadagiti akin-ruar nga URL, dagiti database ken dagiti dadduma pay a taudan",
+ "externaldata-no-param-specified": "Biddut: Awan ti parametro ti \"$1\" a nainaganan.",
+ "externaldata-web-invalid-format": "Imbalido a pormat: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Di mabalin a maikonekta iti $1",
+ "externaldata-xml-error": "Biddut ti XML: $1 iti linia $2",
+ "externaldata-invalid-json": "Biddut: Imbalido a JSON.",
+ "externaldata-db-incomplete-information": "Biddut: Saan a kompleto a pakaammo para iti daytoy nga ID ti database.",
+ "externaldata-db-could-not-get-url": "Saan a makaala iti URL kalpasan ti $1 {{PLURAL:$1|panagipadas|panagipadpadas}}.",
+ "externaldata-db-unknown-type": "Biddut: Di ammo a kita ti database.",
+ "externaldata-db-could-not-connect": "Biddut: Saan a makaikonekta iti database.",
+ "externaldata-db-unknown-collection": "Biddut: Di ammo nga urnong ti MongoDB.",
+ "externaldata-db-no-return-values": "Biddut: Awan ti naisubli kadagiti pateg a nainaganan.",
+ "externaldata-db-invalid-query": "Imbalido a panagusisa."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/it.json b/www/wiki/extensions/ExternalData/i18n/it.json
new file mode 100644
index 00000000..3c5bcd24
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/it.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Pietrodn"
+ ]
+ },
+ "getdata": "Ottieni dati",
+ "externaldata-desc": "Consente di recuperare dati strutturati da URL esterni, database o altre sorgenti",
+ "externaldata-no-param-specified": "Errore: nessun parametro \"$1\" specificato.",
+ "externaldata-web-invalid-format": "Formato non valido: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Impossibile connettersi a $1",
+ "externaldata-xml-error": "Errore XML: $1 alla linea $2",
+ "externaldata-invalid-json": "Errore: JSON non valido",
+ "externaldata-db-incomplete-information": "Errore: informazioni incomplete per questo server ID.",
+ "externaldata-db-could-not-get-url": "Impossibile raggiungere l'URL dopo $1 {{PLURAL:$1|tentativo|tentativi}}.",
+ "externaldata-db-unknown-type": "Errore: tipo di database sconosciuto.",
+ "externaldata-db-could-not-connect": "Errore: impossibile connettersi al database.",
+ "externaldata-db-unknown-collection": "Errore: collezione MongoDB sconosciuta.",
+ "externaldata-db-no-return-values": "Errore: non è stato specificato alcun valore di ritorno.",
+ "externaldata-db-invalid-query": "Query non valida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ja.json b/www/wiki/extensions/ExternalData/i18n/ja.json
new file mode 100644
index 00000000..ab29011a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ja.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fryed-peach",
+ "Schu",
+ "Shirayuki",
+ "青子守歌"
+ ]
+ },
+ "getdata": "データ取得",
+ "externaldata-desc": "外部 URL やデータベース、その他のソースからデータを取得できるようにする",
+ "externaldata-no-param-specified": "エラー: パラメーター「$1」が指定されていません。",
+ "externaldata-web-invalid-format": "無効な書式:「$1」",
+ "externaldata-ldap-unable-to-connect": "$1 に接続できません。",
+ "externaldata-xml-error": "XML エラー: 行 $2 で $1",
+ "externaldata-invalid-json": "エラー: 無効な JSON です。",
+ "externaldata-db-incomplete-information": "エラー: このデータベース ID に対する情報が不十分です。",
+ "externaldata-db-could-not-get-url": "$1 回試行しましたが URL を取得できませんでした。",
+ "externaldata-db-unknown-type": "エラー: データベースの種類が不明です。",
+ "externaldata-db-could-not-connect": "エラー: データベースに接続できませんでした。",
+ "externaldata-db-unknown-collection": "エラー: 不明な MongoDB コレクションです。",
+ "externaldata-db-no-return-values": "エラー: 戻り値が指定されていません。",
+ "externaldata-db-invalid-query": "無効なクエリです。"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ka.json b/www/wiki/extensions/ExternalData/i18n/ka.json
new file mode 100644
index 00000000..4ad6b1b7
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ka.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "externaldata-db-invalid-query": "არასწორი მოთხონა."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/km.json b/www/wiki/extensions/ExternalData/i18n/km.json
new file mode 100644
index 00000000..cdeabe25
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/km.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "វ័ណថារិទ្ធ"
+ ]
+ },
+ "getdata": "យក​ទិន្នន័យ"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/kn.json b/www/wiki/extensions/ExternalData/i18n/kn.json
new file mode 100644
index 00000000..449a4f3a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/kn.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N."
+ ]
+ },
+ "getdata": "ಮಾಹಿತಿಯನ್ನು ಪಡೆ",
+ "externaldata-web-invalid-format": "ಅಸಿಂಧು ವಿನ್ಯಾಸ: \"$1\".",
+ "externaldata-ldap-unable-to-connect": "$1.ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾದ್ಯವಾಗುತ್ತಿಲ್ಲ",
+ "externaldata-invalid-json": "ದೋಷ:ಅಸಮರ್ಪಕ JSON.",
+ "externaldata-db-incomplete-information": "ದೋಷ:ದತ್ತಾಂಶ ಐಡಿ ಬಗ್ಗೆ ಅಸಂಪೂರ್ಣ ಮಾಹಿತಿ.",
+ "externaldata-db-unknown-type": "ದೋಷ:ಆಜ್ಞಾತ ದತ್ತಸಂಚಯ ಮಾದರಿ.",
+ "externaldata-db-could-not-connect": "ದೋಷ:ದತ್ತಸಂಚಯವನ್ನು ಸಂಪರ್ಕಿಸಲು ಸಾದ್ಯವಾಗುತ್ತಿಲ್ಲ.",
+ "externaldata-db-invalid-query": "ಅಸಿಂಧು ಪ್ರಶ್ನೆ."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ko.json b/www/wiki/extensions/ExternalData/i18n/ko.json
new file mode 100644
index 00000000..d4b71ca7
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ko.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Daisy2002",
+ "Priviet",
+ "Yjs5497",
+ "아라"
+ ]
+ },
+ "getdata": "데이터 가져오기",
+ "externaldata-desc": "외부 URL, 데이터베이스 및 다른 출처에서 구조화된 데이터를 가져올 수 있게 하기",
+ "externaldata-no-param-specified": "오류: 지정된 \"$1\" 변수가 없습니다.",
+ "externaldata-web-invalid-format": "\"$1\" 상태가 잘못되었습니다.",
+ "externaldata-ldap-unable-to-connect": "$1에 연결할 수 없습니다.",
+ "externaldata-xml-error": "XML 오류: $2 줄에서 $1 오류 발생.",
+ "externaldata-invalid-json": "오류: 잘못된 JSON입니다.",
+ "externaldata-db-incomplete-information": "오류: 데이터베이스 ID 정보가 충분하지 않습니다.",
+ "externaldata-db-could-not-get-url": "$1 {{PLURAL:$1|번의 시도}}에도 URL을 가져올 수 없었습니다.",
+ "externaldata-db-unknown-type": "오류: 알 수 없는 데이터베이스 형식입니다.",
+ "externaldata-db-could-not-connect": "오류: 데이터베이스에 연결할 수 없습니다.",
+ "externaldata-db-unknown-collection": "오류: 알 수 없는 MongoDB 집합입니다.",
+ "externaldata-db-no-return-values": "오류: 지정된 반환 값이 없습니다.",
+ "externaldata-db-invalid-query": "유효하지 않은 쿼리"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ksh.json b/www/wiki/extensions/ExternalData/i18n/ksh.json
new file mode 100644
index 00000000..9c121056
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ksh.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "getdata": "Daate holle!",
+ "externaldata-desc": "Määt et müjjelich, Date en beshtemmpte Fomaate fun främbde <i lang=\"en\">URLs</i>, Daatebangke, un ander Quälle ze holle.",
+ "externaldata-no-param-specified": "Fähler: Dä Parramehter „$1“ es nit aanjejovve.",
+ "externaldata-web-invalid-format": "Dat Formaat es onjöltsch: „$1“",
+ "externaldata-ldap-unable-to-connect": "Kann nit noh $1 verbenge",
+ "externaldata-xml-error": "Fähler em XML, op Reih $2: $1",
+ "externaldata-invalid-json": "Fähler: Onjöltesch <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"JavaScript Object Notation\">JSON</i>.",
+ "externaldata-db-incomplete-information": "<span style=\"text-transform: uppercase\">Fähler:</span> De Enfomazjuhne vör di ẞööver-Kännong sin nit kumplätt.",
+ "externaldata-db-could-not-get-url": "Kunnt {{PLURAL:$1|noh eimohl Versöhke|och noh $1 Mohl Versöhke|ohne enne Versöhk}} nix vun däm <i lang=\"en\">URL</i> krijje.",
+ "externaldata-db-unknown-type": "<span style=\"text-transform: uppercase\">Fähler:</span> Di Zoot Datebangk es unbikannt.",
+ "externaldata-db-could-not-connect": "<span style=\"text-transform: uppercase\">Fähler:</span> Kunnt kein Verbendung noh dä Datebangk krijje.",
+ "externaldata-db-unknown-collection": "<span style=\"text-transform: uppercase\">Fähler:</span> Dat es en onbikannte <i lang\"en\">MongoDB</i>-Zosammeschtällong.",
+ "externaldata-db-no-return-values": "<span style=\"text-transform: uppercase\">Fähler:</span> Kein Wääte för Zerökzeävve aanjejovve.",
+ "externaldata-db-invalid-query": "Onjöltesch Frooch aan de Datebangk."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/lb.json b/www/wiki/extensions/ExternalData/i18n/lb.json
new file mode 100644
index 00000000..a1bcc76c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/lb.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby"
+ ]
+ },
+ "getdata": "Donnéeë kréien",
+ "externaldata-desc": "Erlaabt et Donnéeën vun externen URLen, Datebanken an anere Quellen ze verschaffen",
+ "externaldata-no-param-specified": "Feeler: Keen \"$1\"-Parameter spezifizéiert.",
+ "externaldata-web-invalid-format": "Net valabele Format: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Onméiglech sech op $1 ze connectéieren",
+ "externaldata-xml-error": "XML Feeler: $1 an der Linn $2",
+ "externaldata-invalid-json": "Feeler:JSON net valabel.",
+ "externaldata-db-incomplete-information": "Feeler: Informatioun fir dës Server ID net komplett.",
+ "externaldata-db-could-not-get-url": "D'URL konnt no {{PLURAL:$1|enger Kéier|$1 Versich}} net opgemaach ginn.",
+ "externaldata-db-unknown-type": "Feeler: Onbekannten Datebank-Typ.",
+ "externaldata-db-could-not-connect": "Feeler: D'Verbindung mat der Datebank konnt net opgebaut ginn.",
+ "externaldata-db-unknown-collection": "Feeler:Onbekannte MongoDB Sammlung.",
+ "externaldata-db-no-return-values": "Feeler: Kee Retour-Wäert festgeluecht.",
+ "externaldata-db-invalid-query": "Net valabel Ufro."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/lt.json b/www/wiki/extensions/ExternalData/i18n/lt.json
new file mode 100644
index 00000000..913db87c
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/lt.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eitvys200"
+ ]
+ },
+ "getdata": "Gauti duomenys",
+ "externaldata-no-param-specified": "Klaida\" Nenurodytas joks „$1“ parametras.",
+ "externaldata-web-invalid-format": "Negalimas formatas: „$1“.",
+ "externaldata-ldap-unable-to-connect": "Negalima prisijungti prie $1.",
+ "externaldata-xml-error": "XML klaida: $1, eilutėje $2.",
+ "externaldata-invalid-json": "Klaida: Negalimas JSON.",
+ "externaldata-db-could-not-get-url": "Nepavyko gauti URL po $1 {{PLURAL:$1|bandymo|bandymų}}.",
+ "externaldata-db-unknown-type": "Klaida: Nežinomas duomenų bazės tipas.",
+ "externaldata-db-could-not-connect": "Klaida: Nepavyko prisijungti prie duomenų bazės.",
+ "externaldata-db-unknown-collection": "Klaida: Nežinoma MongoDB kolekcija.",
+ "externaldata-db-no-return-values": "Klaida: Nenurodytos jokios gražinimo reikšmės.",
+ "externaldata-db-invalid-query": "Negalima užklausa."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/lv.json b/www/wiki/extensions/ExternalData/i18n/lv.json
new file mode 100644
index 00000000..ebf66083
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/lv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Papuass"
+ ]
+ },
+ "getdata": "Saņemt datus"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/mk.json b/www/wiki/extensions/ExternalData/i18n/mk.json
new file mode 100644
index 00000000..07f04e82
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/mk.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "getdata": "Земи податоци",
+ "externaldata-desc": "Овозможува добивање структурирани податоци од надворешни URL-адреси, бази на податоци и други извори",
+ "externaldata-no-param-specified": "Грешка: Го немате укажано параметарот „$1“.",
+ "externaldata-web-invalid-format": "Неважечки формат: „$1“",
+ "externaldata-ldap-unable-to-connect": "Не можам да се поврзам со $1",
+ "externaldata-xml-error": "XML грешка: $1 во ред $2",
+ "externaldata-invalid-json": "Грешка: Неважечки JSON",
+ "externaldata-db-incomplete-information": "Грешка: Нецелосни информации за овој опслужувачки ид. бр.",
+ "externaldata-db-could-not-get-url": "Не можев да ја добијам URL адресата по $1 {{PLURAL:$1|обид|обиди}}.",
+ "externaldata-db-unknown-type": "Грешка: Непознат тип на база на податоци.",
+ "externaldata-db-could-not-connect": "Грешка: Не можев да се поврзам со базата на податоци.",
+ "externaldata-db-unknown-collection": "Грешка: Непозната збирка од MongoDB.",
+ "externaldata-db-no-return-values": "Грешка: Нема назначено повратни вредности.",
+ "externaldata-db-invalid-query": "Грешно барање."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ms.json b/www/wiki/extensions/ExternalData/i18n/ms.json
new file mode 100644
index 00000000..b40f6ae9
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ms.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "getdata": "Dapatkan data",
+ "externaldata-desc": "Membolehkan pengambilan data berstruktur dari URL luaran, pangkalan data atau sumber-sumber lain",
+ "externaldata-web-invalid-format": "Format tidak sah: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Tidak dapat bersambung dengan $1",
+ "externaldata-xml-error": "Ralat XML: $1 di baris $2",
+ "externaldata-db-incomplete-information": "Ralat: Maklumat tidak lengkap untuk ID pelayan ini.",
+ "externaldata-db-could-not-get-url": "URL tidak dapat diterima selepas $1 cubaan.",
+ "externaldata-db-unknown-type": "Ralat: Jenis pangkalan data tidak dikenali.",
+ "externaldata-db-could-not-connect": "Ralat: Tidak dapat bersambung dengan pangkalan data.",
+ "externaldata-db-unknown-collection": "Ralat: Koleksi MongoDB tidak dikenali.",
+ "externaldata-db-no-return-values": "Ralat: Tiada nilai pulangan yang ditentukan.",
+ "externaldata-db-invalid-query": "Pertanyaan tidak sah."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/myv.json b/www/wiki/extensions/ExternalData/i18n/myv.json
new file mode 100644
index 00000000..7df6a260
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/myv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Botuzhaleny-sodamo"
+ ]
+ },
+ "getdata": "Дата мельга"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/nb.json b/www/wiki/extensions/ExternalData/i18n/nb.json
new file mode 100644
index 00000000..62fc39d2
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/nb.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Harald Khan",
+ "Nghtwlkr",
+ "Njardarlogar",
+ "Danmichaelo",
+ "Jon Harald Søby"
+ ]
+ },
+ "getdata": "Hent data",
+ "externaldata-desc": "Gir mulighet til å hente strukturerte data fra eksterne internettadresser, databaser og andre kilder",
+ "externaldata-no-param-specified": "Feil: Ingen parameter «$1» oppgitt.",
+ "externaldata-web-invalid-format": "Ugyldig format: «$1»",
+ "externaldata-ldap-unable-to-connect": "Klarte ikke å koble til $1",
+ "externaldata-xml-error": "XML-feil: $1 på linje $2",
+ "externaldata-invalid-json": "Feil: Ugyldig JSON.",
+ "externaldata-db-incomplete-information": "Feil: Ufullstendig informasjon for denne tjener-IDen.",
+ "externaldata-db-could-not-get-url": "Klarte ikke hente URL etter {{PLURAL:$1|ett forsøk|$1 forsøk}}.",
+ "externaldata-db-unknown-type": "Feil: Ukjent databasetype.",
+ "externaldata-db-could-not-connect": "Feil: Kunne ikke koble til database.",
+ "externaldata-db-unknown-collection": "Feil: Ukjent MongoDB-samling.",
+ "externaldata-db-no-return-values": "Feil: Ingen returverdi spesifisert.",
+ "externaldata-db-invalid-query": "Ugyldig spørring."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/nl.json b/www/wiki/extensions/ExternalData/i18n/nl.json
new file mode 100644
index 00000000..9f5d9b82
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/nl.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Effeietsanders",
+ "SPQRobin",
+ "Siebrand"
+ ]
+ },
+ "getdata": "Gegevens ophalen",
+ "externaldata-desc": "Maakt het mogelijk gegevens van externe URL's, database en andere externe bronnen op te halen",
+ "externaldata-no-param-specified": "Fout: er is geen parameter \"$1\" opgegeven.",
+ "externaldata-web-invalid-format": "Ongeldige indeling: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Het was niet mogelijk te verbinden met $1",
+ "externaldata-xml-error": "XML-fout: $1 op regel $2",
+ "externaldata-invalid-json": "Fout: ongeldige JSON",
+ "externaldata-db-incomplete-information": "Fout: onvolledige informatie voor dit servernummer.",
+ "externaldata-db-could-not-get-url": "Na $1 {{PLURAL:$1|poging|pogingen}} gaf de URL geen resultaat.",
+ "externaldata-db-unknown-type": "Fout: onbekend databasetype.",
+ "externaldata-db-could-not-connect": "Fout: het was niet mogelijk met de database te verbinden.",
+ "externaldata-db-unknown-collection": "Fout: onbekende MongoDB-verzameling.",
+ "externaldata-db-no-return-values": "Fout: er zijn geen return-waarden ingesteld.",
+ "externaldata-db-invalid-query": "Ongeldige zoekopdracht."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/nn.json b/www/wiki/extensions/ExternalData/i18n/nn.json
new file mode 100644
index 00000000..a8552bcd
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/nn.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gunnernett",
+ "Harald Khan",
+ "Njardarlogar"
+ ]
+ },
+ "getdata": "Hent data",
+ "externaldata-desc": "Gjev høve til å henta strukturerte data frå eksterne URL-ar, databasar og andre kjelder",
+ "externaldata-ldap-unable-to-connect": "Kunne ikkje kopla til $1",
+ "externaldata-xml-error": "XML-feil: $1 på line $2",
+ "externaldata-db-incomplete-information": "Feil: Ufullstendig informasjon for denne tenar-ID-en.",
+ "externaldata-db-could-not-get-url": "Kunne ikkje henta URL etter {{PLURAL:$1|eitt forsøk|$1 forsøk}}.",
+ "externaldata-db-unknown-type": "Feil: Ukjend databasetype.",
+ "externaldata-db-could-not-connect": "Feil: Kunne ikkje kopla til databasen.",
+ "externaldata-db-no-return-values": "Feil: Ingen returverdiar oppgjevne.",
+ "externaldata-db-invalid-query": "Ugyldig spørjing."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/oc.json b/www/wiki/extensions/ExternalData/i18n/oc.json
new file mode 100644
index 00000000..898d940d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/oc.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "getdata": "Obténer de donadas",
+ "externaldata-desc": "Permet de recuperar de donadas estructuradas a partir d'URL extèrnas, de basas de donadas e d'autras fonts",
+ "externaldata-ldap-unable-to-connect": "Impossible de se connectar a $1",
+ "externaldata-xml-error": "Error XML : $1 a la linha $2",
+ "externaldata-db-incomplete-information": "Error : Informacions incompletas per aqueste identificant de servidor.",
+ "externaldata-db-could-not-get-url": "Impossible d'obténer l'URL aprèp $1 {{PLURAL:$1|ensag|ensages}}.",
+ "externaldata-db-unknown-type": "ERROR: Tipe de basa de donadas desconegut.",
+ "externaldata-db-could-not-connect": "Error : Impossible de se connectar a la basa de donadas.",
+ "externaldata-db-no-return-values": "Error : Cap de valor de retorn es pas estada especificada.",
+ "externaldata-db-invalid-query": "Requèsta invalida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/or.json b/www/wiki/extensions/ExternalData/i18n/or.json
new file mode 100644
index 00000000..0340fd61
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/or.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jnanaranjan Sahu"
+ ]
+ },
+ "getdata": "ତଥ୍ୟ ହାସଲ କରିବେ",
+ "externaldata-ldap-unable-to-connect": "$1ସହ ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ",
+ "externaldata-db-could-not-connect": "ଅସୁବିଧା : ଡାଟାବେସ ସହ ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ ।"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/pl.json b/www/wiki/extensions/ExternalData/i18n/pl.json
new file mode 100644
index 00000000..44d87bb7
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/pl.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym",
+ "Chrumps",
+ "Leinad",
+ "Sp5uhe"
+ ]
+ },
+ "getdata": "Pobierz dane",
+ "externaldata-desc": "Umożliwia pobieranie strukturalnych danych z zewnętrznych adresów URL, baz danych i innych źródeł",
+ "externaldata-no-param-specified": "Błąd: Nie podano parametru „$1”.",
+ "externaldata-web-invalid-format": "Nieprawidłowy format: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Nie można połączyć się z $1",
+ "externaldata-xml-error": "Błąd XML – $1 w wierszu $2",
+ "externaldata-invalid-json": "Błąd: Nieprawidłowy JSON",
+ "externaldata-db-incomplete-information": "Błąd – niepełne informacje o tym identyfikatorze serwera.",
+ "externaldata-db-could-not-get-url": "Nie można uzyskać adresu URL po $1 {{PLURAL:$1|próbie|próbach}}.",
+ "externaldata-db-unknown-type": "Błąd: Nieznany typ bazy danych.",
+ "externaldata-db-could-not-connect": "Błąd: Nie można połączyć się z bazą danych.",
+ "externaldata-db-unknown-collection": "Błąd: Nieznany zbiór MongoDB.",
+ "externaldata-db-no-return-values": "Błąd – nie określono zwracanej wartości.",
+ "externaldata-db-invalid-query": "Nieprawidłowe zapytanie."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/pms.json b/www/wiki/extensions/ExternalData/i18n/pms.json
new file mode 100644
index 00000000..19af566e
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/pms.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "getdata": "Oten dij dat",
+ "externaldata-desc": "A përmët d'arcuperé dat struturà da adrësse dl'aragnà esterne, base ëd dàit e d'àutre sorgiss",
+ "externaldata-web-invalid-format": "Formà pa bon: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "A peul pa coleghesse a $1",
+ "externaldata-xml-error": "Eror XML: $1 a la linia $2",
+ "externaldata-db-incomplete-information": "Eror: Anformassion pa completa për sto server ID-sì.",
+ "externaldata-db-could-not-get-url": "A peul pa oten-e l'URL d'apress ëd $1 {{PLURAL:$1|preuva|preuve}}.",
+ "externaldata-db-unknown-type": "Eror: Sòrt ëd database pa conossùa",
+ "externaldata-db-could-not-connect": "Eror: a peul pa coleghesse al database.",
+ "externaldata-db-unknown-collection": "Eoro: Colession MongoDB pa conossùa.",
+ "externaldata-db-no-return-values": "Eror: Pa gnun valor d'artorn spessifià.",
+ "externaldata-db-invalid-query": "Ciamà pa bon-a."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/pt-br.json b/www/wiki/extensions/ExternalData/i18n/pt-br.json
new file mode 100644
index 00000000..ad64b486
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/pt-br.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eduardo.mps",
+ "Giro720",
+ "Jaideraf"
+ ]
+ },
+ "getdata": "Obter dados",
+ "externaldata-desc": "Permite a obtenção de dados em CSV, JSON e XML a partir de URLs externos, banco de dados e outras fontes",
+ "externaldata-no-param-specified": "Erro: nenhum parâmetro \"$1\" especificado.",
+ "externaldata-web-invalid-format": "Formato inválido: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Não foi possível conectar-se a $1",
+ "externaldata-xml-error": "Erro no XML: $1 na linha $2",
+ "externaldata-invalid-json": "Erro: JSON inválido.",
+ "externaldata-db-incomplete-information": "Erro: informação incompleta para o ID deste servidor</P>",
+ "externaldata-db-could-not-get-url": "Não foi possível obter o URL após $1 {{PLURAL:$1|tentativa|tentativas}}.",
+ "externaldata-db-unknown-type": "Erro: tipo de base de dados desconhecido.",
+ "externaldata-db-could-not-connect": "Erro: não foi possível conectar-se a base de dados.",
+ "externaldata-db-unknown-collection": "Erro: coleção do MongoDB desconhecida.",
+ "externaldata-db-no-return-values": "Erro: nenhum valor de retorno especificado.",
+ "externaldata-db-invalid-query": "Consulta inválida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/pt.json b/www/wiki/extensions/ExternalData/i18n/pt.json
new file mode 100644
index 00000000..c69e0275
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/pt.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giro720",
+ "Hamilton Abreu",
+ "Waldir",
+ "Vitorvicentevalente"
+ ]
+ },
+ "getdata": "Obter dados",
+ "externaldata-desc": "Permite a importação de dados estruturados a partir de endereços URL, bases de dados e outras fontes externas",
+ "externaldata-no-param-specified": "Erro: Nenhum parâmetro \"$1\" especificado.",
+ "externaldata-web-invalid-format": "Formato inválido: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Não foi possível estabelecer ligação a $1",
+ "externaldata-xml-error": "Erro XML: $1 na linha $2",
+ "externaldata-invalid-json": "Erro: Código JSON inválido.",
+ "externaldata-db-incomplete-information": "Erro: Informação incompleta para este identificador de servidor.",
+ "externaldata-db-could-not-get-url": "Não foi possível importar o URL após {{PLURAL:$1|uma tentativa|$1 tentativas}}.",
+ "externaldata-db-unknown-type": "Erro: Tipo de base de dados desconhecido.",
+ "externaldata-db-could-not-connect": "Erro: Não foi possível estabelecer ligação à base de dados.",
+ "externaldata-db-unknown-collection": "Erro: Coleção desconhecida no MongoDB.",
+ "externaldata-db-no-return-values": "Erro: Não foram especificados valores de retorno.",
+ "externaldata-db-invalid-query": "Consulta inválida."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/qqq.json b/www/wiki/extensions/ExternalData/i18n/qqq.json
new file mode 100644
index 00000000..46fddcd5
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/qqq.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dead3y3",
+ "Fryed-peach",
+ "Shirayuki",
+ "Umherirrender"
+ ]
+ },
+ "getdata": "{{doc-special|GetData}}",
+ "externaldata-desc": "{{desc|name=External Data|url=https://www.mediawiki.org/wiki/Extension:External_Data}}",
+ "externaldata-no-param-specified": "The error message if a parameter to some parser function is not set. Parameters:\n* $1 - parameter name. any one of the following: <code>url</code>, <code>data</code>, <code>filter</code>, <code>domain</code>, <code>db</code>, <code>from</code>",
+ "externaldata-web-invalid-format": "The error message if #get_web_data is called with an invalid format value.\n\nParameters:\n* $1 - invalid file format. Valid formats are: \"xml\", \"xml with xpath\", \"csv\", \"csv with header\", \"json\", and \"gff\"",
+ "externaldata-ldap-unable-to-connect": "The error message if #get_ldap_data can't connect to the LDAP server.\n\nParameters:\n* $1 - the LDAP server name",
+ "externaldata-xml-error": "The error message if #get_web_data can't parse an XML file. Parameters:\n* $1 - error message which are returned by PHP's <code>xml_error_string()</code>\n* $2 - line number",
+ "externaldata-invalid-json": "The error message if the URL being accessed does not contain valid JSON",
+ "externaldata-db-incomplete-information": "Used as error message.\n\nDatabase server, database type, database directory, database username and/or database password are not specified.",
+ "externaldata-db-could-not-get-url": "Parameters:\n* $1 - number of HTTP tries",
+ "externaldata-db-unknown-type": "Used as error message when creating a database object with using the specified information.",
+ "externaldata-db-could-not-connect": "Used as error message when connecting to the database system.",
+ "externaldata-db-unknown-collection": "The error message if #get_db_data can't find the specified \"collection\" when connecting to MongoDB.",
+ "externaldata-db-no-return-values": "Used as error message, if the number of the specified columns is zero.\n\nIf successful, the system returns values in the specified columns.",
+ "externaldata-db-invalid-query": "Used as error message, if the query has been failed."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ro.json b/www/wiki/extensions/ExternalData/i18n/ro.json
new file mode 100644
index 00000000..eeb12c58
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ro.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Firilacroco",
+ "KlaudiuMihaila",
+ "Stelistcristi"
+ ]
+ },
+ "getdata": "Obține date",
+ "externaldata-desc": "Permite obținerea datelor în format CSV, JSON și XML din atât adrese URL externe, cât și pagini wiki locale",
+ "externaldata-web-invalid-format": "Fomat invalid: „$1”",
+ "externaldata-ldap-unable-to-connect": "Nu se poate conecta la $1",
+ "externaldata-xml-error": "Eroare XML: $1 la linia $2",
+ "externaldata-db-unknown-type": "Eroare: Tipul bazei de date necunoscut.",
+ "externaldata-db-could-not-connect": "Eroare: Nu s-a putut conecta la baza de date.",
+ "externaldata-db-invalid-query": "Interogare invalidă."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/roa-tara.json b/www/wiki/extensions/ExternalData/i18n/roa-tara.json
new file mode 100644
index 00000000..eb1a37e8
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/roa-tara.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "getdata": "Pigghie le date",
+ "externaldata-desc": "Permette de repigghià data strutturate da URL fore a Uicchipèdie, database e otre sorgende",
+ "externaldata-no-param-specified": "Errore: Nisciune parametre \"$1\" specificate.",
+ "externaldata-web-invalid-format": "Formate invalide: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Indisponibbile a collegarse a $1",
+ "externaldata-xml-error": "Errore XML: $1 sus a linèe $2",
+ "externaldata-invalid-json": "Errore: JSON invalide.",
+ "externaldata-db-incomplete-information": "Errore: 'Mbormazione ingomblete pe stu ID d'u database.",
+ "externaldata-db-could-not-get-url": "Non ge pozze pigghià 'a URL apprisse $1 {{PLURAL:$1|prove}}.",
+ "externaldata-db-unknown-type": "Errore: Tipe de database scanusciute.",
+ "externaldata-db-could-not-connect": "Errore: Non ge me pozze collegà a 'u database.",
+ "externaldata-db-unknown-collection": "Errore: Collezzione scanusciute MongoDB.",
+ "externaldata-db-no-return-values": "Errore: Nisciune valore de retorne specificate.",
+ "externaldata-db-invalid-query": "Inderrogazione invalide."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ru.json b/www/wiki/extensions/ExternalData/i18n/ru.json
new file mode 100644
index 00000000..698a22dd
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ru.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ferrer",
+ "Kaganer",
+ "Okras",
+ "Александр Сигачёв"
+ ]
+ },
+ "getdata": "Получить данные",
+ "externaldata-desc": "Позволяет получать структурированные данные с внешних адресов, баз данных и других источников",
+ "externaldata-no-param-specified": "Ошибка: Не указан параметр «$1».",
+ "externaldata-web-invalid-format": "Недопустимый формат: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Не удаётся подключиться к $1",
+ "externaldata-xml-error": "Ошибка XML. $1 в строке $2",
+ "externaldata-invalid-json": "Ошибка: Недопустимый JSON",
+ "externaldata-db-incomplete-information": "ОШИБКА. Неполная информация для этого ID сервера.",
+ "externaldata-db-could-not-get-url": "Не удалось получить URL после $1 {{PLURAL:$1|попытки|попыток}}.",
+ "externaldata-db-unknown-type": "ОШИБКА. Неизвестный тип базы данных.",
+ "externaldata-db-could-not-connect": "ОШИБКА. Не удаётся подключиться к базе данных.",
+ "externaldata-db-unknown-collection": "Ошибка: Неизвестная коллекция MongoDB.",
+ "externaldata-db-no-return-values": "ОШИБКА. Не указаны возвращаемые значение.",
+ "externaldata-db-invalid-query": "Ошибочный запрос."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sah.json b/www/wiki/extensions/ExternalData/i18n/sah.json
new file mode 100644
index 00000000..1eb13ea6
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sah.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "HalanTul"
+ ]
+ },
+ "getdata": "Дааннайдары ыларга"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sco.json b/www/wiki/extensions/ExternalData/i18n/sco.json
new file mode 100644
index 00000000..34ca143a
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sco.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "AmaryllisGardener"
+ ]
+ },
+ "getdata": "Get data",
+ "externaldata-desc": "Allaes for retrievin structurt data frae freemit URLs, databases an ither soorces",
+ "externaldata-no-param-specified": "Error: No \"$1\" parameter specified.",
+ "externaldata-web-invalid-format": "Invalid format: \"$1\".",
+ "externaldata-ldap-unable-to-connect": "Unable tae connect tae $1.",
+ "externaldata-xml-error": "XML error: $1 at line $2.",
+ "externaldata-invalid-json": "Error: Invalid JSON.",
+ "externaldata-db-incomplete-information": "Error: Incomplete information for this database ID.",
+ "externaldata-db-could-not-get-url": "Couldna get URL efter $1 {{PLURAL:$1|try|tries}}.",
+ "externaldata-db-unknown-type": "Error: Unkent database teep.",
+ "externaldata-db-could-not-connect": "Error: Couldna connect tae database.",
+ "externaldata-db-unknown-collection": "Error: Unkent MongoDB collection.",
+ "externaldata-db-no-return-values": "Error: No return values specified.",
+ "externaldata-db-invalid-query": "Invalid query."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/si.json b/www/wiki/extensions/ExternalData/i18n/si.json
new file mode 100644
index 00000000..939e7a21
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/si.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "getdata": "දත්ත ලබා ගන්න",
+ "externaldata-web-invalid-format": "වලංගු නොවන ආකෘතිය: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "$1 වෙත සම්බන්ධ විය නොහැක",
+ "externaldata-xml-error": "XML දෝෂය: $1 පේළිය $2",
+ "externaldata-db-unknown-type": "දෝෂය: නොදන්නා දත්ත සංචිත වර්ගය.",
+ "externaldata-db-could-not-connect": "දෝෂය: දත්ත සංචිතය වෙත සම්බන්ධ විය නොහැක.",
+ "externaldata-db-invalid-query": "වලංගු නොවන ප්‍රශ්නය."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sk.json b/www/wiki/extensions/ExternalData/i18n/sk.json
new file mode 100644
index 00000000..68706fde
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sk.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Helix84"
+ ]
+ },
+ "getdata": "Získať dáta",
+ "externaldata-desc": "Umožňuje získavanie štrukturovaných údajov z externých URL, databáz a iných zdrojov",
+ "externaldata-ldap-unable-to-connect": "Nepodarilo sa pripojiť k $1",
+ "externaldata-xml-error": "Chyba XML: $1 na riadku $2",
+ "externaldata-db-incomplete-information": "Chyba: Nekompletné informácie s týmto ID servera.",
+ "externaldata-db-could-not-get-url": "Nepodarilo sa získať URL po $1 {{PLURAL:$1|pokuse|pokusoch}}.",
+ "externaldata-db-unknown-type": "Chyba: Neznámy typ databázy.",
+ "externaldata-db-could-not-connect": "Chyba: Nepodarilo sa pripojiť k databáze.",
+ "externaldata-db-no-return-values": "Chyba: Neboli zadané žiadne návratové hodnoty.",
+ "externaldata-db-invalid-query": "Neplatná požiadavka."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sr-ec.json b/www/wiki/extensions/ExternalData/i18n/sr-ec.json
new file mode 100644
index 00000000..9ba567e2
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sr-ec.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Charmed94",
+ "Milicevic01",
+ "Михајло Анђелковић"
+ ]
+ },
+ "getdata": "Преузми податке",
+ "externaldata-desc": "Омогућава преузимање података из спољашњих адреса, бази података и других извора",
+ "externaldata-ldap-unable-to-connect": "Повезивање на $1 није успело",
+ "externaldata-xml-error": "XML грешка: $1 по линији $2",
+ "externaldata-db-incomplete-information": "Грешка: Непотпуни подаци за овај ID сервера.",
+ "externaldata-db-could-not-get-url": "Преузимање адресе после $1 {{PLURAL:$1|покушаја}} није успело.",
+ "externaldata-db-unknown-type": "Грешка: Непозната врста базе података.",
+ "externaldata-db-could-not-connect": "Грешка: Повезивање с базом података није успело.",
+ "externaldata-db-no-return-values": "Грешка: Повратне вредности нису одређене.",
+ "externaldata-db-invalid-query": "Неисправан упит."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sr-el.json b/www/wiki/extensions/ExternalData/i18n/sr-el.json
new file mode 100644
index 00000000..9f3123f5
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sr-el.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michaello",
+ "Milicevic01"
+ ]
+ },
+ "getdata": "Preuzmi podatke",
+ "externaldata-desc": "Omogućava preuzimanje podataka iz spoljašnjih adresa, bazi podataka i drugih izvora",
+ "externaldata-ldap-unable-to-connect": "Povezivanje na $1 nije uspelo",
+ "externaldata-xml-error": "XML greška: $1 po liniji $2",
+ "externaldata-db-incomplete-information": "Greška: Nepotpuni podaci za ovaj ID servera.",
+ "externaldata-db-could-not-get-url": "Preuzimanje adrese posle $1 {{PLURAL:$1|pokušaja}} nije uspelo.",
+ "externaldata-db-unknown-type": "Greška: Nepoznata vrsta baze podataka.",
+ "externaldata-db-could-not-connect": "Greška: Povezivanje s bazom podataka nije uspelo.",
+ "externaldata-db-no-return-values": "Greška: Povratne vrednosti nisu određene.",
+ "externaldata-db-invalid-query": "Neispravan upit."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/sv.json b/www/wiki/extensions/ExternalData/i18n/sv.json
new file mode 100644
index 00000000..b0fc14e8
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/sv.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Boivie",
+ "Lokal Profil",
+ "Najami",
+ "Per",
+ "Tobulos1",
+ "WikiPhoenix"
+ ]
+ },
+ "getdata": "Hämta data",
+ "externaldata-desc": "Ger möjlighet att hämta strukturerad data från externa URL:er, databaser och andra källor",
+ "externaldata-no-param-specified": "Fel: Ingen \"$1\" parameter specificerad.",
+ "externaldata-web-invalid-format": "Ogiltigt format: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Kunde inte koppla till $1",
+ "externaldata-xml-error": "XML-fel: $1 på rad $2",
+ "externaldata-invalid-json": "Fel: Ogiltig JSON.",
+ "externaldata-db-incomplete-information": "Fel: Informationen för server-ID inte komplett.",
+ "externaldata-db-could-not-get-url": "Kunde inte hämta URL på $1 {{PLURAL:$1|försök|försök}}.",
+ "externaldata-db-unknown-type": "Fel: Okänd databastyp.",
+ "externaldata-db-could-not-connect": "Fel: Kunde inte koppla till databasen.",
+ "externaldata-db-unknown-collection": "Fel: Okänd MongoDB samling.",
+ "externaldata-db-no-return-values": "Fel: Inga returvärden specificerade.",
+ "externaldata-db-invalid-query": "Ogiltig fråga."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/ta.json b/www/wiki/extensions/ExternalData/i18n/ta.json
new file mode 100644
index 00000000..6a673b38
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/ta.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karthi.dr",
+ "மதனாஹரன்"
+ ]
+ },
+ "getdata": "தகவலைப் பெறு",
+ "externaldata-db-unknown-type": "தவறு: அறியாத தரவுத் தள வகை.",
+ "externaldata-db-could-not-connect": "தவறு: தரவுத் தளத்துடன் தொடர்பு கொள்ள முடியவில்லை.",
+ "externaldata-db-invalid-query": "செல்லாத வினவல்."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/te.json b/www/wiki/extensions/ExternalData/i18n/te.json
new file mode 100644
index 00000000..5734bee6
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/te.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chaduvari",
+ "Kiranmayee"
+ ]
+ },
+ "getdata": "విషయములు తీసుకునిరా",
+ "externaldata-ldap-unable-to-connect": "$1 కు కనెక్టు కాలేకున్నాం"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/tl.json b/www/wiki/extensions/ExternalData/i18n/tl.json
new file mode 100644
index 00000000..4904d02d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/tl.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw",
+ "Sky Harbor"
+ ]
+ },
+ "getdata": "Kunin ang dato",
+ "externaldata-desc": "Nagpapahintulot sa pagkuha ng nakabalangkas na datos mula sa panlabas na mga URL, mga kalipunan ng datos at sa ibang mga pinagmulan",
+ "externaldata-web-invalid-format": "Hindi katanggap-tanggap na anyo: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Hindi makakunekta sa $1",
+ "externaldata-xml-error": "Kamalian sa XML: $1 sa linyang $2",
+ "externaldata-db-incomplete-information": "Kamalian: Hindi-kumpletong impormasyon para sa itong ID ng serbidor.",
+ "externaldata-db-could-not-get-url": "Hindi makuha ang URL pagkatapos ng $1 {{PLURAL:$1|pagsubok|pagsubok}}",
+ "externaldata-db-unknown-type": "Kamalian: Hindi-kilalang uri ng kalipunan ng datos.",
+ "externaldata-db-could-not-connect": "Kamalian: Hindi makakunekta sa talaan ng dato.",
+ "externaldata-db-no-return-values": "Kamalian: Walang tinukoy na halagang pabalik.",
+ "externaldata-db-invalid-query": "Hindi tanggap na katanungan."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/tr.json b/www/wiki/extensions/ExternalData/i18n/tr.json
new file mode 100644
index 00000000..78fdb552
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/tr.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karduelis",
+ "Vito Genovese"
+ ]
+ },
+ "getdata": "Veri al",
+ "externaldata-db-unknown-type": "Hata: Bilinmeyen veritabanı türü.",
+ "externaldata-db-could-not-connect": "Hata: Veritabanına bağlanılamıyor.",
+ "externaldata-db-no-return-values": "Hata: Dönüş değeri belirtilmedi.",
+ "externaldata-db-invalid-query": "Geçersiz sorgu."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/uk.json b/www/wiki/extensions/ExternalData/i18n/uk.json
new file mode 100644
index 00000000..8c5fbdab
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/uk.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Andriykopanytsia",
+ "Base",
+ "Ата",
+ "Тест"
+ ]
+ },
+ "getdata": "Отримати дані",
+ "externaldata-desc": "Дозволяє отримувати структуровані дані із зовнішніх URL-адрес, баз даних та інших джерел",
+ "externaldata-no-param-specified": "Помилка: параметр \"$1\" - не вказаний.",
+ "externaldata-web-invalid-format": "Неприпустимий формат: \"$1\"",
+ "externaldata-ldap-unable-to-connect": "Не вдається підключитися до $1",
+ "externaldata-xml-error": "Помилка XML: $1 в рядку $2",
+ "externaldata-invalid-json": "Помилка: Неправильний JSON",
+ "externaldata-db-incomplete-information": "Помилка: Неповна інформація для цього ID сервера.",
+ "externaldata-db-could-not-get-url": "Не вдалося отримати URL після $1 {{PLURAL:$1|1=спроби|спроб}}.",
+ "externaldata-db-unknown-type": "Помилка: Невідомий тип бази даних.",
+ "externaldata-db-could-not-connect": "Помилка: не вдалося підключитися до бази даних.",
+ "externaldata-db-unknown-collection": "Помилка: Невідома колекція MongoDB.",
+ "externaldata-db-no-return-values": "Помилка: Не вказано зворотних значень.",
+ "externaldata-db-invalid-query": "Неприпустимий запит."
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/vep.json b/www/wiki/extensions/ExternalData/i18n/vep.json
new file mode 100644
index 00000000..abad0f38
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/vep.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Игорь Бродский"
+ ]
+ },
+ "getdata": "Sada andmused"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/vi.json b/www/wiki/extensions/ExternalData/i18n/vi.json
new file mode 100644
index 00000000..22c110e6
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/vi.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "Vinhtantran"
+ ]
+ },
+ "getdata": "Lấy dữ liệu",
+ "externaldata-desc": "Cho phép truy xuất dữ liệu từ các địa chỉ URL bên ngoài, cơ sở dữ liệu, và nguồn khác",
+ "externaldata-xml-error": "Lỗi XML ở dòng $2: $1"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/yi.json b/www/wiki/extensions/ExternalData/i18n/yi.json
new file mode 100644
index 00000000..67d767ad
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/yi.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "getdata": "באַקומען דאַטן"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/zh-hans.json b/www/wiki/extensions/ExternalData/i18n/zh-hans.json
new file mode 100644
index 00000000..d42ea52d
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/zh-hans.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hydra",
+ "Liuxinyu970226",
+ "Yfdyh000"
+ ]
+ },
+ "getdata": "获取数据",
+ "externaldata-desc": "允许从外部URL,数据库及其他来源接收结构化数据",
+ "externaldata-no-param-specified": "错误:未指定“$1”参数。",
+ "externaldata-web-invalid-format": "无效的格式:“$1”",
+ "externaldata-ldap-unable-to-connect": "无法连接到 $1",
+ "externaldata-xml-error": "XML错误:$1 在行 $2",
+ "externaldata-invalid-json": "错误:无效的JSON",
+ "externaldata-db-incomplete-information": "错误:此服务器ID信息不完整。",
+ "externaldata-db-could-not-get-url": "$1次尝试后仍无法获取URL。",
+ "externaldata-db-unknown-type": "错误:未知的数据库类型。",
+ "externaldata-db-could-not-connect": "错误:无法连接到数据库。",
+ "externaldata-db-unknown-collection": "错误:未知的MongoDB集合。",
+ "externaldata-db-no-return-values": "错误:没有返回指定的值。",
+ "externaldata-db-invalid-query": "无效的查询。"
+}
diff --git a/www/wiki/extensions/ExternalData/i18n/zh-hant.json b/www/wiki/extensions/ExternalData/i18n/zh-hant.json
new file mode 100644
index 00000000..6fcebe64
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/i18n/zh-hant.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "LNDDYL",
+ "Kly"
+ ]
+ },
+ "getdata": "取得資料",
+ "externaldata-desc": "允許外部 URL、資料庫,以及其它來源檢索結構化資料",
+ "externaldata-no-param-specified": "錯誤:未指定「$1」參數。",
+ "externaldata-web-invalid-format": "無效格式:「$1」。",
+ "externaldata-ldap-unable-to-connect": "無法連結至 $1。",
+ "externaldata-xml-error": "XML 錯誤:在第 $2 行出現 $1。",
+ "externaldata-invalid-json": "錯誤:無效的 JSON。",
+ "externaldata-db-incomplete-information": "錯誤:此資料庫的 ID 訊息不完整。",
+ "externaldata-db-could-not-get-url": "在 $1 {{PLURAL:$1| 次嘗試| 次嘗試}}後仍無法取得 URL。",
+ "externaldata-db-unknown-type": "錯誤:無效資料庫類型。",
+ "externaldata-db-could-not-connect": "錯誤:無法連結至資料庫。",
+ "externaldata-db-unknown-collection": "錯誤:未知的 MongoDB 集合。",
+ "externaldata-db-no-return-values": "錯誤:沒有回傳指定的值。",
+ "externaldata-db-invalid-query": "無效的查詢。"
+}
diff --git a/www/wiki/extensions/ExternalData/includes/ED_GetData.php b/www/wiki/extensions/ExternalData/includes/ED_GetData.php
new file mode 100644
index 00000000..ab084426
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/includes/ED_GetData.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * A special page for retrieving selected rows of any wiki page that contains
+ * data in CSV format
+ */
+
+class EDGetData extends SpecialPage {
+
+ /**
+ * Constructor
+ */
+ function __construct() {
+ parent::__construct( 'GetData' );
+ }
+
+ function execute( $query ) {
+ global $wgRequest, $wgOut;
+
+ $wgOut->disable();
+ $this->setHeaders();
+ $page_name = $query;
+ $title = Title::newFromText( $page_name );
+ if ( is_null( $title ) ) {
+ return;
+ }
+ if ( ! $title->userCan( 'read' ) ) {
+ return;
+ }
+ $wikiPage = WikiPage::factory( $title );
+ $page_text = ContentHandler::getContentText( $wikiPage->getContent() );
+ // Remove <noinclude> sections and <includeonly> tags from text
+ $page_text = StringUtils::delimiterReplace( '<noinclude>', '</noinclude>', '', $page_text );
+ $page_text = strtr( $page_text, array( '<includeonly>' => '', '</includeonly>' => '' ) );
+ $orig_lines = explode( "\n", $page_text );
+ // ignore lines that are either blank or start with a semicolon
+ $page_lines = array();
+ foreach ( $orig_lines as $i => $line ) {
+ if ( $line != '' && $line[0] != ';' ) {
+ $page_lines[] = $line;
+ }
+ }
+ $headers = EDUtils::getValuesFromCSVLine( $page_lines[0] );
+ $queried_headers = array();
+ foreach ( $wgRequest->getValues() as $key => $value ) {
+ foreach ( $headers as $header_index => $header_value ) {
+ $header_value = str_replace( ' ', '_', $header_value );
+ if ( $key == $header_value ) {
+ $queried_headers[$header_index] = $value;
+ }
+ }
+ }
+ // include header in output
+ $text = $page_lines[0];
+ foreach ( $page_lines as $i => $line ) {
+ if ( $i == 0 ) continue;
+ $row_values = EDUtils::getValuesFromCSVLine( $line );
+ $found_match = true;
+ foreach ( $queried_headers as $i => $query_value ) {
+ $single_value = str_replace( ' ', '_', $row_values[$i] );
+ if ( $single_value != $query_value ) {
+ $found_match = false;
+ }
+ }
+ if ( $found_match ) {
+ if ( $text != '' ) $text .= "\n";
+ $text .= $line;
+ }
+ }
+ print $text;
+ }
+
+ protected function getGroupName() {
+ return 'pagetools';
+ }
+}
diff --git a/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php b/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php
new file mode 100644
index 00000000..8edc7e17
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/includes/ED_ParserFunctions.php
@@ -0,0 +1,663 @@
+<?php
+/**
+ * Class for handling the parser functions for External Data
+ */
+
+class EDParserFunctions {
+
+ /**
+ * A helper function, called by doGetWebData().
+ */
+ static public function setGlobalValuesArray( $external_values, $filters, $mappings ) {
+ global $edgValues;
+
+ foreach ( $filters as $filter_var => $filter_value ) {
+ // Find the entry of $external_values that matches
+ // the filter variable; if none exists, just ignore
+ // the filter.
+ if ( array_key_exists( $filter_var, $external_values ) ) {
+ if ( is_array( $external_values[$filter_var] ) ) {
+ $column_values = $external_values[$filter_var];
+ foreach ( $column_values as $i => $single_value ) {
+ // if a value doesn't match
+ // the filter value, remove
+ // the value from this row for
+ // all columns
+ if ( trim( $single_value ) != trim( $filter_value ) ) {
+ foreach ( $external_values as $external_var => $external_value ) {
+ unset( $external_values[$external_var][$i] );
+ }
+ }
+ }
+ } else {
+ // if we have only one row of values,
+ // and the filter doesn't match, just
+ // keep the results array blank and
+ // return
+ if ( $external_values[$filter_var] != $filter_value ) {
+ return;
+ }
+ }
+ }
+ }
+ // for each external variable name specified in the function
+ // call, get its value or values (if any exist), and attach it
+ // or them to the local variable name
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $external_values ) ) {
+ if ( is_array( $external_values[$external_var] ) ) {
+ // array_values() restores regular
+ // 1, 2, 3 indexes to array, after unset()
+ // in filtering may have removed some
+ $edgValues[$local_var] = array_values( $external_values[$external_var] );
+ } else {
+ $edgValues[$local_var][] = $external_values[$external_var];
+ }
+ }
+ }
+ }
+
+ /**
+ * Render the #get_web_data parser function.
+ */
+ static function doGetWebData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'url', $args ) ) {
+ $url = $args['url'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'url')->parse() );
+ }
+ $url = str_replace( ' ', '%20', $url ); // do some minor URL-encoding
+ // if the URL isn't allowed (based on a whitelist), exit
+ if ( ! EDUtils::isURLAllowed( $url ) ) {
+ return EDUtils::formatErrorMessage( "URL is not allowed" );
+ }
+
+ if ( array_key_exists( 'format', $args ) ) {
+ $format = strtolower( $args['format'] );
+ } else {
+ $format = '';
+ }
+ if ( $format == 'xml' ) {
+ if ( array_key_exists( 'use xpath', $args ) ) {
+ // Somewhat of a hack - store the fact that
+ // we're using XPath within the format, even
+ // though the format is still XML.
+ $format = 'xml with xpath';
+ }
+ } elseif ( $format == 'csv' || $format == 'csv with header' ) {
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = $args['delimiter'];
+ // Hopefully this solution isn't "too clever".
+ $format = array( $format, $args['delimiter'] );
+ }
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ if ( $format == 'xml with xpath' ) {
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ $mappings = EDUtils::paramToArray( $args['data'], false, true );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( array_key_exists( 'cache seconds', $args) ) {
+ // set cache expire time
+ $cacheExpireTime = $args['cache seconds'];
+ } else {
+ $cacheExpireTime = $edgCacheExpireTime;
+ }
+
+ if ( array_key_exists( 'json offset', $args) ) {
+ $prefixLength = $args['json offset'];
+ } else {
+ $prefixLength = 0;
+ }
+
+ $postData = array_key_exists( 'post data', $args ) ? $args['post data'] : '';
+ $external_values = EDUtils::getDataFromURL( $url, $format, $mappings, $postData, $cacheExpireTime, $prefixLength );
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+ if ( count( $external_values ) == 0 ) {
+ return;
+ }
+
+ if ( array_key_exists( 'filters', $args ) ) {
+ // parse the 'filters' arg
+ $filters = EDUtils::paramToArray( $args['filters'], true, false );
+ } else {
+ $filters = array();
+ }
+
+ self::setGlobalValuesArray( $external_values, $filters, $mappings );
+ }
+
+ /**
+ * Render the #get_file_data parser function.
+ */
+ static function doGetFileData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'file', $args ) ) {
+ $file = $args['file'];
+ } elseif ( array_key_exists( 'directory', $args ) ) {
+ $directory = $args['directory'];
+ if ( array_key_exists( 'file name', $args ) ) {
+ $fileName = $args['file name'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'file name')->parse() );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'file|directory')->parse() );
+ }
+
+ if ( array_key_exists( 'format', $args ) ) {
+ $format = strtolower( $args['format'] );
+ } else {
+ $format = '';
+ }
+ if ( $format == 'xml' ) {
+ if ( array_key_exists( 'use xpath', $args ) ) {
+ // Somewhat of a hack - store the fact that
+ // we're using XPath within the format, even
+ // though the format is still XML.
+ $format = 'xml with xpath';
+ }
+ } elseif ( $format == 'csv' || $format == 'csv with header' ) {
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = $args['delimiter'];
+ // Hopefully this solution isn't "too clever".
+ $format = array( $format, $args['delimiter'] );
+ }
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ if ( $format == 'xml with xpath' ) {
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ $mappings = EDUtils::paramToArray( $args['data'], false, true );
+ }
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( array_key_exists( 'cache seconds', $args) ) {
+ // set cache expire time
+ $cacheExpireTime = $args['cache seconds'];
+ } else {
+ $cacheExpireTime = $edgCacheExpireTime;
+ }
+
+ if ( isset( $file ) ) {
+ $external_values = EDUtils::getDataFromFile( $file, $format, $mappings );
+ } else {
+ $external_values = EDUtils::getDataFromDirectory( $directory, $fileName, $format, $mappings );
+ }
+
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+ if ( count( $external_values ) == 0 ) {
+ return;
+ }
+
+ if ( array_key_exists( 'filters', $args ) ) {
+ // parse the 'filters' arg
+ $filters = EDUtils::paramToArray( $args['filters'], true, false );
+ } else {
+ $filters = array();
+ }
+
+ self::setGlobalValuesArray( $external_values, $filters, $mappings );
+ }
+ /**
+ * Render the #get_soap_data parser function.
+ */
+ static function doGetSOAPData( &$parser ) {
+ global $edgCurPageName, $edgValues, $edgCacheExpireTime;
+
+ // If we're handling multiple pages, reset $edgValues
+ // when we move from one page to another.
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'url', $args ) ) {
+ $url = $args['url'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'url')->parse() );
+ }
+ $url = str_replace( ' ', '%20', $url ); // do some minor URL-encoding
+ // if the URL isn't allowed (based on a whitelist), exit
+ if ( ! EDUtils::isURLAllowed( $url ) ) {
+ return EDUtils::formatErrorMessage( "URL is not allowed" );
+ }
+
+ if ( array_key_exists( 'request', $args ) ) {
+ $requestName = $args['request'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'request')->parse() );
+ }
+
+ if ( array_key_exists( 'requestData', $args ) ) {
+ $requestData = EDUtils::paramToArray( $args['requestData'] );
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'requestData')->parse() );
+ }
+
+ if ( array_key_exists( 'response', $args ) ) {
+ $responseName = $args['response'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'response')->parse() );
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ $mappings = EDUtils::paramToArray( $args['data'] ); // parse the data arg into mappings
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ $external_values = EDUtils::getSOAPData( $url, $requestName, $requestData, $responseName, $mappings);
+ if ( is_string( $external_values ) ) {
+ // It's an error message - display it on the screen.
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+
+ self::setGlobalValuesArray( $external_values, array(), $mappings );
+ }
+
+ /**
+ * Render the #get_ldap_data parser function
+ */
+ static function doGetLDAPData( &$parser ) {
+ global $edgCurPageName, $edgValues;
+
+ // if we're handling multiple pages, reset $edgValues
+ // when we move from one page to another
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ if ( array_key_exists( 'data', $args ) ) {
+ $mappings = EDUtils::paramToArray( $args['data'] ); // parse the data arg into mappings
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'data')->parse() );
+ }
+
+ if ( !array_key_exists( 'filter', $args ) ) {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'filter')->parse() );
+ } elseif ( !array_key_exists( 'domain', $args ) ) {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'domain')->parse() );
+ } else {
+ $external_values = EDUtils::getLDAPData( $args['filter'], $args['domain'], array_values( $mappings ) );
+ }
+
+ // Build $edgValues
+ foreach ( $external_values as $i => $row ) {
+ if ( !is_array( $row ) ) {
+ continue;
+ }
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $row ) ) {
+ $edgValues[$local_var][] = $row[$external_var][0];
+ } else {
+ $edgValues[$local_var][] = '';
+ }
+ }
+ }
+ }
+
+ /**
+ * Render the #get_db_data parser function
+ */
+ static function doGetDBData( &$parser ) {
+ global $edgCurPageName, $edgValues;
+
+ // if we're handling multiple pages, reset $edgValues
+ // when we move from one page to another
+ $cur_page_name = $parser->getTitle()->getText();
+ if ( ! isset( $edgCurPageName ) || $edgCurPageName != $cur_page_name ) {
+ $edgValues = array();
+ $edgCurPageName = $cur_page_name;
+ }
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+ $data = ( array_key_exists( 'data', $args ) ) ? $args['data'] : null;
+ if ( array_key_exists( 'db', $args ) ) {
+ $dbID = $args['db'];
+ } elseif ( array_key_exists( 'server', $args ) ) {
+ // For backwards-compatibility - 'db' parameter was
+ // added in External Data version 1.3.
+ $dbID = $args['server'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'db' )->parse() );
+ }
+ if ( array_key_exists( 'from', $args ) ) {
+ $from = $args['from'];
+ } else {
+ return EDUtils::formatErrorMessage( wfMessage( 'externaldata-no-param-specified', 'from')->parse() );
+ }
+ $conds = ( array_key_exists( 'where', $args ) ) ? $args['where'] : null;
+ $limit = ( array_key_exists( 'limit', $args ) ) ? $args['limit'] : null;
+ $orderBy = ( array_key_exists( 'order by', $args ) ) ? $args['order by'] : null;
+ $groupBy = ( array_key_exists( 'group by', $args ) ) ? $args['group by'] : null;
+ $sqlOptions = array( 'LIMIT' => $limit, 'ORDER BY' => $orderBy, 'GROUP BY' => $groupBy );
+ $joinOn = ( array_key_exists( 'join on', $args ) ) ? $args['join on'] : null;
+ $otherParams = array();
+ if ( array_key_exists('aggregate', $args ) ) {
+ $otherParams['aggregate'] = $args['aggregate'];
+ } elseif ( array_key_exists( 'find query', $args ) ) {
+ $otherParams['find query'] = $args['find query'];
+ }
+ $mappings = EDUtils::paramToArray( $data ); // parse the data arg into mappings
+
+ $external_values = EDUtils::getDBData( $dbID, $from, array_values( $mappings ), $conds, $sqlOptions, $joinOn, $otherParams );
+
+ // Handle error cases.
+ if ( !is_array( $external_values ) ) {
+ return EDUtils::formatErrorMessage( $external_values );
+ }
+
+ // Build $edgValues.
+ foreach ( $mappings as $local_var => $external_var ) {
+ if ( array_key_exists( $external_var, $external_values ) ) {
+ foreach ( $external_values[$external_var] as $value ) {
+ $edgValues[$local_var][] = $value;
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the specified index of the array for the specified local
+ * variable retrieved by one of the #get... parser functions.
+ */
+ static function getIndexedValue( $var, $i ) {
+ global $edgValues;
+ if ( array_key_exists( $var, $edgValues ) && array_key_exists( $i, $edgValues[$var] ) ) {
+ return $edgValues[$var][$i];
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Render the #external_value parser function
+ */
+ static function doExternalValue( &$parser, $local_var = '' ) {
+ global $edgValues, $edgExternalValueVerbose;
+ if ( ! array_key_exists( $local_var, $edgValues ) ) {
+ return $edgExternalValueVerbose ? EDUtils::formatErrorMessage( "Error: no local variable \"$local_var\" was set." ) : '';
+ } elseif ( is_array( $edgValues[$local_var] ) ) {
+ return $edgValues[$local_var][0];
+ } else {
+ return $edgValues[$local_var];
+ }
+ }
+
+ /**
+ * Render the #for_external_table parser function
+ */
+ static function doForExternalTable( &$parser, $expression = '' ) {
+ global $edgValues;
+
+ // Get the variables used in this expression, get the number
+ // of values for each, and loop through.
+ $matches = array();
+ preg_match_all( '/{{{([^}]*)}}}/', $expression, $matches );
+ $variables = $matches[1];
+ $num_loops = 0;
+
+ $commands = array( "urlencode", "htmlencode" );
+ // Used for a regexp check.
+ $commandsStr = implode( '|', $commands );
+
+ foreach ( $variables as $variable ) {
+ // If it ends with one of the pre-defined "commands",
+ // ignore the command to get the actual variable name.
+ foreach ( $commands as $command ) {
+ $variable = str_replace( $command, '', $variable );
+ }
+ $variable = str_replace( '.urlencode', '', $variable );
+ if ( array_key_exists( $variable, $edgValues ) ) {
+ $num_loops = max( $num_loops, count( $edgValues[$variable] ) );
+ }
+ }
+
+ $text = "";
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ $cur_expression = $expression;
+ foreach ( $variables as $variable ) {
+ // If it ends with one of the pre-defined "commands",
+ // ignore the command to get the actual variable name.
+ $matches = array();
+ preg_match( "/([^.]*)\.?($commandsStr)?$/", $variable, $matches );
+
+ $real_var = $matches[1];
+ if ( count( $matches ) == 3 ) {
+ $command = $matches[2];
+ } else {
+ $command = null;
+ }
+
+ switch( $command ) {
+ case "htmlencode":
+ $value = htmlentities( self::getIndexedValue( $real_var, $i ), ENT_COMPAT | ENT_HTML401| ENT_SUBSTITUTE, null, false );
+ break;
+ case "urlencode":
+ $value = urlencode( self::getIndexedValue( $real_var, $i ) );
+ break;
+ default:
+ $value = self::getIndexedValue( $real_var, $i );
+ }
+
+ $cur_expression = str_replace( '{{{' . $variable . '}}}', $value, $cur_expression );
+ }
+ $text .= $cur_expression;
+ }
+ return $text;
+ }
+
+ /**
+ * Render the #display_external_table parser function
+ *
+ * @author Dan Bolser
+ */
+ static function doDisplayExternalTable( &$parser ) {
+ global $edgValues;
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser ...
+ $args = EDUtils::parseParams( $params ); // parse params into name-value pairs
+
+ if ( array_key_exists( 'template', $args ) ) {
+ $template = $args['template'];
+ } else {
+ return EDUtils::formatErrorMessage( "No template specified" );
+ }
+
+ if ( array_key_exists( 'data', $args ) ) {
+ // parse the 'data' arg into mappings
+ $mappings = EDUtils::paramToArray( $args['data'], false, false );
+ } else {
+ // or just use keys from edgValues
+ foreach ( $edgValues as $local_variable => $values ) {
+ $mappings[$local_variable] = $local_variable;
+ }
+ }
+
+ // The string placed in the wikitext between template calls -
+ // default is a newline.
+ if ( array_key_exists( 'delimiter', $args ) ) {
+ $delimiter = str_replace( '\n', "\n", $args['delimiter'] );
+ } else {
+ $delimiter = "\n";
+ }
+
+ $num_loops = 0; // May differ when multiple '#get_'s are used in one page
+ foreach ( $mappings as $template_param => $local_variable ) {
+ if ( !array_key_exists( $local_variable, $edgValues ) ) {
+ // Don't throw an error message - the source may just
+ // not publish this variable.
+ continue;
+ }
+ $num_loops = max( $num_loops, count( $edgValues[$local_variable] ) );
+ }
+
+ if ( array_key_exists( 'intro template', $args ) && $num_loops > 0) {
+ $text = '{{' . $args['intro template'] . '}}';
+ } else {
+ $text = "";
+ }
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ if ( $i > 0 ) {
+ $text .= $delimiter;
+ }
+ $text .= '{{' . $template;
+ foreach ( $mappings as $template_param => $local_variable ) {
+ $value = self::getIndexedValue( $local_variable, $i );
+ $text .= "|$template_param=$value";
+ }
+ $text .= "}}";
+ }
+ if ( array_key_exists( 'outro template', $args ) && $num_loops > 0 ) {
+ $text .= '{{' . $args['outro template'] . '}}';
+ }
+
+ // This actually 'calls' the template that we built above
+ return array( $text, 'noparse' => false );
+ }
+
+ /**
+ * Based on Semantic Internal Objects'
+ * SIOSubobjectHandler::doSetInternal().
+ */
+ public static function callSubobject( $parser, $params ) {
+ // This is a hack, since SMW's SMWSubobject::render() call is
+ // not meant to be called outside of SMW. However, this seemed
+ // like the better solution than copying over all of that
+ // method's code. Ideally, a true public function can be
+ // added to SMW, that handles a subobject creation, that this
+ // code can then call.
+
+ $subobjectArgs = array( &$parser );
+ // Blank first argument, so that subobject ID will be
+ // an automatically-generated random number.
+ $subobjectArgs[1] = '';
+ // "main" property, pointing back to the page.
+ $mainPageName = $parser->getTitle()->getText();
+ $mainPageNamespace = $parser->getTitle()->getNsText();
+ if ( $mainPageNamespace != '' ) {
+ $mainPageName = $mainPageNamespace . ':' . $mainPageName;
+ }
+ $subobjectArgs[2] = $params[0] . '=' . $mainPageName;
+
+ foreach ( $params as $i => $value ) {
+ if ( $i == 0 ) continue;
+ $subobjectArgs[] = $value;
+ }
+
+ // SMW 1.9+
+ $instance = \SMW\ParserFunctionFactory::newFromParser( $parser )->getSubobjectParser();
+ return $instance->parse( new SMW\ParserParameterFormatter( $subobjectArgs ) );
+ }
+
+ /**
+ * Render the #store_external_table parser function
+ */
+ static function doStoreExternalTable( &$parser ) {
+ global $edgValues;
+
+ $params = func_get_args();
+ array_shift( $params ); // we already know the $parser...
+
+ // Get the variables used in this expression, get the number
+ // of values for each, and loop through.
+ $expression = implode( '|', $params );
+ $matches = array();
+ preg_match_all( '/{{{([^}]*)}}}/', $expression, $matches );
+ $variables = $matches[1];
+ $num_loops = 0;
+ foreach ( $variables as $variable ) {
+ // ignore the presence of '.urlencode' - it's a command,
+ // not part of the actual variable name
+ $variable = str_replace( '.urlencode', '', $variable );
+ if ( array_key_exists( $variable, $edgValues ) ) {
+ $num_loops = max( $num_loops, count( $edgValues[$variable] ) );
+ }
+ }
+ $text = "";
+ for ( $i = 0; $i < $num_loops; $i++ ) {
+ // re-get $params
+ $params = func_get_args();
+ array_shift( $params );
+ foreach ( $params as $j => $param ) {
+ foreach ( $variables as $variable ) {
+ // If variable name ends with a ".urlencode",
+ // that's a command - URL-encode the value of
+ // the actual variable.
+ if ( strrpos( $variable, '.urlencode' ) === strlen( $variable ) - strlen( '.urlencode' ) ) {
+ $real_var = str_replace( '.urlencode', '', $variable );
+ $value = urlencode( self::getIndexedValue( $real_var , $i ) );
+ } else {
+ $value = self::getIndexedValue( $variable , $i );
+ }
+ $params[$j] = str_replace( '{{{' . $variable . '}}}', $value, $params[$j] );
+ }
+ }
+
+ self::callSubobject( $parser, $params );
+ }
+ return null;
+ }
+
+ /**
+ * Render the #clear_external_data parser function
+ */
+ static function doClearExternalData( &$parser ) {
+ global $edgValues;
+ $edgValues = array();
+ }
+}
diff --git a/www/wiki/extensions/ExternalData/includes/ED_Utils.php b/www/wiki/extensions/ExternalData/includes/ED_Utils.php
new file mode 100644
index 00000000..dc0ee222
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/includes/ED_Utils.php
@@ -0,0 +1,1071 @@
+<?php
+/**
+ * Utility functions for External Data
+ */
+
+class EDUtils {
+ // how many times to try an HTTP request
+ private static $http_number_of_tries = 3;
+
+ private static $ampersandReplacement = "THIS IS A LONG STRING USED AS A REPLACEMENT FOR AMPERSANDS 55555555";
+
+ /**
+ * Wraps error message in a span with the "error" class, for better
+ * display, and so that it can be handled correctly by #iferror and
+ * possibly others.
+ */
+ static function formatErrorMessage( $msg ) {
+ return '<span class="error">' . $msg . '</span>';
+ }
+
+ // XML-handling functions based on code found at
+ // http://us.php.net/xml_set_element_handler
+ static function startElement( $parser, $name, $attrs ) {
+ global $edgCurrentXMLTag, $edgCurrentValue, $edgXMLValues;
+ // set to all lowercase to avoid casing issues
+ $edgCurrentXMLTag = strtolower( $name );
+ $edgCurrentValue = '';
+ foreach ( $attrs as $attr => $value ) {
+ $attr = strtolower( $attr );
+ $value = str_replace( self::$ampersandReplacement, '&amp;', $value );
+ if ( array_key_exists( $attr, $edgXMLValues ) ) {
+ $edgXMLValues[$attr][] = $value;
+ } else {
+ $edgXMLValues[$attr] = array( $value );
+ }
+ }
+ }
+
+ static function endElement( $parser, $name ) {
+ global $edgCurrentXMLTag, $edgCurrentValue, $edgXMLValues;
+
+ if ( array_key_exists( $edgCurrentXMLTag, $edgXMLValues ) ) {
+ $edgXMLValues[$edgCurrentXMLTag][] = $edgCurrentValue;
+ } else {
+ $edgXMLValues[$edgCurrentXMLTag] = array( $edgCurrentValue );
+ }
+ // Clear the value both here and in startElement(), in case this
+ // is an embedded tag.
+ $edgCurrentValue = '';
+ }
+
+ /**
+ * Due to the strange way xml_set_character_data_handler() runs,
+ * getContent() may get called multiple times, once for each fragment
+ * of the text, for very long XML values. Given that, we keep a global
+ * variable with the current value and add to it.
+ */
+ static function getContent( $parser, $content ) {
+ global $edgCurrentValue;
+
+ // Replace ampersands, to avoid the XML getting split up
+ // around them.
+ // Note that this is *escaped* ampersands being replaced -
+ // this is unrelated to the fact that bare ampersands aren't
+ // allowed in XML.
+ $content = str_replace( self::$ampersandReplacement, '&amp;', $content );
+ $edgCurrentValue .= $content;
+ }
+
+ static function parseParams( $params ) {
+ $args = array();
+ foreach ( $params as $param ) {
+ $param = preg_replace ( "/\s\s+/", ' ', $param ); // whitespace
+ $param_parts = explode( "=", $param, 2 );
+ if ( count( $param_parts ) < 2 ) {
+ $args[$param_parts[0]] = null;
+ } else {
+ list( $name, $value ) = $param_parts;
+ $args[$name] = $value;
+ }
+ }
+ return $args;
+ }
+
+ /**
+ * Parses an argument of the form "a=b,c=d,..." into an array
+ */
+ static function paramToArray( $arg, $lowercaseKeys = false, $lowercaseValues = false ) {
+ $arg = preg_replace ( "/\s\s+/", ' ', $arg ); // whitespace
+
+ // Split text on commas, except for commas found within quotes
+ // and parentheses. Regular expression based on:
+ // http://stackoverflow.com/questions/1373735/regexp-split-string-by-commas-and-spaces-but-ignore-the-inside-quotes-and-parent#1381895
+ // ...with modifications by Nick Lindridge, ionCube Ltd.
+ $pattern = <<<END
+ /
+ [,]
+ (?=(?:(?:[^"]*"){2})*[^"]*$)
+ (?=(?:(?:[^']*'){2})*[^']*$)
+ (?=(?:[^()]*+\([^()]*+\))*+[^()]*+$)
+ /x
+END;
+ // " - fix for color highlighting in vi :)
+ $keyValuePairs = preg_split( $pattern, $arg );
+
+ $returnArray = array();
+ foreach ( $keyValuePairs as $keyValuePair ) {
+ $keyAndValue = explode( '=', $keyValuePair, 2 );
+ if ( count( $keyAndValue ) == 2 ) {
+ $key = trim( $keyAndValue[0] );
+ if ( $lowercaseKeys ) {
+ $key = strtolower( $key );
+ }
+ $value = trim( $keyAndValue[1] );
+ if ( $lowercaseValues ) {
+ $value = strtolower( $value );
+ }
+ $returnArray[$key] = $value;
+ }
+ }
+ return $returnArray;
+ }
+
+ static function getLDAPData( $filter, $domain, $params ) {
+ global $edgLDAPServer;
+ global $edgLDAPUser;
+ global $edgLDAPPass;
+
+ $ds = self::connectLDAP( $edgLDAPServer[$domain], $edgLDAPUser[$domain], $edgLDAPPass[$domain] );
+ $results = self::searchLDAP( $ds, $domain, $filter, $params );
+
+ return $results;
+ }
+
+ static function connectLDAP( $server, $username, $password ) {
+ $ds = ldap_connect( $server );
+ if ( $ds ) {
+ // these options for Active Directory only?
+ ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 );
+ ldap_set_option( $ds, LDAP_OPT_REFERRALS, 0 );
+
+ if ( $username ) {
+ $r = ldap_bind( $ds, $username, $password );
+ } else {
+ # no username, so do anonymous bind
+ $r = ldap_bind( $ds );
+ }
+
+ # should check the result of the bind here
+ return $ds;
+ } else {
+ echo wfMessage( "externaldata-ldap-unable-to-connect", $server )->text();
+ }
+ }
+
+ static function searchLDAP( $ds, $domain, $filter, $attributes ) {
+ global $edgLDAPBaseDN;
+
+ $sr = ldap_search( $ds, $edgLDAPBaseDN[$domain], $filter, $attributes );
+ $results = ldap_get_entries( $ds, $sr );
+ return $results;
+ }
+
+ static function getArrayValue( $arrayName, $key ) {
+ if ( array_key_exists( $key, $arrayName ) ) {
+ return $arrayName[$key];
+ } else {
+ return null;
+ }
+ }
+
+ static function getDBData( $dbID, $from, $columns, $where, $sqlOptions, $joinOn, $otherParams ) {
+ global $edgDBServerType;
+ global $edgDBServer;
+ global $edgDBDirectory;
+ global $edgDBName;
+ global $edgDBUser;
+ global $edgDBPass;
+ global $edgDBFlags;
+ global $edgDBTablePrefix;
+
+ // Get all possible parameters
+ $db_type = self::getArrayValue( $edgDBServerType, $dbID );
+ $db_server = self::getArrayValue( $edgDBServer, $dbID );
+ $db_directory = self::getArrayValue( $edgDBDirectory, $dbID );
+ $db_name = self::getArrayValue( $edgDBName, $dbID );
+ $db_username = self::getArrayValue( $edgDBUser, $dbID );
+ $db_password = self::getArrayValue( $edgDBPass, $dbID );
+ $db_flags = self::getArrayValue( $edgDBFlags, $dbID );
+ $db_tableprefix = self::getArrayValue( $edgDBTablePrefix, $dbID );
+
+ // MongoDB has entirely different handling from the rest.
+ if ( $db_type == 'mongodb' ) {
+ if ( $db_name == '' ) {
+ return wfMessage( "externaldata-db-incomplete-information" )->text();
+ }
+ return self::getMongoDBData( $db_server, $db_username, $db_password, $db_name, $from, $columns, $where, $sqlOptions, $otherParams );
+ }
+
+ // Validate parameters
+ if ( $db_type == '' ) {
+ return wfMessage( "externaldata-db-incomplete-information" )->text();
+ } elseif ( $db_type == 'sqlite' ) {
+ if ( $db_directory == '' || $db_name == '' ) {
+ return wfMessage( "externaldata-db-incomplete-information" )->text();
+ }
+ } else {
+ // We don't check the username or password because they
+ // could legitimately be blank or null.
+ if ( $db_server == '' || $db_name == '' ) {
+ return wfMessage( "externaldata-db-incomplete-information" )->text();
+ }
+ }
+
+ if ( $db_flags == '' ) {
+ $db_flags = DBO_DEFAULT;
+ }
+
+ $dbConnectionParams = array(
+ 'host' => $db_server,
+ 'user' => $db_username,
+ 'password' => $db_password,
+ 'dbname' => $db_name,
+ 'flags' => $db_flags,
+ 'tablePrefix' => $db_tableprefix,
+ );
+ if ( $db_type == 'sqlite' ) {
+ $dbConnectionParams['dbDirectory'] = $db_directory;
+ }
+
+ // DatabaseBase::factory() was replaced by Database::factory()
+ // in MW 1.28.
+ if ( method_exists( 'Database', 'factory' ) ) {
+ $db = Database::factory( $db_type, $dbConnectionParams );
+ } else {
+ $db = DatabaseBase::factory( $db_type, $dbConnectionParams );
+ }
+
+ if ( $db == null ) {
+ return wfMessage( "externaldata-db-unknown-type" )->text();
+ }
+
+ if ( ! $db->isOpen() ) {
+ return wfMessage( "externaldata-db-could-not-connect" )->text();
+ }
+
+ if ( count( $columns ) == 0 ) {
+ return wfMessage( "externaldata-db-no-return-values" )->text();
+ }
+
+ $rows = self::searchDB( $db, $from, $columns, $where, $sqlOptions, $joinOn );
+ $db->close();
+
+ if ( !is_array( $rows ) ) {
+ // It's an error message.
+ return $rows;
+ }
+
+ $values = array();
+ foreach ( $rows as $row ) {
+ foreach ( $columns as $column ) {
+ $values[$column][] = $row[$column];
+ }
+ }
+
+ return $values;
+ }
+
+ static function getValueFromJSONArray( array $origArray, $path, $default = null ) {
+ $current = $origArray;
+ $token = strtok( $path, '.' );
+
+ while ( $token !== false ) {
+ if ( !isset( $current[$token] ) ) {
+ return $default;
+ }
+ $current = $current[$token];
+ $token = strtok( '.' );
+ }
+ return $current;
+ }
+
+ /**
+ * Handles #get_db_data for the non-relational database system
+ * MongoDB.
+ */
+ static function getMongoDBData( $db_server, $db_username, $db_password, $db_name, $from, $columns, $where, $sqlOptions, $otherParams ) {
+ global $wgMainCacheType, $wgMemc, $edgMemCachedMongoDBSeconds;
+
+ // Use MEMCACHED if configured to cache mongodb queries.
+ if ($wgMainCacheType === CACHE_MEMCACHED && $edgMemCachedMongoDBSeconds > 0) {
+ // Check if cache entry exists.
+ $mckey = wfMemcKey( 'mongodb', $from, md5(json_encode($otherParams) . json_encode($columns) . $where . json_encode($sqlOptions) . $db_name . $db_server));
+ $values = $wgMemc->get( $mckey );
+
+ if ($values !== false) {
+ return $values;
+ }
+ }
+
+ // MongoDB login is done using a single string.
+ // When specifying extra connect string options (e.g. replicasets,timeout, etc.),
+ // use $db_server to pass these values
+ // see http://docs.mongodb.org/manual/reference/connection-string
+ $connect_string = "mongodb://";
+ if ( $db_username != '' ) {
+ $connect_string .= $db_username . ':' . $db_password . '@';
+ }
+ if ( $db_server != '') {
+ $connect_string .= $db_server;
+ } else {
+ $connect_string .= 'localhost:27017';
+ }
+
+ // Use try/catch to suppress error messages, which would show
+ // the MongoDB connect string, which may have sensitive
+ // information.
+ try {
+ $m = new MongoClient( $connect_string );
+ } catch ( Exception $e ) {
+ return wfMessage( "externaldata-db-could-not-connect" )->text();
+ }
+
+ $db = $m->selectDB( $db_name );
+
+ // Check if collection exists
+ if ( $db->system->namespaces->findOne( array( 'name'=>$db_name . "." . $from ) ) === null ){
+ return wfMessage( "externaldata-db-unknown-collection:")->text() . $db_name . "." . $from;
+ }
+
+ $collection = new MongoCollection( $db, $from );
+
+ $findArray = array();
+ $aggregateArray = array();
+ // Was an aggregation pipeline command issued?
+ if ( array_key_exists('aggregate', $otherParams ) ) {
+ // The 'aggregate' parameter should be an array of
+ // aggregation JSON pipeline commands.
+ // Note to users: be sure to use spaces between curly
+ // brackets in the 'aggregate' JSON so as not to trip up the
+ // MW parser.
+ $aggregateArray = json_decode ($otherParams['aggregate'], true);
+ } elseif ( array_key_exists( 'find query', $otherParams ) ) {
+ // Otherwise, was a direct MongoDB "find" query JSON string provided?
+ // If so, use that. As with 'aggregate' JSON, use spaces
+ // between curly brackets
+ $findArray = json_decode ($otherParams['find query'], true);
+ } elseif ( $where != '' ) {
+ // If not, turn the SQL of the "where=" parameter into
+ // a "find" array for MongoDB. Note that this approach
+ // is only appropriate for simple find queries, that
+ // use the operators OR, AND, >=, >, <=, < and LIKE
+ // - and NO NUMERIC LITERALS.
+ $where = str_ireplace( ' and ', ' AND ', $where );
+ $where = str_ireplace( ' like ', ' LIKE ', $where );
+ $whereElements = explode( ' AND ', $where );
+ foreach ( $whereElements as $whereElement ) {
+ if ( strpos( $whereElement, '>=' ) ) {
+ list( $fieldName, $value ) = explode( '>=', $whereElement );
+ $findArray[trim( $fieldName )] = array( '$gte' => trim( $value ) );
+ } elseif ( strpos( $whereElement, '>' ) ) {
+ list( $fieldName, $value ) = explode( '>', $whereElement );
+ $findArray[trim( $fieldName )] = array( '$gt' => trim( $value ) );
+ } elseif ( strpos( $whereElement, '<=' ) ) {
+ list( $fieldName, $value ) = explode( '<=', $whereElement );
+ $findArray[trim( $fieldName )] = array( '$lte' => trim( $value ) );
+ } elseif ( strpos( $whereElement, '<' ) ) {
+ list( $fieldName, $value ) = explode( '<', $whereElement );
+ $findArray[trim( $fieldName )] = array( '$lt' => trim( $value ) );
+ } elseif ( strpos( $whereElement, ' LIKE ' ) ) {
+ list( $fieldName, $value ) = explode( ' LIKE ', $whereElement );
+ $value = trim( $value );
+ $regex = new MongoRegex( "/$value/i" );
+ $findArray[trim( $fieldName )] = $regex;
+ } else {
+ list( $fieldName, $value ) = explode( '=', $whereElement );
+ $findArray[trim( $fieldName )] = trim( $value );
+ }
+ }
+ }
+
+ // Do the same for the "order=" parameter as the "where=" parameter
+ $sortArray = array();
+ if ( $sqlOptions['ORDER BY'] != '' ) {
+ $sortElements = explode( ',', $sqlOptions['ORDER BY'] );
+ foreach ( $sortElements as $sortElement ) {
+ $parts = explode( ' ', $sortElement );
+ $fieldName = $parts[0];
+ $orderingNum = 1;
+ if ( count( $parts ) > 1 ) {
+ if ( strtolower( $parts[1] ) == 'desc' ) {
+ $orderingNum = -1;
+ }
+ }
+ $sortArray[$fieldName] = $orderingNum;
+ }
+ }
+
+ // Get the data!
+ if ( array_key_exists( 'aggregate', $otherParams ) ) {
+ if ( $sqlOptions['ORDER BY'] != '') {
+ $aggregateArray[] = array( '$sort' => $sortArray );
+ }
+ if ( $sqlOptions['LIMIT'] != '' ) {
+ $aggregateArray[] = array( '$limit' => intval( $sqlOptions['LIMIT'] ) );
+ }
+ $aggregateResult = $collection->aggregate( $aggregateArray );
+ $resultsCursor = $aggregateResult['result'];
+ } else {
+ $resultsCursor = $collection->find( $findArray, $columns )->sort( $sortArray )->limit( $sqlOptions['LIMIT'] );
+ }
+
+ $values = array();
+ foreach ( $resultsCursor as $doc ) {
+ foreach ( $columns as $column ) {
+ if ( strstr($column, ".") ) {
+ // If the exact path of the value was
+ // specified using dots (e.g., "a.b.c"),
+ // get the value that way.
+ $values[$column][] = self::getValueFromJSONArray( $doc, $column );
+ } elseif ( isset( $doc[$column] ) && is_array( $doc[$column] ) ) {
+ // If MongoDB returns an array for a column,
+ // but the exact location of the value wasn't specified,
+ // do some extra processing.
+ if ( $column == 'geometry' && array_key_exists( 'coordinates', $doc['geometry'] ) ) {
+ // Check if it's GeoJSON geometry:
+ // http://www.geojson.org/geojson-spec.html#geometry-objects
+ // If so, return it in a format that
+ // the Maps extension can understand.
+ $coordinates = $doc['geometry']['coordinates'][0];
+ $coordinateStrings = array();
+ foreach ( $coordinates as $coordinate ) {
+ $coordinateStrings[] = $coordinate[1] . ',' . $coordinate[0];
+ }
+ $values[$column][] = implode( ':', $coordinateStrings );
+ } else {
+ // Just return it as JSON, the
+ // lingua franca of MongoDB.
+ $values[$column][] = json_encode( $doc[$column] );
+ }
+ } else {
+ // It's a simple literal.
+ $values[$column][] = (isset( $doc[$column] ) ? $doc[$column] : null);
+ }
+ }
+ }
+
+ if ($wgMainCacheType === CACHE_MEMCACHED && $edgMemCachedMongoDBSeconds > 0 ) {
+ $wgMemc->set( $mckey, $values, $edgMemCachedMongoDBSeconds );
+ }
+
+ return $values;
+ }
+
+ static function searchDB( $db, $from, $vars, $conds, $sqlOptions, $joinOn ) {
+ // The format of $from can be just "TableName", or the more
+ // complex "Table1=Alias1,Table2=Alias2,...".
+ $tables = array();
+ $tableStrings = explode( ',', $from );
+ foreach ( $tableStrings as $tableString ) {
+ if ( strpos( $tableString, '=' ) !== false ) {
+ $tableStringParts = explode( '=', $tableString, 2 );
+ $tableName = trim( $tableStringParts[0] );
+ $alias = trim( $tableStringParts[1] );
+ } else {
+ $tableName = $alias = trim( $tableString);
+ }
+ $tables[$alias] = $tableName;
+ }
+ $joinConds = array();
+ $joinStrings = explode( ',', $joinOn );
+ foreach ( $joinStrings as $i => $joinString ) {
+ if ( $joinString == '' ) {
+ continue;
+ }
+ if ( strpos( $joinString, '=' ) === false ) {
+ return "Error: every \"join on\" string must contain an \"=\" sign.";
+ }
+ if ( count( $tables ) <= $i + 1 ) {
+ return "Error: too many \"join on\" conditions.";
+ }
+ $aliases = array_keys( $tables );
+ $alias = $aliases[$i + 1];
+ $joinConds[$alias] = array( 'JOIN', $joinString );
+ }
+ $result = $db->select( $tables, $vars, $conds, 'EDUtils::searchDB', $sqlOptions, $joinConds );
+ if ( !$result ) {
+ return wfMessage( "externaldata-db-invalid-query" )->text();
+ }
+
+ $rows = array();
+ while ( $row = $db->fetchRow( $result ) ) {
+ // Create a new row object that uses the passed-in
+ // column names as keys, so that there's always an
+ // exact match between what's in the query and what's
+ // in the return value (so that "a.b", for instance,
+ // doesn't get chopped off to just "b").
+ $new_row = array();
+ foreach ( $vars as $i => $column_name ) {
+ $dbField = $row[$i];
+ // This can happen with MSSQL.
+ if ( $dbField instanceof DateTime ) {
+ $dbField = $dbField->format('Y-m-d H:i:s');
+ }
+ // Convert the encoding to UTF-8
+ // if necessary - based on code at
+ // http://www.php.net/manual/en/function.mb-detect-encoding.php#102510
+ if ( !function_exists( 'mb_detect_encoding' ) ||
+ mb_detect_encoding( $dbField, 'UTF-8', true ) == 'UTF-8' ) {
+ $new_row[$column_name] = $dbField;
+ } else {
+ $new_row[$column_name] = utf8_encode( $dbField );
+ }
+ }
+ $rows[] = $new_row;
+ }
+ return $rows;
+ }
+
+ static function getXMLData( $xml ) {
+ global $edgXMLValues;
+ $edgXMLValues = array();
+
+ // Remove comments from XML - for some reason, xml_parse()
+ // can't handle them.
+ $xml = preg_replace( '/<!--.*?-->/s', '', $xml );
+
+ // Also, re-insert ampersands, after they were removed to
+ // avoid parsing problems.
+ $xml = str_replace( '&amp;', self::$ampersandReplacement, $xml );
+
+ $xml_parser = xml_parser_create();
+ xml_set_element_handler( $xml_parser, array( 'EDUtils', 'startElement' ), array( 'EDUtils', 'endElement' ) );
+ xml_set_character_data_handler( $xml_parser, array( 'EDUtils', 'getContent' ) );
+ if ( !xml_parse( $xml_parser, $xml, true ) ) {
+ return wfMessage( 'externaldata-xml-error',
+ xml_error_string( xml_get_error_code( $xml_parser ) ),
+ xml_get_current_line_number( $xml_parser ) )->text();
+ }
+ xml_parser_free( $xml_parser );
+ return $edgXMLValues;
+ }
+
+ static function isNodeNotEmpty( $node ) {
+ return trim( $node[0] ) != '';
+ }
+
+ static function filterEmptyNodes( $nodes ) {
+ if ( !is_array( $nodes ) ) return $nodes;
+ return array_filter( $nodes, array( 'EDUtils', 'isNodeNotEmpty' ) );
+ }
+
+ static function getXPathData( $xml, $mappings, $ns ) {
+ global $edgXMLValues;
+
+ try {
+ $sxml = new SimpleXMLElement( $xml );
+ } catch ( Exception $e ) {
+ return "Caught exception parsing XML: " . $e->getMessage();
+ }
+ $edgXMLValues = array();
+
+ foreach ( $mappings as $local_var => $xpath ) {
+ // First, register any necessary XML namespaces, to
+ // avoid "Undefined namespace prefix" errors.
+ $matches = array();
+ preg_match_all( '/[\/\@]([a-zA-Z0-9]*):/', $xpath, $matches );
+ foreach ( $matches[1] as $namespace ) {
+ $sxml->registerXPathNamespace( $namespace, $ns );
+ }
+
+ // Now, get all the matching values, and remove any
+ // empty results.
+ $nodes = self::filterEmptyNodes( $sxml->xpath( $xpath ) );
+ if ( !$nodes ) {
+ continue;
+ }
+
+ // Convert from SimpleXMLElement to string.
+ $nodesArray = array();
+ foreach ( $nodes as $xmlNode ) {
+ $nodesArray[] = (string)$xmlNode;
+ }
+
+ if ( array_key_exists( $xpath, $edgXMLValues ) ) {
+ // At the moment, this code will never get
+ // called, because duplicate values in
+ // $mappings will have been removed already.
+ $edgXMLValues[$xpath] = array_merge( $edgXMLValues[$xpath], $nodesArray );
+ } else {
+ $edgXMLValues[$xpath] = $nodesArray;
+ }
+ }
+ return $edgXMLValues;
+ }
+
+ static function getValuesFromCSVLine( $csv_line ) {
+ // regular expression copied from http://us.php.net/fgetcsv
+ $vals = preg_split( '/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/', $csv_line );
+ $vals2 = array();
+ foreach ( $vals as $val ) {
+ $vals2[] = trim( $val, '"' );
+ }
+ return $vals2;
+ }
+
+ static function getCSVData( $csv, $has_header, $delimiter = ',' ) {
+ // from http://us.php.net/manual/en/function.str-getcsv.php#88311
+ // str_getcsv() is a function that was only added in PHP 5.3.0,
+ // so use the much older fgetcsv() if it's not there
+
+ // actually, for now, always use fgetcsv(), since this call to
+ // str_getcsv() doesn't work, and I can't test/debug it at the
+ // moment
+ //if ( function_exists( 'str_getcsv' ) ) {
+ // $table = str_getcsv( $csv );
+ //} else {
+ $fiveMBs = 5 * 1024 * 1024;
+ $fp = fopen( "php://temp/maxmemory:$fiveMBs", 'r+' );
+ fputs( $fp, $csv );
+ rewind( $fp );
+ $table = array();
+ while ( $line = fgetcsv( $fp, 0, $delimiter ) ) {
+ array_push( $table, $line );
+ }
+ fclose( $fp );
+ //}
+
+ // Get rid of blank characters - these sometimes show up
+ // for certain encodings.
+ foreach( $table as $i => $row ) {
+ foreach ( $row as $j => $cell ) {
+ $table[$i][$j] = str_replace( chr(0), '', $cell );
+ }
+ }
+
+ // Get rid of the "byte order mark", if it's there - it could
+ // be one of a variety of options, depending on the encoding.
+ // Code copied in part from:
+ // http://artur.ejsmont.org/blog/content/annoying-utf-byte-order-marks
+ $sets = array(
+ "\xFE",
+ "\xFF",
+ "\xFE\xFF",
+ "\xFF\xFE",
+ "\xEF\xBB\xBF",
+ "\x2B\x2F\x76",
+ "\xF7\x64\x4C",
+ "\x0E\xFE\xFF",
+ "\xFB\xEE\x28",
+ "\x00\x00\xFE\xFF",
+ "\xDD\x73\x66\x73",
+ );
+ $decodedFirstCell = utf8_decode( $table[0][0] );
+ foreach ( $sets as $set ) {
+ if ( 0 == strncmp( $decodedFirstCell, $set, strlen( $set ) ) ) {
+ $table[0][0] = substr( $decodedFirstCell, strlen( $set ) + 1 );
+ break;
+ }
+ }
+
+ // Another "byte order mark" test, this one copied from the
+ // Data Transfer extension - somehow the first one doesn't work
+ // in all cases.
+ $byteOrderMark = pack( "CCC", 0xef, 0xbb, 0xbf );
+ if ( 0 == strncmp( $table[0][0], $byteOrderMark, 3 ) ) {
+ $table[0][0] = substr( $table[0][0], 3 );
+ }
+
+ // Get header values, if this is 'csv with header'
+ if ( $has_header ) {
+ $header_vals = array_shift( $table );
+ // On the off chance that there are one or more blank
+ // lines at the beginning, cycle through.
+ while ( count( $header_vals ) == 0 ) {
+ $header_vals = array_shift( $table );
+ }
+ }
+
+ // Unfortunately, some subpar CSV generators don't include
+ // trailing commas, so that a line that should look like
+ // "A,B,,," instead is just printed as "A,B".
+ // To get around this, we first figure out the correct number
+ // of columns in this table - which depends on whether the
+ // CSV has a header or not.
+ if ( $has_header ) {
+ $num_columns = count( $header_vals );
+ } else {
+ $num_columns = 0;
+ foreach ( $table as $line ) {
+ $num_columns = max( $num_columns, count( $line ) );
+ }
+ }
+
+ // Now "flip" the data, turning it into a column-by-column
+ // array, instead of row-by-row.
+ $values = array();
+ foreach ( $table as $line ) {
+ for ( $i = 0; $i < $num_columns; $i++ ) {
+ // This check is needed in case it's an
+ // uneven CSV file (see above).
+ if ( array_key_exists( $i, $line ) ) {
+ $row_val = trim( $line[$i] );
+ } else {
+ $row_val = '';
+ }
+ if ( $has_header ) {
+ $column = strtolower( trim( $header_vals[$i] ) );
+ } else {
+ // start with an index of 1 instead of 0
+ $column = $i + 1;
+ }
+ if ( array_key_exists( $column, $values ) ) {
+ $values[$column][] = $row_val;
+ } else {
+ $values[$column] = array( $row_val );
+ }
+ }
+ }
+ return $values;
+ }
+
+ /**
+ * This function handles version 3 of the genomic-data format GFF,
+ * defined here:
+ * http://www.sequenceontology.org/gff3.shtml
+ */
+ static function getGFFData( $gff ) {
+ // use an fgetcsv() call, similar to the one in getCSVData()
+ // (fgetcsv() can handle delimiters other than commas, in this
+ // case a tab)
+ $fiveMBs = 5 * 1024 * 1024;
+ $fp = fopen( "php://temp/maxmemory:$fiveMBs", 'r+' );
+ fputs( $fp, $gff );
+ rewind( $fp );
+ $table = array();
+ while ( $line = fgetcsv( $fp, null, "\t" ) ) {
+ // ignore comment lines
+ if ( strpos( $line[0], '##' ) !== 0 ) {
+ // special handling for final 'attributes' column
+ if ( array_key_exists( 8, $line ) ) {
+ $attributes = explode( ';', $line[8] );
+ foreach ( $attributes as $attribute ) {
+ $keyAndValue = explode( '=', $attribute, 2 );
+ if ( count( $keyAndValue ) == 2 ) {
+ $key = strtolower( $keyAndValue[0] );
+ $value = $keyAndValue[1];
+ $line[$key] = $value;
+ }
+ }
+ }
+ array_push( $table, $line );
+ }
+ }
+ fclose( $fp );
+
+ $values = array();
+ foreach ( $table as $line ) {
+ foreach ( $line as $i => $row_val ) {
+ // each of the columns in GFF have a
+ // pre-defined name - even the last column
+ // has its own name, "attributes"
+ if ( $i === 0 ) {
+ $column = 'seqid';
+ } elseif ( $i == 1 ) {
+ $column = 'source';
+ } elseif ( $i == 2 ) {
+ $column = 'type';
+ } elseif ( $i == 3 ) {
+ $column = 'start';
+ } elseif ( $i == 4 ) {
+ $column = 'end';
+ } elseif ( $i == 5 ) {
+ $column = 'score';
+ } elseif ( $i == 6 ) {
+ $column = 'strand';
+ } elseif ( $i == 7 ) {
+ $column = 'phase';
+ } elseif ( $i == 8 ) {
+ $column = 'attributes';
+ } else {
+ // this is hopefully an attribute key
+ $column = $i;
+ }
+ if ( array_key_exists( $column, $values ) ) {
+ $values[$column][] = $row_val;
+ } else {
+ $values[$column] = array( $row_val );
+ }
+ }
+ }
+ return $values;
+ }
+
+ /**
+ * Helper function that determines whether an array holds a simple
+ * list of scalar values, with no keys (i.e., not an associative
+ * array).
+ */
+ static function holdsSimpleList( $arr ) {
+ $expectedKey = 0;
+ foreach( $arr as $key => $val ) {
+ if ( is_array( $val ) || $key != $expectedKey++ ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Recursive JSON-parsing function for use by getJSONData().
+ */
+ static function parseTree( $tree, &$retrieved_values ) {
+ foreach ( $tree as $key => $val ) {
+ // TODO - this logic could probably be a little nicer.
+ if ( is_array( $val ) && self::holdsSimpleList( $val ) ) {
+ // If it just holds a simple list, turn the
+ // array into a comma-separated list, then
+ // pass it back in in order to do the final // processing.
+ $val = array( $key => implode( ', ', $val ) );
+ self::parseTree( $val, $retrieved_values );
+ } elseif ( is_array( $val ) && count( $val ) > 1 ) {
+ self::parseTree( $val, $retrieved_values );
+ } elseif ( is_array( $val ) && count( $val ) == 1 && is_array( current( $val ) ) ) {
+ self::parseTree( current( $val ), $retrieved_values );
+ } else {
+ // If it's an array with just one element,
+ // treat it like a regular value.
+ // (Why is the null check necessary?)
+ if ( $val != null && is_array( $val ) ) {
+ $val = current( $val );
+ }
+ $key = strtolower( $key );
+ if ( array_key_exists( $key, $retrieved_values ) ) {
+ $retrieved_values[$key][] = $val;
+ } else {
+ $retrieved_values[$key] = array( $val );
+ }
+ }
+ }
+ }
+
+ static function getJSONData( $json, $prefixLength ) {
+ $json = substr( $json, $prefixLength );
+ $json_tree = FormatJson::decode( $json, true );
+ if ( is_null( $json_tree ) ) {
+ // It's probably invalid JSON.
+ return wfMessage( 'externaldata-invalid-json' )->text();
+ }
+ $values = array();
+ if ( is_array( $json_tree ) ) {
+ self::parseTree( $json_tree, $values );
+ }
+ return $values;
+ }
+
+ static function fetchURL( $url, $post_vars = array(), $cacheExpireTime = 0, $get_fresh = false, $try_count = 1 ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ global $edgStringReplacements, $edgCacheTable, $edgAllowSSL;
+
+ if ( $post_vars ) {
+ return Http::post( $url, array( 'postData' => $post_vars ) );
+ }
+
+ // do any special variable replacements in the URLs, for
+ // secret API keys and the like
+ foreach ( $edgStringReplacements as $key => $value ) {
+ $url = str_replace( $key, $value, $url );
+ }
+
+ if ( !isset( $edgCacheTable ) || is_null( $edgCacheTable ) ) {
+ if ( $edgAllowSSL ) {
+ $contents = Http::get( $url, 'default', array( 'sslVerifyCert' => false, 'followRedirects' => false ) );
+ } else {
+ $contents = Http::get( $url );
+ }
+ // Handle non-UTF-8 encodings.
+ // Copied from http://www.php.net/manual/en/function.file-get-contents.php#85008
+ // Unfortunately, 'mbstring' functions are not available
+ // in all PHP installations.
+ if ( function_exists( 'mb_convert_encoding' ) ) {
+ $contents = mb_convert_encoding( $contents, 'UTF-8',
+ mb_detect_encoding( $contents, 'UTF-8, ISO-8859-1', true ) );
+ }
+ return $contents;
+ }
+
+ // check the cache (only the first 254 chars of the url)
+ $row = $dbr->selectRow( $edgCacheTable, '*', array( 'url' => substr( $url, 0, 254 ) ), 'EDUtils::fetchURL' );
+
+ if ( $row && ( ( time() - $row->req_time ) > $cacheExpireTime ) ) {
+ $get_fresh = true;
+ }
+
+ if ( !$row || $get_fresh ) {
+ if ( $edgAllowSSL ) {
+ $page = Http::get( $url, 'default', array( CURLOPT_SSL_VERIFYPEER => false ) );
+ } else {
+ $page = Http::get( $url );
+ }
+ if ( $page === false ) {
+ sleep( 1 );
+ if ( $try_count >= self::$http_number_of_tries ) {
+ echo wfMessage( 'externaldata-db-could-not-get-url', self::$http_number_of_tries )->text();
+ return '';
+ }
+ $try_count++;
+ return self::fetchURL( $url, $post_vars, $cacheExpireTime, $get_fresh, $try_count );
+ }
+ if ( $page != '' ) {
+ $dbw = wfGetDB( DB_MASTER );
+ // Delete the old entry, if one exists.
+ $dbw->delete( $edgCacheTable, array( 'url' => substr( $url, 0, 254 )));
+ // Insert contents into the cache table.
+ $dbw->insert( $edgCacheTable, array( 'url' => substr( $url, 0, 254 ), 'result' => $page, 'req_time' => time() ) );
+ return $page;
+ }
+ } else {
+ return $row->result;
+ }
+ }
+
+ static private function getDataFromText( $contents, $format, $mappings, $source, $prefixLength = 0 ) {
+ // For now, this is only done for the CSV formats.
+ if ( is_array( $format ) ) {
+ list( $format, $delimiter ) = $format;
+ } else {
+ $delimiter = ',';
+ }
+
+ if ( $format == 'xml' ) {
+ return self::getXMLData( $contents );
+ } elseif ( $format == 'xml with xpath' ) {
+ return self::getXPathData( $contents, $mappings, $source );
+ } elseif ( $format == 'csv' ) {
+ return self::getCSVData( $contents, false, $delimiter );
+ } elseif ( $format == 'csv with header' ) {
+ return self::getCSVData( $contents, true, $delimiter );
+ } elseif ( $format == 'json' ) {
+ return self::getJSONData( $contents, $prefixLength );
+ } elseif ( $format == 'gff' ) {
+ return self::getGFFData( $contents );
+ } else {
+ return wfMessage( 'externaldata-web-invalid-format', $format )->text();
+ }
+ }
+
+ /**
+ * Checks whether this URL is allowed, based on the
+ * $edgAllowExternalDataFrom whitelist
+ */
+ static public function isURLAllowed( $url ) {
+ // this code is based on Parser::maybeMakeExternalImage()
+ global $edgAllowExternalDataFrom;
+ $data_from = $edgAllowExternalDataFrom;
+ $text = false;
+ if ( empty( $data_from ) ) {
+ return true;
+ } elseif ( is_array( $data_from ) ) {
+ foreach ( $data_from as $match ) {
+ if ( strpos( $url, $match ) === 0 ) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ if ( strpos( $url, $data_from ) === 0 ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ static public function getDataFromURL( $url, $format, $mappings, $postData = null, $cacheExpireTime, $prefixLength ) {
+ $url_contents = self::fetchURL( $url, $postData, $cacheExpireTime );
+ // Show an error message if there's nothing there.
+ if ( empty( $url_contents ) ) {
+ return "Error: No contents found at URL $url.";
+ }
+
+ return self::getDataFromText( $url_contents, $format, $mappings, $url, $prefixLength );
+ }
+
+ static private function getDataFromPath( $path, $format, $mappings ) {
+ if ( !file_exists( $path ) ) {
+ return "Error: No file found.";
+ }
+ $file_contents = file_get_contents( $path );
+ // Show an error message if there's nothing there.
+ if ( empty( $file_contents ) ) {
+ return "Error: Unable to get file contents.";
+ }
+
+ return self::getDataFromText( $file_contents, $format, $mappings, $path );
+ }
+
+ static public function getDataFromFile( $file, $format, $mappings ) {
+ global $edgFilePath;
+
+ if ( array_key_exists( $file, $edgFilePath ) ) {
+ return self::getDataFromPath( $edgFilePath[$file], $format, $mappings );
+ } else {
+ return "Error: No file is set for ID \"$file\".";
+ }
+ }
+
+ static public function getDataFromDirectory( $directory, $fileName, $format, $mappings ) {
+ global $edgDirectoryPath;
+
+ if ( array_key_exists( $directory, $edgDirectoryPath ) ) {
+ $directoryPath = $edgDirectoryPath[$directory];
+ $path = realpath( $directoryPath . $fileName );
+ if ( $path !== false && strpos( $path, $directoryPath ) === 0 ) {
+ return self::getDataFromPath( $path, $format, $mappings );
+ } else {
+ return "Error: File name \"$fileName\" is not allowed for directory ID \"$directory\".";
+ }
+ } else {
+ return "Error: No directory is set for ID \"$directory\".";
+ }
+ }
+
+ /**
+ * Recursive function, used by getSOAPData().
+ */
+ static public function getValuesForKeyInTree( $key, $tree ) {
+ // The passed-in tree can be either an array or a stdObject -
+ // we need it to be an array.
+ if ( is_object( $tree ) ) {
+ $tree = get_object_vars( $tree );
+ }
+ $values = array();
+ foreach ( $tree as $curKey => $curValue ) {
+ if ( is_object( $curValue ) || is_array( $curValue ) ) {
+ $additionalValues = self::getValuesForKeyInTree( $key, $curValue );
+ $values = array_merge( $values, $additionalValues );
+ } elseif ( $curKey == $key ) {
+ $values[] = $curValue;
+ }
+ }
+ return $values;
+ }
+
+ static public function getSOAPData( $url, $requestName, $requestData, $responseName, $mappings) {
+ $client = new SoapClient( $url );
+ try {
+ $result = $client->$requestName( $requestData );
+ } catch ( Exception $e ) {
+ return "Caught exception: " . $e->getMessage();
+ }
+
+ $realResultJSON = $result->$responseName;
+ if ( $realResultJSON == '' ) {
+ return 'Error: no data found for this set of "requestData" fields.';
+ }
+
+ $realResult = json_decode( $realResultJSON );
+ $errorKey = '#Error:';
+ if ( array_key_exists( $errorKey, $realResult ) ) {
+ return 'Error: ' . $realResult->$errorKey;
+ }
+
+ $values = array();
+ foreach ( $mappings as $fieldName ) {
+ $values[$fieldName] = self::getValuesForKeyInTree( $fieldName, $realResult );
+ }
+ return $values;
+ }
+
+}
diff --git a/www/wiki/extensions/ExternalData/package.json b/www/wiki/extensions/ExternalData/package.json
new file mode 100644
index 00000000..ea62e434
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/package.json
@@ -0,0 +1,11 @@
+{
+ "private": true,
+ "scripts": {
+ "test": "grunt test"
+ },
+ "devDependencies": {
+ "grunt": "1.0.3",
+ "grunt-banana-checker": "0.4.0",
+ "grunt-jsonlint": "1.0.7"
+ }
+}
diff --git a/www/wiki/extensions/ExternalData/sql/ExternalData.sql b/www/wiki/extensions/ExternalData/sql/ExternalData.sql
new file mode 100644
index 00000000..009362bb
--- /dev/null
+++ b/www/wiki/extensions/ExternalData/sql/ExternalData.sql
@@ -0,0 +1,9 @@
+CREATE TABLE IF NOT EXISTS `ed_url_cache` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `url` varchar(255) NOT NULL,
+ `post_vars` text,
+ `req_time` int(11) NOT NULL,
+ `result` longtext character set utf8 collate utf8_unicode_ci,
+ UNIQUE KEY `id` (`id`),
+ KEY `url` (`url`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file