diff --git a/.gitignore b/.gitignore index 00f1cf4..eec222b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,13 @@ _build/build.config.php -core.config.php -.settings/ -.project -.buildpath -/nbproject -*.iml -.idea/ -*.ipr -*.iws -/config.core.php +config.core.php + +_build/site + +icon/*.svg + +_packages/*.* +!_packages/.gitignore +!_packages/*.zip + +node_modules/ +core/components/*/vendor/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b551190..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "core/components/babel/vendor/iana-language-subtag-registry"] - path = core/components/babel/vendor/iana-language-subtag-registry - url = git@github.com:goldsky/IANA-s-Language-Subtag-Registry.git diff --git a/core/components/babel/docs/license.txt b/LICENSE.md similarity index 97% rename from core/components/babel/docs/license.txt rename to LICENSE.md index c0f1a70..17ff2f8 100644 --- a/core/components/babel/docs/license.txt +++ b/LICENSE.md @@ -1,287 +1,287 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 --------------------------- - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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 \ No newline at end of file +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 +-------------------------- + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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 diff --git a/README.markdown b/README.markdown deleted file mode 100644 index 6976a80..0000000 --- a/README.markdown +++ /dev/null @@ -1,32 +0,0 @@ -Babel -============= - -Babel is an Extra for MODx Revolution that helps you managing your multilingual -websites using different contexts. Babel even supports managing several different -multilingual websites within one MODx instance by using so called context groups. - -Babel maintains links between translated resources. In the manager you can use -the Babel Box to easily switch between the different language versions -of your resources. Translations can be created automatically by Babel or defined -manually. - -Additionally Babel can be used to synchronize certain template variables (TVs) -of translated resources which should be the same in every context (language). - -For detailed information please refer to [core/components/babel/docs/readme.txt](https://github.com/mikrobi/babel/blob/master/core/components/babel/docs/readme.txt "readme.txt") - -Screenshots of the Babel Box -------------- -![Link translation](https://github.com/mikrobi/babel/raw/master/screenshots/babel-linking-window.png "Link translation") - -![Menu of linked resources](https://github.com/mikrobi/babel/raw/master/screenshots/babel-linked-menu.png "Menu of linked resources") - -![Menu of unlinked resources](https://github.com/mikrobi/babel/raw/master/screenshots/babel-unlinked-menu.png "Menu of unlinked resources") - - -Installation via the MODx Package Management -------------- - -Babel is available in the MODx Package Manager at - -For the latest version please refer to this GitHub repository \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7f66e4 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +[![Default Lexicon](https://hosted.weblate.org/widget/modx-extras/babel/standard/svg-badge.svg)](https://hosted.weblate.org/projects/modx-extras/babel/) + +# Babel + +The easy way for your multilingual site! + +## Features + +Babel is an Extra for MODx Revolution that helps you to manage your multilingual +websites using different contexts. Babel even supports managing several different +multilingual websites within one MODx instance by using so-called context groups. + +Babel maintains links between translated resources. In the manager you can use +the Babel Box to easily switch between the different language versions +of your resources. Translations can be created automatically by Babel or defined +manually. + +Additionally, Babel can be used to synchronize certain template variables (TVs) +of translated resources which should be the same in every context (language). + +## Installation + +MODX Package Management + +## Usage + +Install via package manager and fill the system setting `babel.contextKeys` with +a comma separated list of context keys which should be used to link multilingual +resources. + +## Documentation + +For more information please read the [documentation](https://mikrobi.github.io/babel/). + +## License + +The project is licensed under the [GPLv2 license](https://github.com/mikrobi/babel/LICENSE.md). + +## Translations + +Translations of the package can be made for the [Default Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/standard/), the [Permissions Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/permissions/), the [Properties Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/properties/) and the [System Settings Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/system-settings/) diff --git a/_build/config.json b/_build/config.json index d9c0e4f..1ba3d30 100644 --- a/_build/config.json +++ b/_build/config.json @@ -2,8 +2,8 @@ "name": "Babel", "lowCaseName": "babel", "description": "The easy way for your multilingual site!", - "author": "Jakob Class, goldsky", - "version": "3.1.1-pl", + "author": "Jakob Class, Rico Goldsky, Joshua Luckers, Thomas Jakobi", + "version": "3.2.0", "package": { "menus": [ { @@ -21,36 +21,53 @@ "properties": [ { "name": "resourceId", - "description": "babellinks.resourceId", "value": "" }, { "name": "tpl", - "description": "babeltranslation.tpl", - "value": "babelLink" + "value": "tplBabellink" + }, + { + "name": "wrapperTpl", + "value": "" }, { "name": "activeCls", - "description": "babeltranslation.activeCls", "value": "active" }, { "name": "showUnpublished", - "description": "babeltranslation.showUnpublished", "type": "combo-boolean", "value": "0" }, { "name": "showCurrent", - "description": "babeltranslation.showCurrent", "type": "combo-boolean", "value": "0" }, { "name": "includeUnlinked", - "description": "babeltranslation.includeUnlinked", "type": "combo-boolean", "value": "0" + }, + { + "name": "ignoreSiteStatus", + "type": "combo-boolean", + "value": "0" + }, + { + "name": "restrictToGroup", + "type": "combo-boolean", + "value": "0" + }, + { + "name": "toArray", + "type": "combo-boolean", + "value": "0" + }, + { + "name": "toPlaceholder", + "value": "" } ] }, @@ -61,22 +78,18 @@ "properties": [ { "name": "resourceId", - "description": "babeltranslation.resourceId", "value": "" }, { "name": "contextKey", - "description": "babeltranslation.contextKey", "value": "" }, { "name": "cultureKey", - "description": "babeltranslation.cultureKey", "value": "" }, { "name": "showUnpublished", - "description": "babeltranslation.showUnpublished", "type": "combo-boolean", "value": "0" } @@ -97,41 +110,76 @@ "OnResourceSort" ] } + ], + "chunks": [ + { + "name": "tplBabellink", + "file": "babellink.chunk.html" + }, + { + "name": "tplBabellinkWrapper", + "file": "babellinkwrapper.chunk.html" + } ] }, "systemSettings": [ + { + "key": "debug", + "type": "combo-boolean", + "area": "system", + "value": "0" + }, { "key": "contextKeys", - "type": "textfield", - "area": "common", + "area": "system", "value": "" }, + { + "key": "restrictToGroup", + "type": "combo-boolean", + "area": "system", + "value": "1" + }, + { + "key": "displayText", + "area": "system", + "value": "language" + }, { "key": "babelTvName", - "type": "textfield", - "area": "common", + "area": "system", "value": "babelLanguageLinks" }, { "key": "syncTvs", - "type": "textfield", - "area": "common", + "area": "system", "value": "" } ] }, + "dependencies": [ + { + "name": "php", + "version": ">=7.2" + }, + { + "name": "modx", + "version": ">=2.4" + } + ], "build": { - "readme": "docs/readme.txt", - "license": "docs/license.txt", - "changelog": "docs/changelog.txt", + "readme": "docs/readme.md", + "license": "docs/license.md", + "changelog": "docs/changelog.md", "resolver": { "after": [ - "setupoptions.resolver.php", - "babelevents.resolver.php" + "resolve.setupoptions.php", + "resolve.permissions.php", + "resolve.babelevents.php" ] }, "setupOptions": { "source": "setup.options.php" } } -} \ No newline at end of file +} diff --git a/_build/resolvers/babelevents.resolver.php b/_build/resolvers/resolve.babelevents.php similarity index 71% rename from _build/resolvers/babelevents.resolver.php rename to _build/resolvers/resolve.babelevents.php index 8d0e809..b124bee 100644 --- a/_build/resolvers/babelevents.resolver.php +++ b/_build/resolvers/resolve.babelevents.php @@ -1,33 +1,12 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ /** * Resolves creating/removing babel events. * - * @author Jakob Class - * * @package babel * @subpackage build + * + * @var array $options + * @var xPDOObject $object */ /** @@ -36,7 +15,7 @@ * @param integer $service see https://github.com/modxcms/revolution/blob/2.x/core/model/modx/modx.class.php#L2005-L2010 * @return bool */ -function createEvent(modX &$modx, $name, $service = 0) +function createEvent(modX $modx, $name, $service = 0) { $success = true; $ct = $modx->getCount('modEvent', [ @@ -67,7 +46,7 @@ function createEvent(modX &$modx, $name, $service = 0) * @param string $name * @return bool */ -function removeEvent(modX &$modx, $name) +function removeEvent(modX $modx, $name) { $success = true; /** @var modEvent $event */ diff --git a/_build/resolvers/resolve.permissions.php b/_build/resolvers/resolve.permissions.php new file mode 100644 index 0000000..450feb6 --- /dev/null +++ b/_build/resolvers/resolve.permissions.php @@ -0,0 +1,150 @@ + [ + 'name' => 'Babel', + 'description' => 'Babel Access Policy with all attributes.', + 'lexicon' => $options['namespace'] . ':permissions' + ], + 'template' => [ + 'name' => 'BabelTemplate', + 'description' => 'Babel Policy Template with all attributes.', + 'lexicon' => $options['namespace'] . ':permissions', + 'template_group' => '1' + ], + 'permissions' => [ + 'babel_settings', // modx->lexicon('babel.permission.babel_settings_desc'); + ] + ] +]; + +/** + * @param modX $modx + * @param array $policy + * @param array $template + * @param string $permission + * @return bool + */ +function createAccessPermission($modx, $policy, $template, $permission) +{ + /** @var modAccessPolicyTemplate $accessPolicyTemplate */ + if (!$accessPolicyTemplate = $modx->getObject('modAccessPolicyTemplate', [ + 'name' => $template['name'] + ]) + ) { + $accessPolicyTemplate = $modx->newObject('modAccessPolicyTemplate'); + $accessPolicyTemplate->fromArray([ + 'name' => $template['name'], + 'description' => $template['description'], + 'lexicon' => $template['lexicon'], + 'template_group' => $template['template_group'] + ]); + $accessPolicyTemplate->save(); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Policy Template "' . $template['name'] . '" created.'); + } + + /** @var modAccessPolicy $accessPolicy */ + if (!$accessPolicy = $modx->getObject('modAccessPolicy', [ + 'name' => $policy['name'] + ]) + ) { + $accessPolicy = $modx->newObject('modAccessPolicy'); + $accessPolicy->fromArray([ + 'name' => $policy['name'], + 'description' => $policy['description'], + 'data' => [$permission => true], + 'lexicon' => $policy['lexicon'] + ]); + $accessPolicy->addOne($accessPolicyTemplate, 'Template'); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Policy "' . $policy['name'] . '" created.'); + } else { + $data = $accessPolicy->get('data'); + $data = ($data) ? array_merge($data, [$permission => true]) : [$permission => true]; + $accessPolicy->set('data', $data); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Policy "' . $policy['name'] . '" updated.'); + } + $accessPolicy->save(); + + if (!$accessPermission = $modx->getObject('modAccessPermission', [ + 'name' => $permission + ])) { + /** @var modAccessPermission $accessPermission */ + $accessPermission = $modx->newObject('modAccessPermission'); + $accessPermission->fromArray([ + 'name' => $permission, + 'description' => 'babel.permission.' . $permission . '_desc', + 'value' => '1' + ]); + $accessPermission->addOne($accessPolicyTemplate, 'Template'); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Permission "' . $permission . '" created.'); + } else { + $accessPermission->set('description', 'babel.permission.' . $permission . '_desc'); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Permission "' . $permission . '" updated.'); + } + $accessPermission->save(); + return true; +} + +/** + * @param modX $modx + * @param array $policy + * @param array $template + * @param string $permission + * @return bool + */ +function removeAccessPermission($modx, $policy, $template, $permission) +{ + /** @var modAccessPermission $accessPermission */ + if ($accessPolicy = $modx->getObject('modAccessPolicy', ['name' => $policy['name']])) { + $accessPolicy->remove(); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Policy "' . $policy['name'] . '" removed.'); + } + /** @var modAccessPolicyTemplate $accessPolicyTemplate */ + if ($accessPolicyTemplate = $modx->getObject('modAccessPolicyTemplate', ['name' => $template['name']])) { + $accessPolicyTemplate->remove(); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Policy Template "' . $template['name'] . '" removed.'); + } + /** @var modAccessPermission $accessPermission */ + if ($accessPermission = $modx->getObject('modAccessPermission', ['name' => $permission])) { + $accessPermission->remove(); + $modx->log(xPDO::LOG_LEVEL_INFO, 'Access Permission "' . $permission . '" removed.'); + } + return true; +} + +$success = true; +if ($object->xpdo) { + /** @var modX $modx */ + $modx = &$object->xpdo; + switch ($options[xPDOTransport::PACKAGE_ACTION]) { + case xPDOTransport::ACTION_INSTALL: + case xPDOTransport::ACTION_UPGRADE: + foreach ($accessPolicies as $accessPolicy) { + foreach ($accessPolicy['permissions'] as $accessPermission) { + $result = createAccessPermission($modx, $accessPolicy['policy'], $accessPolicy['template'], $accessPermission); + $success = $success && $result; + } + } + + break; + case xPDOTransport::ACTION_UNINSTALL: + foreach ($accessPolicies as $accessPolicy) { + foreach ($accessPolicy['permissions'] as $accessPermission) { + $result = removeAccessPermission($modx, $accessPolicy['policy'], $accessPolicy['template'], $accessPermission); + $success = $success && $result; + } + } + break; + } +} +return $success; diff --git a/_build/resolvers/resolve.setupoptions.php b/_build/resolvers/resolve.setupoptions.php new file mode 100644 index 0000000..419ea4b --- /dev/null +++ b/_build/resolvers/resolve.setupoptions.php @@ -0,0 +1,47 @@ +xpdo) { + /** @var xPDO $modx */ + $modx = &$object->xpdo; + + switch ($options[xPDOTransport::PACKAGE_ACTION]) { + case xPDOTransport::ACTION_INSTALL: + case xPDOTransport::ACTION_UPGRADE: + $settings = [ + 'contextKeys', + 'babelTvName', + 'syncTvs', + ]; + foreach ($settings as $key) { + if (isset($options[$key])) { + $setting = $modx->getObject('modSystemSetting', [ + 'key' => 'babel.' . $key + ]); + if ($setting != null) { + $setting->set('value', $modx->getOption($key, $options)); + $setting->save(); + } else { + $modx->log(xPDO::LOG_LEVEL_ERROR, 'The babel.' . $key . ' system setting was not found and can\'t be updated.'); + } + } + } + + $success = true; + break; + case xPDOTransport::ACTION_UNINSTALL: + $success = true; + break; + } +} +return $success; diff --git a/_build/resolvers/setupoptions.resolver.php b/_build/resolvers/setupoptions.resolver.php deleted file mode 100644 index edb33dc..0000000 --- a/_build/resolvers/setupoptions.resolver.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Resolves setup-options settings by setting email options. - * - * @author Jakob Class - * - * @package babel - * @subpackage build - */ -$success= false; -switch ($options[xPDOTransport::PACKAGE_ACTION]) { - case xPDOTransport::ACTION_INSTALL: - case xPDOTransport::ACTION_UPGRADE: - $settings = [ - 'contextKeys', - 'babelTvName', - 'syncTvs', - ]; - foreach ($settings as $key) { - if (isset($options[$key])) { - $setting = $object->xpdo->getObject('modSystemSetting', ['key' => 'babel.'.$key]); - if ($setting != null) { - $setting->set('value',$options[$key]); - $setting->save(); - } else { - $object->xpdo->log(xPDO::LOG_LEVEL_ERROR,'[Babel] '.$key.' setting could not be found, so the setting could not be changed.'); - } - } - } - - $success= true; - break; - case xPDOTransport::ACTION_UNINSTALL: - $success= true; - break; -} -return $success; \ No newline at end of file diff --git a/_build/setup.options.php b/_build/setup.options.php index 908f507..6aa0984 100644 --- a/_build/setup.options.php +++ b/_build/setup.options.php @@ -1,77 +1,88 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Build the setup options form. - * - * @author Jakob Class + * Setup options * * @package babel * @subpackage build + * @var modX $modx + * @var array $options */ -/* set some default values */ + +// Defaults $contexts = $modx->getCollection('modContext'); $contextKeys = []; -foreach($contexts as $context) { - $contextKey = $context->get('key'); - if($contextKey != 'mgr') { - $contextKeys[] = $contextKey; - } +foreach ($contexts as $context) { + $contextKey = $context->get('key'); + if ($contextKey != 'mgr') { + $contextKeys[] = $contextKey; + } } -$values = [ - 'contextKeys' => implode(',',$contextKeys), +$defaults = [ + 'contextKeys' => implode(',', $contextKeys), 'babelTvName' => 'babelLanguageLinks', - 'syncTvs' => '', + 'syncTvs' => '', ]; + +$output = ''; + switch ($options[xPDOTransport::PACKAGE_ACTION]) { case xPDOTransport::ACTION_INSTALL: + $output .= '

Install Babel

+

Babel will be installed. Please review the installation options carefully.


'; + + $output .= '
+ + +

Hint: For advanced configuration you can even set context groups separated by semicolons. Example: "web,ctx1,ctx2;ctx3,ctx4;ctx5,ctx6" please refer to readme.txt for details.

+
'; + $output .= '
+ + +
'; + $output .= '
+ + +

Hint: Leave blank if no TVs should be synchronized.

+
'; + break; case xPDOTransport::ACTION_UPGRADE: $setting = $modx->getObject('modSystemSetting', ['key' => 'babel.contextKeys']); - if ($setting != null) { $values['contextKeys'] = $setting->get('value'); } + $values['contextKeys'] = ($setting) ? $setting->get('value') : $defaults['contextKeys']; unset($setting); $setting = $modx->getObject('modSystemSetting', ['key' => 'babel.babelTvName']); - if ($setting != null) { $values['babelTvName'] = $setting->get('value'); } + $values['babelTvName'] = ($setting) ? $setting->get('value') : $defaults['babelTvName']; unset($setting); $setting = $modx->getObject('modSystemSetting', ['key' => 'babel.syncTvs']); - if ($setting != null) { $values['syncTvs'] = $setting->get('value'); } + $values['syncTvs'] = ($setting) ? (bool)$setting->get('value') : $defaults['syncTvs']; unset($setting); - break; - case xPDOTransport::ACTION_UNINSTALL: break; -} -$output = '
- -Hint: For advanced configuration you can even set context groups separated by semi-colons. Example: "web,ctx1,ctx2;ctx3,ctx4;ctx5,ctx6" please refer to readme.txt for details. -

+ $output .= '

Upgrade Babel

+

Babel will be upgraded. Please review the installation options carefully.


'; -
- -

+ $output .= '
+ + +

Hint: For advanced configuration you can even set context groups separated by semicolons. Example: "web,ctx1,ctx2;ctx3,ctx4;ctx5,ctx6" please refer to readme.txt for details.

+
'; + $output .= '
+ + +
'; + $output .= '
+ + +

Hint: Leave blank if no TVs should be synchronized.

+
'; + break; + case xPDOTransport::ACTION_UNINSTALL: + break; +} -
- -Hint: Leave blank if no TVs should be synchronized'; -return $output; \ No newline at end of file +return $output; diff --git a/_packages/babel-3.2.0-pl.transport.zip b/_packages/babel-3.2.0-pl.transport.zip new file mode 100644 index 0000000..d2f6045 Binary files /dev/null and b/_packages/babel-3.2.0-pl.transport.zip differ diff --git a/assets/components/babel/conn/mgr.php b/assets/components/babel/conn/mgr.php deleted file mode 100644 index 3f08fe8..0000000 --- a/assets/components/babel/conn/mgr.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel AJAX connector in the manager. - * - * @author goldsky - * - * @package babel - */ - -require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/config.core.php'; -require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php'; -require_once MODX_CONNECTORS_PATH . 'index.php'; - -$corePath = $modx->getOption('babel.core_path', null, $modx->getOption('core_path') . 'components/babel/'); -require_once $corePath . 'model/babel/babel.class.php'; -$modx->babel = new Babel($modx); - -$modx->lexicon->load('babel:default'); - -/* handle request */ -$path = $modx->getOption('processorsPath', $modx->babel->config, $corePath . 'processors/'); -$modx->request->handleRequest([ - 'processors_path' => $path, - 'location' => '', - ]); \ No newline at end of file diff --git a/assets/components/babel/connector.php b/assets/components/babel/connector.php new file mode 100644 index 0000000..c2f4676 --- /dev/null +++ b/assets/components/babel/connector.php @@ -0,0 +1,25 @@ +getOption('babel.core_path', null, $modx->getOption('core_path') . 'components/babel/'); +/** @var Babel $babel */ +$babel = $modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath +]); + +// Handle request +$modx->request->handleRequest([ + 'processors_path' => $babel->getOption('processorsPath'), + 'location' => '', +]); diff --git a/assets/components/babel/css/babel.css b/assets/components/babel/css/babel.css deleted file mode 100644 index 663ea8f..0000000 --- a/assets/components/babel/css/babel.css +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Babel CSS file - * - * @author goldsky - * - * @package babel - */ - -.icon-link { - background-image: url(../icons/link.png) !important; - background-repeat: no-repeat; -} -.icon-unlink { - background-image: url(../icons/link_break.png) !important; - background-repeat: no-repeat; -} -.icon-page-go { - background-image: url(../icons/page_go.png) !important; - background-repeat: no-repeat; -} -.icon-pencil-go { - background-image: url(../icons/pencil_go.png) !important; - background-repeat: no-repeat; -} - -.icon-babel-actioncolumn-img { - width: 16px; - height: 16px; - margin-top: 6px; - padding-top: 7px; - padding-bottom: 7px; - margin-right: 6px; -} - -.icon-babel-description-img { - width: 16px; - height: 16px; - margin-right: 6px; -} - -.x-combo-list-item { - min-height: 20px; -} - -#babel-language-select .x-btn-arrow button { - border-right-width: 0px; - padding-right: 0px; -} \ No newline at end of file diff --git a/assets/components/babel/css/mgr/babel.min.css b/assets/components/babel/css/mgr/babel.min.css new file mode 100644 index 0000000..dbc5be2 --- /dev/null +++ b/assets/components/babel/css/mgr/babel.min.css @@ -0,0 +1,6 @@ +.x-grid3-locked,.x-grid3-unlocked{overflow:hidden;position:absolute}.x-grid3-locked{border-right:1px solid #99bbe8}.x-grid3-locked .x-grid3-scroller{overflow:hidden}.x-grid3-locked .x-grid3-row{border-right:0}.x-grid3-scroll-spacer{height:19px}.x-grid3-unlocked .x-grid3-header-offset{padding-left:0}.x-grid3-unlocked .x-grid3-row{border-left:0}.babel-panel .action-buttons{text-align:center}.babel-panel .action-buttons li{display:inline-block;font-size:1.1em;line-height:.7;margin-right:5px}.babel-panel .action-buttons li:last-child{margin-right:0}.babel-panel .x-combo-list-item{min-height:20px}.babel-panel .icon-babel-description-img{height:16px;margin:0 6px 0 12px;width:16px}.babel-panel .icon-babel-description-img:first-child{margin-left:0}.home-panel.debug{background:linear-gradient(to top right,transparent,transparent,transparent,#fff)}.ribbon{height:180px;overflow:hidden;pointer-events:none;position:absolute;width:180px;z-index:10}.ribbon:after,.ribbon:before{border:5px solid #a20000;content:"";display:block;position:absolute;z-index:-1}.ribbon.top-right{right:-10px;top:-10px}.ribbon.top-right:after,.ribbon.top-right:before{border-right-color:transparent;border-top-color:transparent}.ribbon.top-right:before{left:0;top:0}.ribbon.top-right:after{bottom:0;right:0}.ribbon.top-right span{left:-46px;top:46px;transform:rotate(45deg)}.ribbon span{background-color:#be0000;box-shadow:0 5px 10px rgba(0,0,0,.1);color:#fff;display:block;font:700 18px/1 Lato,sans-serif;padding:15px 0;position:absolute;text-align:center;text-shadow:0 1px 1px rgba(0,0,0,.2);text-transform:uppercase;width:300px} +/*! + * Babel - The easy way for your multilingual site! + * Version: 3.2.0 + * Build date: 2024-02-07 + */ \ No newline at end of file diff --git a/assets/components/babel/icons/link.png b/assets/components/babel/icons/link.png deleted file mode 100644 index c4f00cb..0000000 Binary files a/assets/components/babel/icons/link.png and /dev/null differ diff --git a/assets/components/babel/icons/link_break.png b/assets/components/babel/icons/link_break.png deleted file mode 100644 index 57bafcf..0000000 Binary files a/assets/components/babel/icons/link_break.png and /dev/null differ diff --git a/assets/components/babel/icons/page_go.png b/assets/components/babel/icons/page_go.png deleted file mode 100644 index fad87d7..0000000 Binary files a/assets/components/babel/icons/page_go.png and /dev/null differ diff --git a/assets/components/babel/icons/pencil_go.png b/assets/components/babel/icons/pencil_go.png deleted file mode 100644 index 4771ee5..0000000 Binary files a/assets/components/babel/icons/pencil_go.png and /dev/null differ diff --git a/assets/components/babel/js/babel.class.js b/assets/components/babel/js/babel.class.js deleted file mode 100644 index dd783e0..0000000 --- a/assets/components/babel/js/babel.class.js +++ /dev/null @@ -1,395 +0,0 @@ -/** - * Babel - * - * Copyright 2010 by Jakob Class - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel JavaScript class file for the menu in the manager. - * - * @author goldsky - * - * @package babel - */ - -function Babel(config) { - this.config = config; -} - -Babel.prototype.getMenu = function (menus) { - var _this = this; - var actionButtons = Ext.getCmp("modx-action-buttons"); - if (actionButtons) { - var menu = [], i = 0; - for (var ctx in menus) { - if (ctx === _this.config.context_key) { - continue; - } - if (typeof(menus[ctx]["resourceUrl"]) !== 'undefined' && - menus[ctx]["resourceUrl"] !== "" && - menus[ctx]["resourceUrl"] !== "#" ) { - menu.push({ - text: menus[ctx]["displayText"], - iconCls: 'icon-link', - menu: { - items: [ - { - text: _('babel.open') + " " + menus[ctx]["resourceTitle"] + " (" + menus[ctx]["resourceId"] + ")", - iconCls: 'icon-page-go', - resourceUrl: menus[ctx]["resourceUrl"], - resourceId: menus[ctx]["resourceId"], - handler: function() { - MODx.loadPage('resource/update', 'id=' + this.resourceId); - } - }, '-', { - text: _('babel.unlink') + " " + menus[ctx]["resourceTitle"] + " (" + menus[ctx]["resourceId"] + ")", - iconCls: 'icon-unlink', - contextKey: ctx, - target: menus[ctx]["resourceId"], - handler: function() { - _this.unlinkTranslation(this.contextKey, this.target); - } - } - ] - } - }); - - ++i; - } else { - menu.push({ - text: menus[ctx]["displayText"], - handler: Ext.emptyFn, - menu: { - items: [ - { - text: _('babel.create_translation'), - iconCls: 'icon-pencil-go', - contextKey: ctx, - handler: function() { - _this.createTranslation(this.contextKey); - } - }, '-', { - text: _('babel.link_translation'), - iconCls: 'icon-link', - contextKey: ctx, - handler: function() { - _this.linkTranslation(this.contextKey); - } - } - ] - } - }); - } - } - if (i > 0) { - menu.push('-'); - menu.push({ - text: _('babel.unlink_all_translations'), - handler: function() { - _this.unlinkTranslation(); - } - }); - } - // destroy existing - var buttonMenu = Ext.getCmp('babel-language-select'); - if (buttonMenu) { - buttonMenu.destroy(); - } else { - actionButtons.insertButton(0, ["-"]); - } - buttonMenu = new Ext.Button({ - id: 'babel-language-select', - text: 'Select Language', - menu: menu, - listeners: { - render: { - fn: function (btn) { - btn.setText(menus[_this.config.context_key]["displayText"]); - }, - scope: this - }, - mouseover: function (btn) { - btn.showMenu(); - }, - mouseout: function (btn) { -// btn.hideMenu(); - } - } - }); - actionButtons.insertButton(0, [buttonMenu]); - actionButtons.doLayout(); - } -}; - -Babel.prototype.linkTranslation = function (ctx) { - var id = MODx.request.id; - var win = MODx.load({ - xtype: 'modx-window', - title: _('babel.link_translation'), - url: this.config.connectorUrl, - baseParams: { - action: 'mgr/resource/link', - context: ctx, - id: id - }, - listeners: { - success: { - fn: function (r) { - MODx.msg.status({ - title: _('success'), - message: r.message || _('save_successful') - }); - this.getMenu(r.a.result.object.menu); - this.hideMask(); - }, - scope: this - }, - failure: { - fn: function (r) { - this.hideMask(); - }, - scope: this - }, - beforeSubmit: { - fn: function (r) { - this.loadMask(); - }, - scope: this - } - }, - fields: [ - { - xtype: 'textfield', - fieldLabel: _('context'), - disabled: true, - emptyText: ctx - }, { - xtype: 'modx-field-parent-change', - fieldLabel: _('babel.select_tree_node'), - id: '', - anchor: '100%', - name: 'target-combo', - end: function (p) { - var t = Ext.getCmp('modx-resource-tree'); - if (!t) - return; - p.d = p.d || p.v; - if (p.c !== ctx) { - return; - } - t.removeListener('click',this.handleChangeParent,this); - t.on('click',t._handleClick,t); - t.disableHref = false; - win.fp.getForm().findField('target').setValue(p.v); - win.fp.getForm().findField('page_id').setValue(null); - this.setValue(p.d); - this.oldValue = false; - }, - handleChangeParent: function (node, e) { - var t = Ext.getCmp('modx-resource-tree'); - if (!t) { - return false; - } - t.disableHref = true; - - var id = node.id.split('_'); - id = id[1]; - if (id == this.config.currentid) { - MODx.msg.alert('', _('resource_err_own_parent')); - return false; - } - - this.fireEvent('end', { - v: node.attributes.type !== 'modContext' ? id : node.attributes.pk, - d: Ext.util.Format.stripTags(node.text), - c: node.attributes.ctx - }); - e.preventDefault(); - e.stopEvent(); - return true; - } - }, { - xtype: 'modx-combo', - fieldLabel: _('babel....or') + ' ' + _('babel.pagetitle_of_target'), - name: 'page_id', - anchor: '100%', - url: this.config.connectorUrl, - baseParams: { - action: 'mgr/resource/getlist', - context: ctx, - combo: true - }, - displayField: 'pagetitle', - valueField: 'id', - fields: ['id','pagetitle'], - editable: true, - typeAhead: true, - forceSelection: true, - listeners: { - select: { - fn: function(combo, record) { - var val = combo.getValue(); - if (val === "" || val === 0 || val === " ") { - combo.setValue(null); - } else { - win.fp.getForm().findField('target').setValue(record.get('id')); - } - win.fp.getForm().findField('target-combo').reset(); - }, - scope: this - }, - blur: { - fn: function (combo) { - var val = combo.getValue(); - if (val === "" || val === 0 || val === " ") { - combo.setValue(null); - } - }, - scope: this - } - }, - }, { - fieldLabel: _('babel.id_of_target'), - xtype: 'numberfield', - name: 'target', - enableKeyEvents: true, - listeners: { - keyup: { - fn: function(field, e) { - win.fp.getForm().findField('target-combo').reset(); - win.fp.getForm().findField('page_id').reset(); - }, - scope: this - } - } - }, { - xtype: 'xcheckbox', - boxLabel: _('babel.copy_tv_values'), - name: 'copy-tv-values' - }, { - xtype: 'xcheckbox', - boxLabel: _('babel.sync_linked_tranlations'), - name: 'sync-linked-tranlations', - checked: true - } - ] - }); -// win.reset(); - win.show(); -}; - -Babel.prototype.unlinkTranslation = function (ctx, target) { - this.loadMask(); - ctx = ctx || ''; - target = parseInt(target) || 0; - var id = MODx.request.id, text = ''; - if (target === 0) { - text = _('babel.unlink_all_translations_confirm'); - } else { - text = _('babel.unlink_translation_confirm', {context: ctx, id: id}); - } - return MODx.msg.confirm({ - title: _('confirm'), - text: text, - url: this.config.connectorUrl, - params: { - action: 'mgr/resource/unlink', - id: id, - context: ctx, - target: target - }, - listeners: { - success: { - fn: function (r) { - MODx.msg.status({ - title: _('success'), - message: r.message || _('save_successful') - }); - this.getMenu(r.object.menu); - this.hideMask(); - }, - scope: this - }, - failure: { - fn: function (r) { - this.hideMask(); - }, - scope: this - }, - cancel: { - fn: function (r) { - this.hideMask(); - }, - scope: this - } - } - }); -}; - -Babel.prototype.createTranslation = function (ctx) { - this.loadMask(); - var id = MODx.request.id; - return MODx.msg.confirm({ - title: _('confirm'), - text: _('babel.create_translation_confirm', {context: ctx, id: id}), - url: this.config.connectorUrl, - params: { - action: 'mgr/resource/duplicate', - context_key: ctx, - id: id - }, - listeners: { - success: { - fn: function (r) { - this.hideMask(); - MODx.loadPage('resource/update', 'id=' + r.object.id); - }, - scope: this - }, - failure: { - fn: function (r) { - this.hideMask(); - }, - scope: this - }, - cancel: { - fn: function (r) { - this.hideMask(); - }, - scope: this - } - } - }); -}; - -Babel.prototype.loadMask = function () { - if (!this.overlayMask) { - var domHandler = Ext.getBody().dom; - this.overlayMask = new Ext.LoadMask(domHandler, { - msg: _('babel.please_wait') - }); - } - this.overlayMask.show(); -}; - -Babel.prototype.hideMask = function () { - if (this.overlayMask) { - this.overlayMask.hide(); - } -}; diff --git a/assets/components/babel/js/mgr/babel.js b/assets/components/babel/js/mgr/babel.js deleted file mode 100644 index 20bef8b..0000000 --- a/assets/components/babel/js/mgr/babel.js +++ /dev/null @@ -1,9 +0,0 @@ -var Babel = function (config) { - config = config || {}; - Babel.superclass.constructor.call(this, config); -}; -Ext.extend(Babel, Ext.Component, { - page: {}, window: {}, grid: {}, tree: {}, panel: {}, combo: {}, config: {} -}); -Ext.reg('babel', Babel); -Babel = new Babel(); \ No newline at end of file diff --git a/assets/components/babel/js/mgr/babel.min.js b/assets/components/babel/js/mgr/babel.min.js new file mode 100644 index 0000000..087887b --- /dev/null +++ b/assets/components/babel/js/mgr/babel.min.js @@ -0,0 +1,6 @@ +/*! + * Babel - The easy way for your multilingual site! + * Version: 3.2.0 + * Build date: 2024-02-07 + */ +var babel=function(e){babel.superclass.constructor.call(this,e=e||{})},Babel=(Ext.extend(babel,Ext.Component,{page:{},window:{},grid:{},tree:{},panel:{},combo:{},config:{},util:{},getMenu:function(t){var i=this,e=Ext.getCmp("modx-action-buttons");if(e){var s,o=[],l=0;for(s in t)s!==this.config.context_key&&(void 0!==t[s].resourceUrl&&""!==t[s].resourceUrl&&"#"!==t[s].resourceUrl?(o.push({text:''+t[s].displayText,menu:{items:[{text:''+_("babel.open")+" "+t[s].resourceTitle+" ("+t[s].resourceId+")",resourceUrl:t[s].resourceUrl,resourceId:t[s].resourceId,handler:function(){MODx.loadPage("resource/update","id="+this.resourceId)}},"-",{text:''+_("babel.unlink")+" "+t[s].resourceTitle+" ("+t[s].resourceId+")",contextKey:s,target:t[s].resourceId,handler:function(){i.unlinkTranslation(this.contextKey,this.target)}}]}}),l++):o.push({text:''+t[s].displayText,handler:Ext.emptyFn,menu:{items:[{text:''+_("babel.create_translation"),contextKey:s,handler:function(){i.createTranslation(this.contextKey)}},"-",{text:''+_("babel.link_translation"),contextKey:s,handler:function(){i.linkTranslation(this.contextKey)}}]}}));0'+_("babel.unlink_all_translations"),handler:function(){i.unlinkTranslation()}})),o.push("-"),o.push({text:''+_("babel.about"),handler:function(){i.aboutWindow()}});var n=Ext.getCmp("babel-language-select");n&&n.destroy(),n=new Ext.Button({id:"babel-language-select",text:"Select Language",menu:o,listeners:{render:{fn:function(e){e.setText(t[i.config.context_key].displayText)},scope:this},mouseover:function(e){e.showMenu()}}}),e.insertButton(0,[n]),e.doLayout()}},linkTranslation:function(i){var e=MODx.request.id,s=MODx.load({xtype:"modx-window",title:_("babel.link_translation"),url:this.config.connectorUrl,baseParams:{action:"mgr/resource/link",context:i,id:e},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.getMenu(e.a.result.object.menu),this.hideMask()},scope:this},failure:{fn:this.hideMask,scope:this},beforeSubmit:{fn:this.loadMask,scope:this}},fields:[{xtype:"textfield",fieldLabel:_("context"),anchor:"100%",disabled:!0,emptyText:i},{xtype:"modx-field-parent-change",fieldLabel:_("babel.select_tree_node"),id:"",name:"target-combo",anchor:"100%",end:function(e){var t=Ext.getCmp("modx-resource-tree");t&&(e.display=e.display||e.value,e.context===i)&&(t.removeListener("click",this.handleChangeParent,this),t.on("click",t._handleClick,t),t.disableHref=!1,s.fp.getForm().findField("target").setValue(e.value),s.fp.getForm().findField("page_id").setValue(null),this.setValue(e.display),this.oldValue=!1)},handleChangeParent:function(e,t){var i=Ext.getCmp("modx-resource-tree");return!!i&&(i.disableHref=!0,(i=e.id.split("_")[1])===this.config.currentid?(MODx.msg.alert("",_("resource_err_own_parent")),!1):(this.fireEvent("end",{value:"modContext"!==e.attributes.type?i:e.attributes.pk,display:Ext.util.Format.stripTags(e.text),context:e.attributes.ctx}),t.preventDefault(),t.stopEvent(),!0))}},{xtype:"modx-combo",fieldLabel:_("babel.target_pagetitle"),name:"page_id",anchor:"100%",url:this.config.connectorUrl,baseParams:{action:"mgr/resource/getlist",context:i,combo:!0},displayField:"pagetitle",valueField:"id",fields:["id","pagetitle"],editable:!0,typeAhead:!0,forceSelection:!0,listeners:{select:{fn:function(e,t){var i=e.getValue();""===i||0===i||" "===i?e.setValue(null):s.fp.getForm().findField("target").setValue(t.get("id")),s.fp.getForm().findField("target-combo").reset()},scope:this},blur:{fn:function(e){var t=e.getValue();""!==t&&0!==t&&" "!==t||e.setValue(null)},scope:this}}},{fieldLabel:_("babel.target_id"),xtype:"numberfield",name:"target",anchor:"100%",enableKeyEvents:!0,listeners:{keyup:{fn:function(){s.fp.getForm().findField("target-combo").reset(),s.fp.getForm().findField("page_id").reset()},scope:this}}},{xtype:"xcheckbox",boxLabel:_("babel.copy_tv_values"),name:"copy-tv-values"},{xtype:"xcheckbox",boxLabel:_("babel.sync_linked_tranlations"),name:"sync-linked-tranlations",checked:!0}]});s.show()},unlinkTranslation:function(e,t){this.loadMask(),e=e||"",t=parseInt(t)||0;var i=MODx.request.id,s=0===t?_("babel.unlink_all_translations_confirm"):_("babel.unlink_translation_confirm",{context:e,id:i});return MODx.msg.confirm({title:_("confirm"),text:s,url:this.config.connectorUrl,params:{action:"mgr/resource/unlink",id:i,context:e,target:t},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.getMenu(e.object.menu),this.hideMask()},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},createTranslation:function(e){this.loadMask();var t=MODx.request.id;return MODx.msg.confirm({title:_("confirm"),text:_("babel.create_translation_confirm",{context:e,id:t}),url:this.config.connectorUrl,params:{action:"mgr/resource/duplicate",context_key:e,id:t},listeners:{success:{fn:function(e){this.hideMask(),MODx.loadPage("resource/update","id="+e.object.id)},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},loadMask:function(){var e;this.overlayMask||(e=Ext.getBody().dom,this.overlayMask=new Ext.LoadMask(e,{msg:_("babel.please_wait")})),this.overlayMask.show()},hideMask:function(){this.overlayMask&&this.overlayMask.hide()},aboutWindow:function(){Ext.Msg.show({title:_("babel")+" "+Babel.config.version,msg:'© 2010-2024 by Jakob Class

Authors: Jakob Class, Rico Goldsky, Joshua Luckers, Thomas Jakobi

Repository: github.com/Jako/Babel',buttons:Ext.Msg.OK,cls:"babel_window",width:358})}}),Ext.reg("babel",babel),new babel);Babel.combo.Context=function(e){e=e||{},Ext.applyIf(e,{url:Babel.config.connectorUrl,baseParams:{action:"mgr/context/getlist",combo:!0,exclude:"mgr"},tpl:new Ext.XTemplate('
{name:htmlEncode} ({key:htmlEncode})
')}),Babel.combo.Context.superclass.constructor.call(this,e)},Ext.extend(Babel.combo.Context,MODx.combo.Context,{setValue:function(e){Babel.combo.Context.superclass.setValue.call(this,e=""===e?null:e)}}),Ext.reg("babel-combo-context",Babel.combo.Context),Ext.ns("Ext.ux.grid"),Ext.ux.grid.LockingGridView=Ext.extend(Ext.grid.GridView,{lockText:"Lock",unlockText:"Unlock",rowBorderWidth:1,lockedBorderWidth:1,syncHeights:!1,initTemplates:function(){var e=this.templates||{};e.masterTpl||(e.masterTpl=new Ext.Template('
','
','
{lockedHeader}
','
{lockedBody}
',"
",'
','
{header}
','
{body}
',"
",'
 
','
 
',"
")),this.templates=e,Ext.ux.grid.LockingGridView.superclass.initTemplates.call(this)},getEditorParent:function(e){return this.el.dom},initElements:function(){var e=Ext.get(this.grid.getGridEl().dom.firstChild),t=e.child("div.x-grid3-locked"),i=t.child("div.x-grid3-header"),s=t.child("div.x-grid3-scroller"),o=e.child("div.x-grid3-viewport"),l=o.child("div.x-grid3-header"),n=o.child("div.x-grid3-scroller");this.grid.hideHeaders&&(i.setDisplayed(!1),l.setDisplayed(!1)),this.forceFit&&n.setStyle("overflow-x","hidden"),Ext.apply(this,{el:e,mainWrap:o,mainHd:l,innerHd:l.dom.firstChild,scroller:n,mainBody:n.child("div.x-grid3-body"),focusEl:n.child("a"),resizeMarker:e.child("div.x-grid3-resize-marker"),resizeProxy:e.child("div.x-grid3-resize-proxy"),lockedWrap:t,lockedHd:i,lockedScroller:s,lockedBody:s.child("div.x-grid3-body"),lockedInnerHd:i.child("div.x-grid3-header-inner",!0)}),this.focusEl.swallowEvent("click",!0)},getLockedRows:function(){return this.hasRows()?this.lockedBody.dom.childNodes:[]},getLockedRow:function(e){return this.getLockedRows()[e]},getCell:function(e,t){var i=this.cm.getLockedCount();return t
',{compiled:!0}),this.ident="babel-resourcematrix-"+Ext.id();var t=this,i=[],s=["id","context_key","pagetitle","parent"],o=[],l=(e.contexts&&(i=[{header:_("id"),width:70,sortable:!0,dataIndex:"id",locked:!0,id:"res_id"},{header:_("context"),width:80,sortable:!0,dataIndex:"context_key",locked:!0,id:"context_key"},{header:_("pagetitle"),width:200,sortable:!0,dataIndex:"pagetitle",locked:!0,id:"pagetitle"},{header:_("babel.all"),renderer:this.buttonColumnAllRenderer.bind(this),menuDisabled:!0,fixed:!0,locked:!0,width:50}],Ext.each(e.contexts,function(e){s.push("linkedres_id_"+e),s.push("linkedres_pagetitle_"+e),o.push(e),i.push({header:e,width:70,sortable:!1,dataIndex:"linkedres_id_"+e,id:"linkedres_id_"+e,menuDisabled:!0,renderer:t.buttonColumnContextRenderer.bind(t)})})),new Ext.ux.grid.LockingColumnModel({columns:i}));new Ext.ux.grid.LockingGridView({syncHeights:!0});Ext.apply(e,{url:Babel.config.connectorUrl,baseParams:{action:"mgr/resource/getmatrixlist",contexts:o.toString()},colModel:l,fields:s,paging:!0,remoteSort:!0,anchor:"100%",view:new Ext.ux.grid.LockingGridView,autoHeight:!1,showActionsColumn:!1,tbar:[{xtype:"babel-combo-context",id:this.ident+"-filter-context",emptyText:_("babel.select_context"),listeners:{select:{fn:this.filterByContext,scope:this}}},"->",{xtype:"textfield",id:this.ident+"-filter-query",cls:"x-form-filter",emptyText:_("babel.search"),width:300,listeners:{change:{fn:this.filterByQuery,scope:this},render:{fn:function(e){new Ext.KeyMap(e.getEl(),{key:Ext.EventObject.ENTER,fn:this.blur,scope:e})},scope:this}}},{xtype:"button",id:this.ident+"-filter-clear",cls:"x-form-filter-clear",text:_("babel.reset"),listeners:{click:{fn:this.clearFilter,scope:this}}}]}),Babel.grid.ResourceMatrix.superclass.constructor.call(this,e)},Ext.extend(Babel.grid.ResourceMatrix,MODx.grid.Grid,{linkTranslation:function(i,e){var s=MODx.load({xtype:"modx-window",title:_("babel.link_translation"),url:Babel.config.connectorUrl,baseParams:{action:"mgr/resource/link",context:i,id:e},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.hideMask(),this.refresh()},scope:this},failure:{fn:this.hideMask,scope:this},beforeSubmit:{fn:this.loadMask,scope:this}},fields:[{xtype:"textfield",fieldLabel:_("context"),anchor:"100%",disabled:!0,emptyText:i},{xtype:"modx-field-parent-change",fieldLabel:_("babel.select_tree_node"),id:"",name:"target-combo",anchor:"100%",end:function(e){var t=Ext.getCmp("modx-resource-tree");t&&(e.display=e.display||e.value,e.context===i)&&(t.removeListener("click",this.handleChangeParent,this),t.on("click",t._handleClick,t),t.disableHref=!1,s.fp.getForm().findField("target").setValue(e.value),s.fp.getForm().findField("page_id").setValue(null),this.setValue(e.display),this.oldValue=!1)},handleChangeParent:function(e,t){var i=Ext.getCmp("modx-resource-tree");return!!i&&(i.disableHref=!0,(i=e.id.split("_")[1])===this.config.currentid?(MODx.msg.alert("",_("resource_err_own_parent")),!1):(this.fireEvent("end",{value:"modContext"!==e.attributes.type?i:e.attributes.pk,display:Ext.util.Format.stripTags(e.text),context:e.attributes.ctx}),t.preventDefault(),t.stopEvent(),!0))}},{xtype:"modx-combo",fieldLabel:_("babel.target_pagetitle"),name:"page_id",anchor:"100%",url:Babel.config.connectorUrl,baseParams:{action:"mgr/resource/getlist",context:i,combo:!0},displayField:"pagetitle",valueField:"id",fields:["id","pagetitle"],editable:!0,typeAhead:!0,forceSelection:!0,listeners:{select:{fn:function(e,t){var i=e.getValue();""===i||0===i||" "===i?e.setValue(null):s.fp.getForm().findField("target").setValue(t.get("id")),s.fp.getForm().findField("target-combo").reset()},scope:this},blur:{fn:function(e){var t=e.getValue();""!==t&&0!==t&&" "!==t||e.setValue(null)},scope:this}}},{fieldLabel:_("babel.target_id"),xtype:"numberfield",name:"target",anchor:"100%",enableKeyEvents:!0,listeners:{keyup:{fn:function(){s.fp.getForm().findField("target-combo").reset(),s.fp.getForm().findField("page_id").reset()},scope:this}}},{xtype:"xcheckbox",boxLabel:_("babel.copy_tv_values"),name:"copy-tv-values"},{xtype:"xcheckbox",boxLabel:_("babel.sync_linked_tranlations"),name:"sync-linked-tranlations",checked:!0}]});s.reset(),s.show()},unlinkTranslation:function(e,t,i){this.loadMask(),e=e||"";var s=0===(i=parseInt(i)||0)?_("babel.unlink_all_translations_confirm"):_("babel.unlink_translation_confirm",{context:e,id:t});return MODx.msg.confirm({title:_("confirm"),text:s,url:Babel.config.connectorUrl,params:{action:"mgr/resource/unlink",id:t,context:e,target:i},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.hideMask(),this.refresh()},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},createTranslation:function(e,t){return this.loadMask(),MODx.msg.confirm({title:_("confirm"),text:_("babel.create_translation_confirm",{context:e,id:t}),url:Babel.config.connectorUrl,params:{action:"mgr/resource/duplicate",context_key:e,id:t},listeners:{success:{fn:function(e){this.hideMask(),MODx.loadPage("resource/update","id="+e.object.id)},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},clearFilter:function(){var e=this.getStore();e.baseParams.context="",e.baseParams.query="",Ext.getCmp(this.ident+"-filter-context").reset(),Ext.getCmp(this.ident+"-filter-query").reset(),this.getBottomToolbar().changePage(1),this.refresh()},filterByContext:function(e,t){this.getStore().baseParams.context=t.data.key,this.getBottomToolbar().changePage(1),this.refresh()},filterByQuery:function(e,t){return this.getStore().baseParams.query=t,this.getBottomToolbar().changePage(1),this.refresh(),!0},loadMask:function(){var e;this.overlayMask||(e=Ext.getBody().dom,this.overlayMask=new Ext.LoadMask(e,{msg:_("babel.please_wait")})),this.overlayMask.show()},hideMask:function(){this.overlayMask&&this.overlayMask.hide()},buttonColumnAllRenderer:function(){return this.buttonColumnTpl.apply({action_buttons:[{className:"unlink-all",icon:"chain-broken",text:_("babel.unlink")}]})},buttonColumnContextRenderer:function(e,t,i){var s,o=[];return t.id!=="linkedres_id_"+i.get("context_key")&&(s=t.id.substr("linkedres_id_".length),""===i.get(t.id)?o.push({className:"create",icon:"plus-circle",text:_("babel.create_translation"),ctx:s,target:0},{className:"link",icon:"link",text:_("babel.link_translation"),ctx:s,target:0}):(t=i.get("linkedres_pagetitle_"+s),i=i.get("linkedres_id_"+s),o.push({className:"update",icon:"pencil-square-o",text:_("edit")+": "+t+" ("+i+")",ctx:s,target:i},{className:"unlink",icon:"chain-broken",text:_("babel.unlink")+": "+t+" ("+i+")",ctx:s,target:i}))),this.buttonColumnTpl.apply({action_buttons:o})},onClick:function(e){var t=e.getTarget();if("icon"===t.className.split(" ")[0]){var e=t.className.split(" ")[1],i=this.getSelectionModel().getSelected();switch(e){case"unlink-all":this.unlinkTranslation("",i.get("id"),0);break;case"create":this.createTranslation(t.dataset.ctx,i.get("id"));break;case"link":this.linkTranslation(t.dataset.ctx,i.get("id"));break;case"update":MODx.loadPage("resource/update","id="+t.dataset.target),console.log(i);break;case"unlink":this.unlinkTranslation(t.dataset.ctx,i.get("id"),t.dataset.target)}}}}),Ext.reg("babel-grid-resourcematrix",Babel.grid.ResourceMatrix),Babel.panel.Home=function(e){e=e||{},Ext.applyIf(e,{cls:"container home-panel"+(Babel.config.debug?" debug":"")+" modx"+Babel.config.modxversion,defaults:{collapsible:!1,autoHeight:!0},items:[{html:"

"+_("babel")+"

"+(Babel.config.debug?'
'+_("babel.debug_mode")+"
":""),border:!1,cls:"modx-page-header"},{defaults:{autoHeight:!0},border:!0,cls:"babel-panel",items:[{xtype:"babel-panel-overview"}]}]}),Babel.panel.Home.superclass.constructor.call(this,e)},Ext.extend(Babel.panel.Home,MODx.Panel),Ext.reg("babel-panel-home",Babel.panel.Home),Babel.panel.HomeTab=function(e){e=e||{},Ext.applyIf(e,{id:"babel-panel-"+e.tabtype,title:e.title,items:[{html:"

"+e.description+"

",border:!1,cls:"panel-desc"},{layout:"form",cls:"x-form-label-left main-wrapper",defaults:{autoHeight:!0},border:!0,items:[{id:"babel-panel-"+e.tabtype+"-"+e.contenttype,xtype:"babel-"+e.contenttype+"-"+e.tabtype,preventRender:!0,contexts:Babel.config.contexts,listeners:{afterrender:function(){this.store.on("load",function(){var e=this.getTopToolbar().getHeight(),t=this.getView().lockedHd.getHeight(),i=this.getView().lockedBody.getHeight(),s=this.getBottomToolbar().getHeight();this.setHeight(e+t+i+s+14)},this)}}}]}]}),Babel.panel.HomeTab.superclass.constructor.call(this,e)},Ext.extend(Babel.panel.HomeTab,MODx.Panel),Ext.reg("babel-panel-hometab",Babel.panel.HomeTab),Babel.panel.Overview=function(e){e=e||{},this.ident="babel-overview-"+Ext.id(),this.panelOverviewTabs=[{xtype:"babel-panel-hometab",title:_("babel.contexts"),description:"
"+_("babel.contexts_desc")+'
'+_("babel.contexts_desc_link")+''+_("babel.contexts_desc_unlink")+''+_("babel.contexts_desc_update")+''+_("babel.contexts_desc_create")+"
",tabtype:"resourcematrix",contenttype:"grid"}],(Babel.config.permissions.babel_settings||Babel.config.permissions.settings)&&this.panelOverviewTabs.push({xtype:"babel-panel-settings"}),Ext.applyIf(e,{id:this.ident,items:[{xtype:"modx-tabs",border:!0,stateful:!0,stateId:"babel-panel-overview",stateEvents:["tabchange"],getState:function(){return{activeTab:this.items.indexOf(this.getActiveTab())}},autoScroll:!0,deferredRender:!0,forceLayout:!1,defaults:{layout:"form",autoHeight:!0,hideMode:"offsets"},items:this.panelOverviewTabs,listeners:{tabchange:function(e,t){"babel-panel-settings"===t.xtype?Ext.getCmp("babel-grid-system-settings")&&Ext.getCmp("babel-grid-system-settings").getStore().reload():"babel-panel-hometab"===t.xtype&&Ext.getCmp("babel-panel-"+t.tabtype+"-"+t.contenttype)&&Ext.getCmp("babel-panel-"+t.tabtype+"-"+t.contenttype).getStore().reload()}}}]}),Babel.panel.Overview.superclass.constructor.call(this,e)},Ext.extend(Babel.panel.Overview,MODx.Panel),Ext.reg("babel-panel-overview",Babel.panel.Overview),MODx.grid.SettingsGrid&&(Babel.panel.Settings=function(e){e=e||{},MODx.request.ns="babel",Ext.applyIf(e,{id:"babel-panel-settings",title:_("babel.settings"),items:[{html:"

"+_("babel.settings_desc")+"

",border:!1,cls:"panel-desc"},{xtype:"babel-grid-system-settings",id:"babel-grid-system-settings",cls:"main-wrapper",preventSaveRefresh:!0}]}),Babel.panel.Settings.superclass.constructor.call(this,e)},Ext.extend(Babel.panel.Settings,MODx.Panel),Ext.reg("babel-panel-settings",Babel.panel.Settings),Babel.grid.SystemSettings=function(e){e=e||{},Ext.applyIf(e,{id:"babel-grid-systemsettings",url:Babel.config.connectorUrl,baseParams:{action:"mgr/settings/getlist",area:MODx.request.area||""},save_action:"mgr/settings/updatefromgrid",tbar:[],queryParam:3<=Babel.config.modxversion?"query":"key"}),Babel.grid.SystemSettings.superclass.constructor.call(this,e)},Ext.extend(Babel.grid.SystemSettings,MODx.grid.SettingsGrid,{_showMenu:function(e,t,i){i.stopEvent(),i.preventDefault(),this.menu.record=this.getStore().getAt(t).data,this.getSelectionModel().isSelected(t)||this.getSelectionModel().selectRow(t),this.menu.removeAll();t=[];this.menu.record.menu?t=this.menu.record.menu:t.push({text:_("setting_update")||_("edit"),handler:this.updateSetting}),0'+t[i].displayText,menu:{items:[{text:''+_("babel.open")+" "+t[i].resourceTitle+" ("+t[i].resourceId+")",resourceUrl:t[i].resourceUrl,resourceId:t[i].resourceId,handler:function(){MODx.loadPage("resource/update","id="+this.resourceId)}},"-",{text:''+_("babel.unlink")+" "+t[i].resourceTitle+" ("+t[i].resourceId+")",contextKey:i,target:t[i].resourceId,handler:function(){n.unlinkTranslation(this.contextKey,this.target)}}]}}),o++):s.push({text:''+t[i].displayText,handler:Ext.emptyFn,menu:{items:[{text:''+_("babel.create_translation"),contextKey:i,handler:function(){n.createTranslation(this.contextKey)}},"-",{text:''+_("babel.link_translation"),contextKey:i,handler:function(){n.linkTranslation(this.contextKey)}}]}}));0'+_("babel.unlink_all_translations"),handler:function(){n.unlinkTranslation()}})),s.push("-"),s.push({text:''+_("babel.about"),handler:function(){n.aboutWindow()}});var a=Ext.getCmp("babel-language-select");a&&a.destroy(),a=new Ext.Button({id:"babel-language-select",text:"Select Language",menu:s,listeners:{render:{fn:function(e){e.setText(t[n.config.context_key].displayText)},scope:this},mouseover:function(e){e.showMenu()}}}),e.insertButton(0,[a]),e.doLayout()}},linkTranslation:function(n){var e=MODx.request.id,i=MODx.load({xtype:"modx-window",title:_("babel.link_translation"),url:this.config.connectorUrl,baseParams:{action:"mgr/resource/link",context:n,id:e},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.getMenu(e.a.result.object.menu),this.hideMask()},scope:this},failure:{fn:this.hideMask,scope:this},beforeSubmit:{fn:this.loadMask,scope:this}},fields:[{xtype:"textfield",fieldLabel:_("context"),anchor:"100%",disabled:!0,emptyText:n},{xtype:"modx-field-parent-change",fieldLabel:_("babel.select_tree_node"),id:"",name:"target-combo",anchor:"100%",end:function(e){var t=Ext.getCmp("modx-resource-tree");t&&(e.display=e.display||e.value,e.context===n)&&(t.removeListener("click",this.handleChangeParent,this),t.on("click",t._handleClick,t),t.disableHref=!1,i.fp.getForm().findField("target").setValue(e.value),i.fp.getForm().findField("page_id").setValue(null),this.setValue(e.display),this.oldValue=!1)},handleChangeParent:function(e,t){var n=Ext.getCmp("modx-resource-tree");return!!n&&(n.disableHref=!0,(n=e.id.split("_")[1])===this.config.currentid?(MODx.msg.alert("",_("resource_err_own_parent")),!1):(this.fireEvent("end",{value:"modContext"!==e.attributes.type?n:e.attributes.pk,display:Ext.util.Format.stripTags(e.text),context:e.attributes.ctx}),t.preventDefault(),t.stopEvent(),!0))}},{xtype:"modx-combo",fieldLabel:_("babel.target_pagetitle"),name:"page_id",anchor:"100%",url:this.config.connectorUrl,baseParams:{action:"mgr/resource/getlist",context:n,combo:!0},displayField:"pagetitle",valueField:"id",fields:["id","pagetitle"],editable:!0,typeAhead:!0,forceSelection:!0,listeners:{select:{fn:function(e,t){var n=e.getValue();""===n||0===n||" "===n?e.setValue(null):i.fp.getForm().findField("target").setValue(t.get("id")),i.fp.getForm().findField("target-combo").reset()},scope:this},blur:{fn:function(e){var t=e.getValue();""!==t&&0!==t&&" "!==t||e.setValue(null)},scope:this}}},{fieldLabel:_("babel.target_id"),xtype:"numberfield",name:"target",anchor:"100%",enableKeyEvents:!0,listeners:{keyup:{fn:function(){i.fp.getForm().findField("target-combo").reset(),i.fp.getForm().findField("page_id").reset()},scope:this}}},{xtype:"xcheckbox",boxLabel:_("babel.copy_tv_values"),name:"copy-tv-values"},{xtype:"xcheckbox",boxLabel:_("babel.sync_linked_tranlations"),name:"sync-linked-tranlations",checked:!0}]});i.show()},unlinkTranslation:function(e,t){this.loadMask(),e=e||"",t=parseInt(t)||0;var n=MODx.request.id,i=0===t?_("babel.unlink_all_translations_confirm"):_("babel.unlink_translation_confirm",{context:e,id:n});return MODx.msg.confirm({title:_("confirm"),text:i,url:this.config.connectorUrl,params:{action:"mgr/resource/unlink",id:n,context:e,target:t},listeners:{success:{fn:function(e){MODx.msg.status({title:_("success"),message:e.message||_("save_successful")}),this.getMenu(e.object.menu),this.hideMask()},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},createTranslation:function(e){this.loadMask();var t=MODx.request.id;return MODx.msg.confirm({title:_("confirm"),text:_("babel.create_translation_confirm",{context:e,id:t}),url:this.config.connectorUrl,params:{action:"mgr/resource/duplicate",context_key:e,id:t},listeners:{success:{fn:function(e){this.hideMask(),MODx.loadPage("resource/update","id="+e.object.id)},scope:this},failure:{fn:this.hideMask,scope:this},cancel:{fn:this.hideMask,scope:this}}})},loadMask:function(){var e;this.overlayMask||(e=Ext.getBody().dom,this.overlayMask=new Ext.LoadMask(e,{msg:_("babel.please_wait")})),this.overlayMask.show()},hideMask:function(){this.overlayMask&&this.overlayMask.hide()},aboutWindow:function(){Ext.Msg.show({title:_("babel")+" "+Babel.config.version,msg:'© 2010-2024 by Jakob Class

Authors: Jakob Class, Rico Goldsky, Joshua Luckers, Thomas Jakobi

Repository: github.com/Jako/Babel',buttons:Ext.Msg.OK,cls:"babel_window",width:358})}}),Ext.reg("babel",babel),new babel); \ No newline at end of file diff --git a/assets/components/babel/js/mgr/sections/index.js b/assets/components/babel/js/mgr/sections/index.js deleted file mode 100644 index fa2e7ca..0000000 --- a/assets/components/babel/js/mgr/sections/index.js +++ /dev/null @@ -1,15 +0,0 @@ -Ext.onReady(function () { - MODx.load({xtype: 'babel-page-home'}); -}); -Babel.page.Home = function (config) { - config = config || {}; - Ext.applyIf(config, { - components: [{ - xtype: 'babel-panel-home' - , renderTo: 'babel-panel-home-div' - }] - }); - Babel.page.Home.superclass.constructor.call(this, config); -}; -Ext.extend(Babel.page.Home, MODx.Component); -Ext.reg('babel-page-home', Babel.page.Home); \ No newline at end of file diff --git a/assets/components/babel/js/mgr/widgets/combo.context.js b/assets/components/babel/js/mgr/widgets/combo.context.js deleted file mode 100644 index 2d4073c..0000000 --- a/assets/components/babel/js/mgr/widgets/combo.context.js +++ /dev/null @@ -1,25 +0,0 @@ -Babel.combo.Context = function (config) { - config = config || {}; - Ext.applyIf(config, { - url: Babel.config.connectorUrl, - baseParams: { - action: 'mgr/context/getlist', - combo: true, - exclude: 'mgr' - } - }); - Babel.combo.Context.superclass.constructor.call(this, config); - - this.on('select', function (comp, record, index){ - if (comp.getValue() === "" || comp.getValue() === " ") { - comp.setValue(null); - } - }); - this.on('change', function (comp, newValue, oldValue){ - if (newValue === "" || newValue === " ") { - comp.setValue(null); - } - }); -}; -Ext.extend(Babel.combo.Context, MODx.combo.Context); -Ext.reg('babel-combo-context', Babel.combo.Context); diff --git a/assets/components/babel/js/mgr/widgets/grid.resourcematrix.js b/assets/components/babel/js/mgr/widgets/grid.resourcematrix.js deleted file mode 100644 index 89f7322..0000000 --- a/assets/components/babel/js/mgr/widgets/grid.resourcematrix.js +++ /dev/null @@ -1,479 +0,0 @@ -Babel.grid.ResourceMatrix = function (config) { - config = config || {}; - - var columns = []; - var fields = []; - var contexts = []; - - columns.push({ - header: _('id'), - dataIndex: 'id', - sortable: true, - width: 70, - locked: true, - id: 'res_id' - }); - columns.push({ - header: _('context'), - dataIndex: 'context_key', - sortable: true, - width: 80, - locked: true, - id: 'context_key' - }); - columns.push({ - header: _('pagetitle'), - dataIndex: 'pagetitle', - sortable: true, - width: 200, - locked: true, - id: 'pagetitle' - }); - - columns.push({ - header: _('babel.all'), - xtype: 'actioncolumn', - dataIndex: 'id', - sortable: false, - editable: false, - fixed: true, - width: 50, - locked: true, - items: [ - { - iconCls: 'icon-unlink icon-babel-actioncolumn-img', - tooltip: _('babel.unlink'), - altText: _('babel.unlink'), - handler: function (grid, row, col) { - var rec = this.store.getAt(row); - grid.unlinkTranslation('', rec.get('id'), 0) - }, - scope: this - } - ] - }); - - fields.push('id'); - fields.push('context_key'); - fields.push('pagetitle'); - fields.push('parent'); - - if (config.record) { - Ext.each(config.record, function (item, index) { - fields.push('linkedres_id_' + item.key); - fields.push('linkedres_pagetitle_' + item.key); - contexts.push(item.key); - - var actionItems = []; - actionItems.push({ - handler: function (grid, row, col) { - var sel_model = grid.getSelectionModel(); - sel_model.selectRow(row); - var rec = grid.getStore().getAt(row); - var colName = grid.getColumnModel().getDataIndex(col); - var ctx = colName.substr('linkedres_id_'.length); - var cellvalue = rec.data[colName]; - if (cellvalue.length === 0) { - grid.createTranslation(ctx, rec.get('id')); - } else { - MODx.loadPage('resource/update', 'id=' + cellvalue); - } - }, - getClass: function (v, meta, rec) { - if (meta.id === 'linkedres_id_' + rec.get('context_key')) { - return ''; - } - if (rec.get(meta.id) === '') { - this.items[0].tooltip = _('babel.create_translation'); - this.items[0].altText = _('babel.create_translation'); - return 'icon-pencil-go icon-babel-actioncolumn-img'; - } else { - var ctx = meta.id.substr('linkedres_id_'.length); - var pagetitle = rec.get('linkedres_pagetitle_' + ctx); - this.items[0].tooltip = _('edit') + ': ' + pagetitle; - this.items[0].altText = _('edit') + ': ' + pagetitle; - return 'icon-page-go icon-babel-actioncolumn-img'; - } - } - }); - actionItems.push({ - handler: function (grid, row, col) { - var sel_model = grid.getSelectionModel(); - sel_model.selectRow(row); - var rec = grid.getStore().getAt(row); - var colName = grid.getColumnModel().getDataIndex(col); - var ctx = colName.substr('linkedres_id_'.length); - var cellvalue = rec.data[colName]; - if (cellvalue.length === 0) { - grid.linkTranslation(ctx, rec.get('id')); - } else { - grid.unlinkTranslation(ctx, rec.get('id'), cellvalue); - } - }, - getClass: function (v, meta, rec) { - if (meta.id === 'linkedres_id_' + rec.get('context_key')) { - return ''; - } - if (rec.get(meta.id) === '') { - this.items[1].tooltip = _('babel.link_translation'); - this.items[1].altText = _('babel.link_translation'); - return 'icon-link icon-babel-actioncolumn-img'; - } else { - var ctx = meta.id.substr('linkedres_id_'.length); - var pagetitle = rec.get('linkedres_pagetitle_' + ctx); - this.items[1].tooltip = _('babel.unlink') + ': ' + pagetitle; - this.items[1].altText = _('babel.unlink') + ': ' + pagetitle; - return 'icon-unlink icon-babel-actioncolumn-img'; - } - } - }); - - columns.push({ - header: item.key, - width: 70, - sortable: false, - id: 'linkedres_id_' + item.key, - dataIndex: 'linkedres_id_' + item.key, // 'id' conflicts with Indonesian's ISO code 'id' - xtype: 'actioncolumn', - items: actionItems - }); - }); - } - - var cm = new Ext.ux.grid.LockingColumnModel({ - columns: columns - }); - var view = new Ext.ux.grid.LockingGridView({ - syncHeights: true - }); - - Ext.applyIf(config, { - id: 'babel-grid-resourcematrix', - url: Babel.config.connectorUrl, - baseParams: { - action: 'mgr/resource/getMatrixList', - contexts: contexts.toString() - }, - fields: fields, - paging: true, - remoteSort: true, - anchor: '100%', - colModel: cm, - view: view, - autoHeight: false, - tbar: [ - { - xtype: 'babel-combo-context', - id: 'babel-combo-context' - }, { - xtype: 'textfield', - id: 'babel-search-resource', - width: 300, - emptyText: _('babel.search...') - }, { - text: _('babel.filter'), - handler: function () { - var ctx = Ext.getCmp('babel-combo-context').getValue(); - var qry = Ext.getCmp('babel-search-resource').getValue(); - this.baseParams.context = ctx; - this.baseParams.query = qry; - this.getBottomToolbar().changePage(1); - this.refresh(); - }, - scope: this - }, { - text: _('babel.reset'), - handler: function () { - Ext.getCmp('babel-combo-context').reset(); - Ext.getCmp('babel-combo-context').setValue(null); - Ext.getCmp('babel-search-resource').reset(); - this.baseParams.context = ''; - this.baseParams.query = ''; - this.getBottomToolbar().changePage(1); - this.refresh(); - } - } - ] - }); - - Babel.grid.ResourceMatrix.superclass.constructor.call(this, config); - - var originalHeight = this.getHeight(); - this.store.on('load', function(store, records, options){ - // fixing height - var scrollerHeight = this.getView().scroller.dom.children[0].offsetHeight; - var tbarHeight = this.getTopToolbar().getHeight(); - this.setHeight(tbarHeight + originalHeight + scrollerHeight + 4); - - }, this); - -}; -Ext.extend(Babel.grid.ResourceMatrix, MODx.grid.Grid, { - linkTranslation: function (ctx, id) { - var win = MODx.load({ - xtype: 'modx-window', - title: _('babel.link_translation'), - url: Babel.config.connectorUrl, - baseParams: { - action: 'mgr/resource/link', - context: ctx, - id: id - }, - listeners: { - success: { - fn: function (r) { - MODx.msg.status({ - title: _('success'), - message: r.message || _('save_successful') - }); - this.hideGridMask(); - this.refresh(); - }, - scope: this - }, - failure: { - fn: function (r) { - this.hideGridMask(); - }, - scope: this - }, - beforeSubmit: { - fn: function (r) { - this.loadGridMask(); - }, - scope: this - } - }, - fields: [ - { - xtype: 'textfield', - fieldLabel: _('context'), - disabled: true, - emptyText: ctx - }, { - xtype: 'modx-field-parent-change', - fieldLabel: _('babel.select_tree_node'), - id: '', - anchor: '100%', - name: 'target-combo', - end: function (p) { - var t = Ext.getCmp('modx-resource-tree'); - if (!t) - return; - p.d = p.d || p.v; - if (p.c !== ctx) { - return; - } - t.removeListener('click', this.handleChangeParent, this); - t.on('click', t._handleClick, t); - t.disableHref = false; - - win.fp.getForm().findField('target').setValue(p.v); - win.fp.getForm().findField('page_id').setValue(null); - this.setValue(p.d); - this.oldValue = false; - }, - disableTreeClick: function () { - MODx.debug('Disabling tree click'); - var t = Ext.getCmp('modx-resource-tree'); - if (!t) { - MODx.debug('No tree found in disableTreeClick!'); - return false; - } - this.oldDisplayValue = this.getValue(); - this.oldValue = win.fp.getForm().findField('target').getValue(); - - this.setValue(_('resource_parent_select_node')); - - t.expand(); - t.removeListener('click', t._handleClick); - t.on('click', this.handleChangeParent, this); - t.disableHref = true; - - return true; - }, - handleChangeParent: function (node, e) { - var t = Ext.getCmp('modx-resource-tree'); - if (!t) { - return false; - } - t.disableHref = true; - - var id = node.id.split('_'); - id = id[1]; - if (id == this.config.currentid) { - MODx.msg.alert('', _('resource_err_own_parent')); - return false; - } - - this.fireEvent('end', { - v: node.attributes.type !== 'modContext' ? id : node.attributes.pk, - d: Ext.util.Format.stripTags(node.text), - c: node.attributes.ctx - }); - e.preventDefault(); - e.stopEvent(); - return true; - } - }, { - xtype: 'modx-combo', - fieldLabel: _('babel....or') + ' ' + _('babel.pagetitle_of_target'), - name: 'page_id', - anchor: '100%', - url: Babel.config.connectorUrl, - baseParams: { - action: 'mgr/resource/getlist', - context: ctx, - combo: true - }, - displayField: 'pagetitle', - valueField: 'id', - fields: ['id', 'pagetitle'], - editable: true, - typeAhead: true, - forceSelection: false, - listeners: { - select: { - fn: function (combo, record, index) { - var val = combo.getValue(); - if (val === "" || val === 0 || val === " ") { - combo.setValue(null); - } else { - win.fp.getForm().findField('target').setValue(record.id); - } - win.fp.getForm().findField('target-combo').reset(); - }, - scope: this - }, - blur: { - fn: function (combo) { - var val = combo.getValue(); - if (val === "" || val === 0 || val === " ") { - combo.setValue(null); - } - }, - scope: this - } - } - }, { - fieldLabel: _('babel.id_of_target'), - xtype: 'numberfield', - name: 'target', - enableKeyEvents: true, - listeners: { - keyup: { - fn: function(field, e) { - win.fp.getForm().findField('target-combo').reset(); - win.fp.getForm().findField('page_id').reset(); - }, - scope: this - } - } - }, { - xtype: 'xcheckbox', - boxLabel: _('babel.copy_tv_values'), - name: 'copy-tv-values' - }, { - xtype: 'xcheckbox', - boxLabel: _('babel.sync_linked_tranlations'), - name: 'sync-linked-tranlations', - checked: true - } - ] - }); - win.reset(); - win.show(); - }, - unlinkTranslation: function (ctx, id, target) { - var _this = Ext.getCmp('babel-grid-resourcematrix'); - _this.loadGridMask(); - ctx = ctx || ''; - target = parseInt(target) || 0; - var text = ''; - if (target === 0) { - text = _('babel.unlink_all_translations_confirm'); - } else { - text = _('babel.unlink_translation_confirm', {context: ctx, id: id}); - } - return MODx.msg.confirm({ - title: _('confirm'), - text: text, - url: Babel.config.connectorUrl, - params: { - action: 'mgr/resource/unlink', - context: ctx, - id: id, - target: target - }, - listeners: { - success: { - fn: function (r) { - MODx.msg.status({ - title: _('success'), - message: r.message || _('save_successful') - }); - _this.hideGridMask(); - _this.refresh(); - } - }, - failure: { - fn: function (r) { - _this.hideGridMask(); - } - }, - cancel: { - fn: function (r) { - _this.hideGridMask(); - } - } - } - }); - }, - createTranslation: function (ctx, id) { - var _this = Ext.getCmp('babel-grid-resourcematrix'); - _this.loadGridMask(); - return MODx.msg.confirm({ - title: _('confirm'), - text: _('babel.create_translation_confirm', {context: ctx, id: id}), - url: Babel.config.connectorUrl, - params: { - action: 'mgr/resource/duplicate', - context_key: ctx, - id: id - }, - listeners: { - success: { - fn: function (r) { - _this.hideGridMask(); - MODx.loadPage('resource/update', 'id=' + r.object.id); - } - }, - failure: { - fn: function (r) { - _this.hideGridMask(); - } - }, - cancel: { - fn: function (r) { - _this.hideGridMask(); - } - } - } - }); - }, - loadGridMask: function () { - if (!this.overlayMask) { - var domHandler = Ext.getBody().dom; - this.overlayMask = new Ext.LoadMask(domHandler, { - msg: _('babel.please_wait') - }); - } - this.overlayMask.show(); - }, - hideGridMask: function () { - if (this.overlayMask) { - this.overlayMask.hide(); - } - } -}); -Ext.reg('babel-grid-resourcematrix', Babel.grid.ResourceMatrix); diff --git a/assets/components/babel/js/mgr/widgets/panel.home.js b/assets/components/babel/js/mgr/widgets/panel.home.js deleted file mode 100644 index 2da74f5..0000000 --- a/assets/components/babel/js/mgr/widgets/panel.home.js +++ /dev/null @@ -1,80 +0,0 @@ -Babel.panel.Home = function (config) { - config = config || {}; - Ext.applyIf(config, { - border: false, - baseCls: 'modx-formpanel', - cls: 'container', - items: [ - { - html: '

' + _('babel') + '

', - border: false, - cls: 'modx-page-header' - }, { - html: _('babel.icon_descriptions', {'base_url': MODx.config.base_url}), - cls: 'panel-desc' - }, { - id: 'babel-grid-resourcematrix-holder', - preventRender: true, - border: false, - listeners: { - 'afterrender': { - fn: function (tabPanel) { - this.getContexts('getResourceGrid'); - }, - scope: this - } - } -// xtype: 'babel-grid-resourcematrix', -// cls: 'main-wrapper', -// preventRender: true - } - ] - }); - Babel.panel.Home.superclass.constructor.call(this, config); - -}; -Ext.extend(Babel.panel.Home, MODx.Panel, { - contexts: [], - getContexts: function(callback) { - if (this.contexts.length > 0) { - if (typeof(this[callback]) === 'function') { - return this[callback].call(this, this.config); - } - return this.contexts; - } - return MODx.Ajax.request({ - url: Babel.config.connectorUrl, - params: { - action: 'mgr/context/getlist', - exclude: 'mgr' - }, - listeners: { - 'success': { - fn: function (r) { - if (r.success) { - this.contexts = r.results; - if (this.contexts.length > 0 && typeof(this[callback]) === 'function') { - return this[callback].call(this, this.config); - } - } - }, - scope: this - } - } - }); - }, - getResourceGrid: function() { - if (this.contexts.length < 1) { - return; - } - MODx.load({ - xtype: 'babel-grid-resourcematrix', - record: this.contexts, - cls: 'main-wrapper', - preventRender: true, - applyTo: 'babel-grid-resourcematrix-holder' - }); - } -}); - -Ext.reg('babel-panel-home', Babel.panel.Home); \ No newline at end of file diff --git a/core/components/babel/composer.json b/core/components/babel/composer.json new file mode 100644 index 0000000..e0ddd66 --- /dev/null +++ b/core/components/babel/composer.json @@ -0,0 +1,42 @@ +{ + "name": "mikrobi/babel", + "description": "The easy way for your multilingual site!", + "authors": [ + { + "name": "Jakob Class", + "email": "jakob.class@gmail.com", + "homepage": "https://github.com/mikrobi" + }, + { + "name": "Rico Goldsky", + "email": "goldsky@virtudraft.com", + "homepage": "https://github.com/goldsky" + }, + { + "name": "Joshua Luckers", + "email": "joshualuckers@me.com", + "homepage": "https://github.com/JoshuaLuckers" + }, + { + "name": "Thomas Jakobi", + "email": "office@treehillstudio.com", + "homepage": "https://treehillstudio.com" + } + ], + "license": "GPL-2.0-or-later", + "config": { + "platform": { + "php": "7.2" + } + }, + "require": { + "php": ">=7.2", + "ext-json": "*", + "ext-pdo": "*" + }, + "autoload": { + "psr-4": { + "mikrobi\\Babel\\": "src/" + } + } +} diff --git a/core/components/babel/composer.lock b/core/components/babel/composer.lock new file mode 100644 index 0000000..28edd0f --- /dev/null +++ b/core/components/babel/composer.lock @@ -0,0 +1,25 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "8112a3c4c82f4c4e4f54cb4d6752efc6", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.2", + "ext-json": "*", + "ext-pdo": "*" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.2" + }, + "plugin-api-version": "2.3.0" +} diff --git a/core/components/babel/controllers/default/index.class.php b/core/components/babel/controllers/default/index.class.php index 4101770..cce678f 100644 --- a/core/components/babel/controllers/default/index.class.php +++ b/core/components/babel/controllers/default/index.class.php @@ -1,55 +1,98 @@ babel = new Babel($this->modx); - $this->addCss($this->babel->config['cssUrl'].'babel.css'); - $this->addCss($this->babel->config['cssUrl'].'cmp.css'); - $this->addJavascript($this->babel->config['jsUrl'].'mgr/babel.js'); + $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath + ]); + } + + /** + * {@inheritDoc} + */ + public function loadCustomCssJs() + { + $assetsUrl = $this->babel->getOption('assetsUrl'); + $jsUrl = $this->babel->getOption('jsUrl') . 'mgr/'; + $jsSourceUrl = $assetsUrl . '../../../source/js/mgr/'; + $cssUrl = $this->babel->getOption('cssUrl') . 'mgr/'; + $cssSourceUrl = $assetsUrl . '../../../source/css/mgr/'; + + if ($this->babel->getOption('debug') && ($this->babel->getOption('assetsUrl') != MODX_ASSETS_URL . 'components/babel/')) { + $this->addCss($cssSourceUrl . 'babel.css?v=v' . $this->babel->version); + $this->addJavascript($jsSourceUrl . 'babel.js?v=v' . $this->babel->version); + $this->addJavascript($jsSourceUrl . 'helper/combo.js?v=v' . $this->babel->version); + $this->addJavascript($jsSourceUrl . '../ux/LockingGridView/LockingGridView.js?v=v' . $this->babel->version); + $this->addJavascript($jsSourceUrl . 'widgets/resourcematrix.grid.js?v=v' . $this->babel->version); + $this->addJavascript($jsSourceUrl . 'widgets/home.panel.js?v=v' . $this->babel->version); + $this->addJavascript(MODX_MANAGER_URL . 'assets/modext/widgets/core/modx.grid.settings.js'); + $this->addJavascript($jsSourceUrl . 'widgets/settings.panel.js?v=v' . $this->babel->version); + $this->addLastJavascript($jsSourceUrl . 'sections/index.js?v=v' . $this->babel->version); + } else { + $this->addCss($cssUrl . 'babel.min.css?v=v' . $this->babel->version); + $this->addJavascript(MODX_MANAGER_URL . 'assets/modext/widgets/core/modx.grid.settings.js'); + $this->addJavascript($jsUrl . 'babel.min.js?v=v' . $this->babel->version); + } + $this->addHtml(''); - return parent::initialize(); } + /** + * {@inheritDoc} + * @return string[] + */ public function getLanguageTopics() { - return ['babel:default', 'babel:cmp']; - } - - public function loadCustomCssJs() - { - $this->addJavascript($this->babel->config['jsUrl'].'mgr/widgets/combo.context.js'); - $this->addCss($this->babel->config['jsUrl'].'ux/LockingGridView/LockingGridView.css'); - $this->addJavascript($this->babel->config['jsUrl'].'ux/LockingGridView/LockingGridView.js'); - $this->addJavascript($this->babel->config['jsUrl'].'mgr/widgets/grid.resourcematrix.js'); - $this->addJavascript($this->babel->config['jsUrl'].'mgr/widgets/panel.home.js'); - $this->addLastJavascript($this->babel->config['jsUrl'].'mgr/sections/index.js'); + return ['core:setting', 'babel:default']; } + /** + * {@inheritDoc} + * @param array $scriptProperties + */ public function process(array $scriptProperties = []) { - } + /** + * {@inheritDoc} + * @return string|null + */ public function getPageTitle() { return $this->modx->lexicon('babel'); } + /** + * {@inheritDoc} + * @return string + */ public function getTemplateFile() { - return 'index.tpl'; + return $this->babel->getOption('templatesPath') . 'index.tpl'; } } diff --git a/core/components/babel/docs/changelog.md b/core/components/babel/docs/changelog.md new file mode 100644 index 0000000..2a39461 --- /dev/null +++ b/core/components/babel/docs/changelog.md @@ -0,0 +1,305 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [3.2.0] - 2024-02-07 + +### Changed + +- Code refactoring +- Modernized the user experience + +### Added + +- Show the Babel button only on resources in contexts referenced in `babel.contextKeys` system setting +- Show the context column in the custom manager page only for contexts referenced in `babel.contextKeys` system setting +- System settings tab in custom manager page +- Change the Babel button text by the `babel.displayText` system setting (language, context or combination) +- Show all contexts in the Babel button by disabling the `babel.restrictToGroup` system setting +- New snippet property `restrictToGroup` for the BabelLinks snippet. + +### Fixed + +- Set context grid height on base of the content + +## [3.1.1] - 2021-05-26 + +### Fixed + +- [#189] Fix various bugs - thanks to Jako + +## [3.1.0] - 2021-11-21 + +### Added + +- Add MODX 3.x compatability +- Add various new translations +- [#176] Accept a comma separated list of IDs in resourceId property of the BabelTranslation snippet +- [#168] Invoke OnDocFormSave event when duplicating a resource + +### Fixed + +- Fix minor bugs + +## [3.0.0] - 2016-12-12 + +### Added + +- [#143] Link to a translation by entering the ID +- [#134] Add Babel System Events - thanks to Jako +- [#147] Initiated language code standard using IANA's Language Subtag Registry +- Add options to link to specific resource or all resources +- [#144] Add options to unlink to specific resource or all resources +- Add config to set table's height +- Add styling to align table in CMP +- Initialized PSR-2 coding standard https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md + +### Changed + +- [#123] Minor cosmetic update +- Resource title's width + +### Fixed + +- [#135] Fix not found icons +- [#145] Fix unlinking unsync TVs +- [#139][#140] Fix Unable to link translations by searching by pagetitle + +## [3.0.0-rc1] - 2016-04-15 + +### Added + +- Add Custom Manager Page for resources matrix, supported by Steven Morgan of Waterlogic + +## [3.0.0-beta5] - 2016-03-22 + +### Added + +- [#103] Add mouseover action on babel's button to show menu +- [#115] Add language property in BabelLinks snippet + +### Changed + +- Ignore the menu if the current context key is not included in `babel.contextKeys` System Settings +- Change empty item on combobox +- Change link & unlink logic, no reset whatsoever +- [#107] Replace contextKey with cultureKey in the button drop down +- [#110] Update dutch lexicon + +### Fixed + +- [#66] Fix moving resource to another context +- [#114] Fix context on linking + +## [3.0.0-beta4] - 2015-03-25 + +### Added + +- [#105] Add `babel.ignoreSiteStatus` system setting to ignore site_status (when the site is offline) + +### Fixed + +- [#108] Fix context's link then there's no translation available when the includeUnlinked property is enabled +- [#106] Fix resource selection when selecting empty text ( ) + +## [3.0.0-beta3] - 2015-02-14 + +### Added + +- [#100] Add optional typeahead combo of pagetitle on searching new link +- [#99] Add polish lexicon + +### Fixed + +- [#101] Fix BabelTranslation + +## [3.0.0-beta2] - 2014-12-02 + +### Added + +- Add optional toArray property to BabelLinks snippet +- Add optional toPlaceholder property to BabelLinks snippet +- Add optional wrapperTpl property to BabelLinks snippet +- Add icons +- [#97] Add russian lexicon +- [#73] Add AjaxManager support + +### Changed + +- Remove "q" and "cultureKey" url parameters in urls generated in the BabelLinks snippet + +## [3.0.0-beta1] - 2014-11-28 + +### Added + +- [#51] Append URL parameters of current page if any +- Add includeUnlinked property to BabelLinks snippet, option to skip/include unlinked context +- [#88] Skip unpublished contexts +- [#78][#62] Add outputSeparator property to BabelLinks snippet +- [#67] Add italian lexicon +- [#60] Add dutch lexicon + +### Changed + +- [#77] Update readme.txt +- [#82] Check for resourceId property before defaulting +- [#75] Replaced deprecated method clearCache() with refresh() +- [#84] Optimize OnResourceDuplicate plugin event +- [#44][#29] Use cultureKey instead of contextKey in the output of the BabelTranslation snippet +- [#27][#90][#92] Refactor language selection, runs using AJAX +- [#83][#59] Extend OnResourceDuplicate plugin event for nested resources + +### Fixed + +- [#56] Emptying the MODX trash can corrupt values in modx_site_tmplvar_contentvalues +- [#70] fix is_folder to isfolder +- [#58][#64] Fix the error with updating a resource, at least in the quick update window + +## [2.2.5] - 2011-12-11 + +### Added + +- Extended list of languages in translation files +- Add Romanian lexicon + +### Fixed + +- [#31] Make babel buttons fixed in manager and change the look accordingly + +## [2.2.4] - 2011-03-28 + +### Added + +- [#22] Add showCurrent property to BabelLinks snippet + +### Fixed + +- [#25] Correctly synchronize unchecked "checkbox" TVs + +## [2.2.3-rc1] - 2011-01-26 + +### Added + +- [#18] Add id placeholder to the BabelLink chunk used by the BabelLinks snippet + +### Fixed + +- [#21] Fix Manager redirect causes error in Google Chrome browser + +## [2.2.2-rc2] - 2011-01-17 + +### Fixed + +- Fix initial synchronization of TV values when setting a link manually didn't work + +## [2.2.2-rc1] - 2011-01-14 + +### Added + +- [#16] Values of synchronized TVs of the source resource(s) can be copied to the target resource when setting a translation link manually +- Add showUnpublished property to BabelLinks and BabelTranslation snippets + +## [2.2.1-rc1] - 2011-01-09 + +### Added + +- [#11] User is redirect to new resource after creating a translation + +### Fixed + +- [#15] Fix Babel TV of duplicated resources is being initiated +- Alias is duplicated when creating a translation, too + +## [2.2.0-pl] - 2010-12-22 + +### Added + +- [#10] Add checks to handle invalid Babel settings (defined by the user) + +### Added + +- Improved performance of TV synchronization + +### Fixed + +- Fix bug occuring when creating new resources +- Fix bug in validation when setting a link manually + +## [2.1.1-pl1] - 2010-12-21 + +### Fixed + +- [#9] Calling deprecated and non-existing method in Babel class + +## [2.1.1-rc1] - 2010-12-19 + +### Added + +- Add resourceId property to BabelLinks snippet +- Add French translation for new keys from version 2.1.0-beta +- Add BabelTranslation snippet to get the id of a translated resource in a given context + +### Changed + +- Protect the Babel TV from being manipulated manually by setting the type to 'hidden' by default + +### Fixed + +- Fix bug with empty babel settings (contextKeys and syncTvs) + +## [2.1.0-beta] - 2010-12-17 + +### Added + +- Add french lexicon. Thanks to Romain +- New Babel-Box: + - A chunk is used to generate the language links (mgr/babelBoxItem) + - Changed CSS + - Add JavaScript (for the langauge layers, see below) + - All languages (contexts) of current group are displayed even if there are no links defined + - If there is no link to a language it's background is light gray + - When mouseovering a language link a layer is displayed where you can + - create a translation (new resource) if no link is defined + - manually link the translation to an existing resource if no link is defined + - remove a link if a link is defined +- Add validation to keep the babel TV clear +- Add several keys to the lexicon + +## [2.0.0-beta] - 2010-12-16 + +### Added + +- Add build script +- Add multilanguage support for the extra itself +- Easier but more powerfull configuration: + No need to specify names/caption of context anymore (caption is derived from the contexts' cultureKey) + 3 system settings which can be set during package installation + * babel.contextKeys: + Define which context should be used to link translation + Defining several groups of context is supported, too (see readme.txt) + * babel.babelTvName: + Name of TV in which links between translated resources are keept + * babel.syncTvs: + IDs of TVs which should be synchronized by Babel +- Plugin listens to OnEmptyTrash event to remove links to non-existing resources stored in the Babel TV +- Plugin listens to OnContextRemove event to remove links to non-existing context stored in the Babel TV and to clean the `babel.contextKeys` setting + +### Changed + +- Total reengineering of the whole extra (code structure and logic, too) => NOT BACKWARD COMPATIBLE +- Moved CSS into asset folder +- Moved codebase to https://github.com/mikrobi/babel/ +- This version is NOT BACKWARD COMPATIBLE to older versions + +### Fixed + +- Fix issue with primary key validation errors when linking the Babel TV to templates + +## [1.0.0] - 2010-12-13 + +### Added + +- Initial release from Sylvain Aerni see https://github.com/enzyms/babel diff --git a/core/components/babel/docs/changelog.txt b/core/components/babel/docs/changelog.txt deleted file mode 100644 index 1d68365..0000000 --- a/core/components/babel/docs/changelog.txt +++ /dev/null @@ -1,179 +0,0 @@ -Changelog for Babel. - -Babel 3.1.1-pl (May 26, 2021) -- [#189] Fix various bugs - thanks to Thomas Jakobi https://treehillstudio.com - -Babel 3.1.0-pl (November 21, 2021) -===================================== -- Add MODX 3.x compatability -- Fix minor bugs -- Add various new translations -- [#176] Accept a comma separated list of IDs in resourceId property (BabelTranslation snippet) -- [#168] Invoke OnDocFormSave event when duplicating a resource - -Babel 3.0.0-pl (December 12, 2016) -===================================== -- [#135] Fixed not found icons -- [#143] Link to a translation by entering the ID -- [#134] Added Babel System Events - thanks to Jako -- [#147] Initiated language code standard using IANA's Language Subtag Registry -- [#145] bugfixed unlinking unsync TVs -- added options to link to specific resource or all resources -- [#144] added options to unlink to specific resource or all resources -- [#123] Minor cosmetic update -- [#139][#140] Fixed Unable to link translations by searching by pagetitle -- fixed resource title's width -- added config to set table's height -- added styling to align table in CMP -- initialized PSR-2 coding standard https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md - -Babel 3.0.0-rc1 (April 15, 2016) -===================================== -- added Custom Manager Page for resources matrix, supported by Steven Morgan of Waterlogic - -Babel 3.0.0-beta5 (March 22, 2016) -===================================== -- updated plugin to ignore menu if the current context key is not included "babel.contextKeys" in System Settings -- changed empty item on combobox -- changed link & unlink logics, no reset whatsoever -- [#103] Added mouseover action on babel's button to show menu -- [#66] fixed moving resource to another context -- [#107] Replaced contextKey with cultureKey on drop down selection -- [#114] Fixed context on linking -- [#115] BabelLinks: Add &language Parameter -- [#110] Updated dutch lexicon - -Babel 3.0.0-beta4 (March 25, 2015) -===================================== -- [#105] add &ignoreSiteStatus option to ignore site_status (when the site is offline) -- [#108] fix context's link then there's no translation on &includeUnlinked=`1` option -- [#106] fix resource selection when selecting empty text ( ) - -Babel 3.0.0-beta3 (February 14, 2015) -===================================== -- [#101] fix BabelTranslation -- [#100] add optional typeahead combo of pagetitle on searching new link -- [#99] Polish translation - -Babel 3.0.0-beta2 (December 2, 2014) -==================================== -- remove "q" and "cultureKey" url parameters on BabelLinks -- add optional &toArray property to BabelLinks snippet -- add optional &toPlaceholder property to BabelLinks snippet -- add optional &wrapperTpl property to BabelLinks snippet -- add icons -- [#97] Add ru lexicon -- [#73] Add AjaxManager support - -Babel 3.0.0-beta1 (November 28, 2014) -===================================== -- [#77] Update readme.txt -- [#51] Append URL parameters of current page if any -- add &includeUnlinked property to BabelLinks, option to skip/include unlinked context -- [#56] Emptying the MODX trash can corrupt values in modx_site_tmplvar_contentvalues -- [#88] Skip unpublished contexts -- [#82] Check for resourceId parameter before defaulting. -- [#78][#62] added outputSeparator for BabelLinks -- [#75] Replaced deprecated method clearCache() with refresh() -- [#84] optimize OnResourceDuplicate -- [#44][#29] Using cultureKey instead of contextKey on BabelTranslation snippet -- [#70] fix is_folder to isfolder -- [#27][#90][#92] Refactor language selection, runs using AJAX -- [#83][#59] extend babel plugin OnResourceDuplicate for nested resources -- [#67] italian translation -- [#60] Added Dutch translation -- [#58][#64] Fixed the error with updating a resource, at least in the quick update window - -Babel 2.2.5-pl -============== -- Extended list of languages in translation files and added Romanian translation. -- Issue #31: Maked babel buttons in manager position fixed and changed look accordingly. - -Babel 2.2.4-pl -============== -- Fixed issue #25: Unchecked "checkbox" TVs are now synchronized correctly. -- Issue #22: Added showCurrent parameter to BabelLinks snippet. - -Babel 2.2.3-rc1 -============== -- Issue #18: Added 'id' placeholder for BabelLink chunk which is used by the BabelLinks snippet. -- Fixed issue #21: Manager redirect causes error in Google Chrome browser. - -Babel 2.2.2-rc2 -============== -- Fixed bug: Initial synchronization of TV values when setting a link manually didn't work. - -Babel 2.2.2-rc1 -============== -- Added feature #16: Values of synchronized TVs of the source resource(s) can be copied to the target resource when setting a translation link manually. -- Added showUnpublished parameter to BabelLinks and BabelTranslation snippets. - -Babel 2.2.1-rc1 -============== -- Added feature #11: User is redirect to new resource after creating a translation. -- Fixed issue #15: Babel TV of duplicated resources is being initiated. -- Alias is duplicated when creating an translation, too. - -Babel 2.2.0-pl -============== -- Fixed bug which occured when creating new resources. -- Fixed bug in validation which is performed on setting a link manually. -- Improved performance of TV synchronization. -- Regarding issue #10: Added checks to handle invalid Babel settings (defined by the user). - -Babel 2.1.1-pl1 -============== -- Fixed issue #9: Calling deprecated and non-existing method in babel.class - -Babel 2.1.1-rc1 -============== -- Added &resourceId parameter to BabelLinks snippet. -- Added French translation for new keys from version 2.1.0-beta. -- Added BabelTranslation snippet to get the id of a translated resource in a given context. -- Fixed bug with empty babel settings (contextKeys and syncTvs). -- In order to protect the Babel TV from being manipulated manually its type is set to 'hidden' by default. - -Babel 2.1.0-beta -============== -- Added Frech translation: Thanks to Romain -- New Babel-Box: - - A chunk is used to generate the language links (mgr/babelBoxItem). - - Changed CSS. - - Added JavaScript (for the langauge layers, see below). - - All languages (contexts) of current group are displayed even if there are no links defined. - - If there is no link to a language it's background is light gray. - - When mouseovering a language link a layer is displayed where you can - - create a translation (new resource) if no link is defined. - - manually link the translation to an existing resource if no link is defined. - - remove a link if a link is defined. - - Added validation to keep the babel TV clear - - Added several keys to the lexicon: French translation still pending. - -Babel 2.0.0-beta -============== -- Total reengineering of the whole extra (code structure and logic, too). - => NOT BACKWARD COMPATIBLE to older versions. -- Fixed issue with primary key validation errors when linking the Babel TV to templates -- Added build script -- Added multilanguage support for the extra itself -- Easier but more powerfull configuration: - No need to specify names/caption of context anymore (caption is derived from the contexts' cultureKey). - 3 system settings which can be set during package installation. - * babel.contextKeys: - Define which context should be used to link translation. - Defining several groups of context is supported, too (see readme.txt). - * babel.babelTvName: - Name of TV in which links between translated resources are keept. - * babel.syncTvs: - IDs of TVs which should be synchronized by Babel. -- Moved CSS into asset folder -- Moved codebase to https://github.com/mikrobi/babel/ -- Plugin listens to OnEmptyTrash event to remove links to non-existing resources stored in the Babel TV -- Plugin listens to OnContextRemove event to remove links to non-existing context stored in the Babel TV - and to clean the babel.contextKeys setting -- This version is NOT BACKWARD COMPATIBLE to older versions - - -Babel 1.0.0 -============== -- Initial release from Sylvain Aerni see https://github.com/enzyms/babel \ No newline at end of file diff --git a/core/components/babel/docs/license.md b/core/components/babel/docs/license.md new file mode 100644 index 0000000..997cdc8 --- /dev/null +++ b/core/components/babel/docs/license.md @@ -0,0 +1,287 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 +-------------------------- + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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 diff --git a/core/components/babel/docs/readme.md b/core/components/babel/docs/readme.md new file mode 100644 index 0000000..e8c1b5b --- /dev/null +++ b/core/components/babel/docs/readme.md @@ -0,0 +1,40 @@ +# Babel + +The easy way for your multilingual site! + +- Authors: Jakob Class , Rico Goldsky + , Joshua Luckers , Thomas Jakobi + +- License: GNU GPLv2 + +## Features + +Babel is an Extra for MODx Revolution that helps you to manage your multilingual +websites using different contexts. Babel even supports managing several different +multilingual websites within one MODx instance by using so-called context groups. + +Babel maintains links between translated resources. In the manager you can use +the Babel Box to easily switch between the different language versions +of your resources. Translations can be created automatically by Babel or defined +manually. + +Additionally, Babel can be used to synchronize certain template variables (TVs) +of translated resources which should be the same in every context (language). + +## Installation + +MODX Package Management + +## Usage + +Install via package manager and fill the system setting `babel.contextKeys` with +a comma separated list of context keys which should be used to link multilingual +resources. + +## Documentation + +For more information please read the documentation on https://mikrobi.github.io/babel/ + +## GitHub Repository + +https://github.com/Jako/Babel diff --git a/core/components/babel/docs/readme.txt b/core/components/babel/docs/readme.txt deleted file mode 100644 index ebbb28e..0000000 --- a/core/components/babel/docs/readme.txt +++ /dev/null @@ -1,201 +0,0 @@ --------------------- -Babel --------------------- -Author: Jakob Class - goldsky - -License: GNU GPLv2 (or later at your option) --------------------- - -Babel is an Extra for MODx Revolution that helps you managing your multilingual -websites using different contexts. Babel even supports managing several different -multilingual websites within one MODx instance by using so called context groups. - -Babel maintains links between translated resources. In the manager you can use -the Babel Box to easily switch between the different language versions -of your resources. Translations can be created automatically by Babel or defined -manually. - -Additionally Babel can be used to synchronize certain template variables (TVs) -of translated resources which should be the same in every context (language). - -Feel free to suggest ideas/improvements/bugs on GitHub: -https://github.com/mikrobi/babel/issues - - -IMPORTANT: Upgrading from version < 2.0.0: -==================== - -Babel is based on ideas of Sylvain Aerni and has been completely -reengineered in version 2.0.0 and is NOT BACKWARD COMPATIBLE to older versions. -If you're using an older version of Babel you have to uninstall and remove that -version first. - - -Installation -==================== - -0. Create a context for each language and set the cultureKey and site_url settings - according to your needs. You may refer to our tutorial to setup your - multilingual site(s): - http://www.multilingual-modx.com/blog/2011/multilingual-websites-with-modx-and-babel.html - - Be sure that your context switches work well. - -1. Install Babel via the package manager and set the system settings for Babel via - the form displayed during setup: - - Context Keys (babel.contextKeys): - Comma separated list of context keys which should be used to link - multilingual resources. - For advanced configuration you may define several groups of context keys - by using a semicolon (;) as delimiter. This is usefull if your're - administrating multiple multilingual sites within one MODx instance. - Example scenario: - site1: en, de, fr. Using contexts: web, site1de, site1fr - site2: en, de. Using contexts: site2en, site2de - You would set babel.contextKeys to "web,site1de,site1fr;site2en,site2de". - - - Name of Babel TV (babel.babelTvName): - Name of template variable (TV) in which Babel will store the links between - multilingual resources this TV will be maintained by Babel. Please don't - change this TV manually otherwhise your translation links may be broken. - - - IDs of TVs to be synchronized (babel.syncTvs): - Comma separated list of ids of template variables (TVs) which should be - synchronized by Babel. - - -Usage -==================== - -When you open a resource for editing, the Babel Box -will be displayed on top of the resource form. There will be button-like links for -each language (context) you have defined in the babel.contextKeys system setting. - -The buttons may have three different colors according to their state: -- Black: - Language of the currently displayed resource. -- Green: - Language for which a translated resource is defined. -- Light Gray: - Language for which no translation has been created or defined yet. - -By clicking on the (green) language buttons you can easily switch between the -different language versions of your resources. - -If there are no translations defined for certain language (gray button), -mousover the language's button: a layer appears where you can tell Babel to -create a translation of the current resource or you can set the translation link -to an existing resource manually by entering the ID of the translated resource. - -When clicking on "Create Translation" Babel will create a new resource in the -language's context and copy all the content of the current resource to the newly -created resource. You now can translated all the content and TVs and publish -the translated resource. - -If you'd like to remove a translation link, just mouseover the (green) language -button: a layer appears where you can click on "Unlink translation" button to -remove the translation link to this language. - - -Snippet usage -==================== - -Currently there are two snippets available for Babel: -BabelLinks and BabelTranslation. - - -BabelLinks --------------------- -BabelLinks is a snippet which displays links to other languages (contexts) -in the frontend. You can call the snippet in your templates like this: - -
    - [[BabelLinks]] -
- -The following parameters are supported by BabelLinks: -- resourceId (optional): - ID of resource of which links to translations should be displayed. - Default: current resource's ID. -- tpl (optional): - Chunk to display a language link. - Default: babelLink. -- activeCls (optional): - CSS class name for the current active language. - Default: active. -- showUnpublished (optional): - Flag whether to show unpublished translations. - Default: 0 -- showCurrent (optional): - Flag whether to show a link to a translation of the current language. - Default: 0 -- includeUnlinked (optional): - Flag whether to show unlinked context. - Default: 0 - -You can use your own chunk to display the links - -[[BabelLinks? &tpl=`babelLink`]] - -In this Chunk you have access to the following placeholders: -- [[+url]]: - Url to linked translation (or site_url of specific language if there - is no translated resource available). -- [[+cultureKey]]: - Culture key of translation (e.g en, de, fr oder es). - You may use the babel lexicon to display the language's name: - [[%babel.language_[[+cultureKey]]? &topic=`default` &namespace=`babel`]] -- [[+active]]: - If link points to a resource of the current active language (context) - this placeholder is set to the active CSS class name specified by the - &activeCls parameter (default=active). Otherwise this placeholder is empty. -- [[+id]]: - ID of tranlated resource. If no translation is available this placeholder - is empty (''). - - -BabelTranslation --------------------- -The BabelTranslation snippets returns the ID of a translated resource in a -given context. - -The following parameters are supported by BabelLinks: -- resourceId (optional): - ID of resource of which a translated resource should be determined. - Default: current resource's ID. -- contextKey (required): - Key of context in which translated resource should be determined. -- showUnpublished (optional): - Flag whether to show unpublished translations. - Default: 0 - -Example usage: - -[[BabelTranslation? &contextKey=`de`]] - -This will return the ID of the translated resource located in the "de" context -of the current resource. - -Plugin Events -==================== - -Babel triggers some system events you could use in plugins. The following -events are available: - -OnBabelDuplicate: invoked on duplicating the resource in a new language context -OnBabelLink: invoked on link the resource with a target resource -OnBabelUnlink: invoked on unlink the resource from a target resource - -A generic plugin for the events could be found on GitHub: -https://github.com/Jako/BabelEvents - -You could use the plugins for i.e. an automatic translation of the resource -via a webservice. - - -Support -==================== - -Feel free to suggest ideas/improvements/bugs on GitHub: -https://github.com/mikrobi/babel/issues \ No newline at end of file diff --git a/core/components/babel/elements/chunks/babellink.chunk.tpl b/core/components/babel/elements/chunks/babellink.chunk.html similarity index 100% rename from core/components/babel/elements/chunks/babellink.chunk.tpl rename to core/components/babel/elements/chunks/babellink.chunk.html diff --git a/core/components/babel/elements/chunks/babellinkwrapper.chunk.tpl b/core/components/babel/elements/chunks/babellinkwrapper.chunk.html similarity index 100% rename from core/components/babel/elements/chunks/babellinkwrapper.chunk.tpl rename to core/components/babel/elements/chunks/babellinkwrapper.chunk.html diff --git a/core/components/babel/elements/plugins/babel.plugin.php b/core/components/babel/elements/plugins/babel.plugin.php index a582048..984c00d 100644 --- a/core/components/babel/elements/plugins/babel.plugin.php +++ b/core/components/babel/elements/plugins/babel.plugin.php @@ -1,168 +1,33 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ /** - * Babel Plugin to link and synchronize multilingual resources - * - * Based on ideas of Sylvain Aerni - * - * Events: - * OnDocFormPrerender,OnDocFormSave,OnEmptyTrash,OnContextRemove,OnResourceDuplicate - * - * @author Jakob Class - * goldsky + * Babel Plugin * * @package babel + * @subpackage plugin * + * @var modX $modx + * @var array $scriptProperties */ -$babel = $modx->getService('babel', 'Babel', $modx->getOption('babel.core_path', null, $modx->getOption('core_path').'components/babel/').'model/babel/'); - -/* be sure babel TV is loaded */ -if (!($babel instanceof Babel) || !$babel->babelTv) - return; - -switch ($modx->event->name) { - case 'OnDocFormPrerender': - $output = ''; - $errorMessage = ''; - $resource = & $modx->event->params['resource']; - if (!$resource) { - /* a new resource is being to created - * -> skip rendering the babel box */ - break; - } - $linkedResources = $babel->getLinkedResources($resource->get('id')); - if (empty($linkedResources)) { - /* always be sure that the Babel TV is set */ - $babel->initBabelTv($resource); - } - - /* create babel-box with links to translations */ - $outputLanguageItems = ''; - if (!$modx->lexicon) { - $modx->getService('lexicon', 'modLexicon'); - } - $languagesStore = []; - $contextKeys = $babel->getGroupContextKeys($resource->get('context_key')); - foreach ($contextKeys as $contextKey) { - /* for each (valid/existing) context of the context group a button will be displayed */ - $context = $modx->getObject('modContext', ['key' => $contextKey]); - if (!$context) { - $modx->log(modX::LOG_LEVEL_ERROR, 'Could not load context: '.$contextKey); - continue; - } - $context->prepare(); - $cultureKey = $context->getOption('cultureKey', $modx->getOption('cultureKey')); - $languagesStore[] = [$modx->lexicon('babel.language_'.$cultureKey)." ($contextKey)", $contextKey]; - } - - $babel->config['context_key'] = $resource->get('context_key'); - $babel->config['languagesStore'] = $languagesStore; - $babel->config['menu'] = $babel->getMenu($resource); - if (empty($babel->config['menu'])) { - $modx->log(modX::LOG_LEVEL_ERROR, '[Babel] Could not load menu for context key: "'.$babel->config['context_key'].'". Try to check "babel.contextKeys" in System Settings. If this is intended, you can ignore this warning.'); - return; - } - $version = str_replace(' ', '', $babel->config['version']); - $isCSSCompressed = $modx->getOption('compress_css'); - $withVersion = $isCSSCompressed ? '' : '?v='.$version; - $modx->controller->addCss($babel->config['cssUrl'].'babel.css'.$withVersion); - - $modx->controller->addLexiconTopic('babel:default'); - $isJsCompressed = $modx->getOption('compress_js'); - $withVersion = $isJsCompressed ? '' : '?v='.$version; - $modx->controller->addJavascript($babel->config['jsUrl'].'babel.class.js'.$withVersion); - $modx->controller->addHtml(' -'); - break; - - case 'OnDocFormSave': - $resource = & $modx->event->params['resource']; - if (!$resource) { - $modx->log(modX::LOG_LEVEL_ERROR, 'No resource provided for OnDocFormSave event'); - break; - } - if ($modx->event->params['mode'] == modSystemEvent::MODE_NEW) { - /* no TV synchronization for new resources, just init Babel TV */ - $babel->initBabelTv($resource); - break; - } - $babel->synchronizeTvs($resource->get('id')); - break; - - case 'OnEmptyTrash': - /* remove translation links to non-existing resources */ - $deletedResourceIds = & $modx->event->params['ids']; - if (is_array($deletedResourceIds)) { - foreach ($deletedResourceIds as $deletedResourceId) { - $babel->removeLanguageLinksToResource($deletedResourceId); - } - } - break; - - case 'OnContextRemove': - /* remove translation links to non-existing contexts */ - $context = & $modx->event->params['context']; - if ($context) { - $babel->removeLanguageLinksToContext($context->get('key')); - } - break; - case 'OnResourceDuplicate': - /* init Babel TV of duplicated resources */ - $resource = & $modx->event->params['newResource']; - $babel->initBabelTvsRecursive($modx, $babel, $resource->get('id')); - break; - - case 'OnResourceSort': - $nodesAffected = & $modx->event->params['nodesAffected']; - foreach ($nodesAffected as $node) { - $linkedResources = $babel->getLinkedResources($node->get('id')); - foreach ($linkedResources as $key => $id) { - if ($id === $node->get('id')) { - unset($linkedResources[$key]); - } - } - $linkedResources[$node->get('context_key')] = $node->get('id'); - $babel->updateBabelTv($linkedResources, $linkedResources); - } - - break; - - case 'OnSiteRefresh': - $cacheManager = $modx->getCacheManager(); - $cacheManager->refresh([ - 'babel' => [], - ]); - break; - - default: - break; +$className = 'mikrobi\Babel\Plugins\Events\\' . $modx->event->name; + +$corePath = $modx->getOption('babel.core_path', null, $modx->getOption('core_path') . 'components/babel/'); +/** @var Babel $babel */ +$babel = $modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath +]); + +if ($babel) { + if (class_exists($className)) { + $handler = new $className($modx, $scriptProperties); + if (get_class($handler) == $className) { + $handler->run(); + } else { + $modx->log(xPDO::LOG_LEVEL_ERROR, $className . ' could not be initialized!', '', 'Babel Plugin'); + } + } else { + $modx->log(xPDO::LOG_LEVEL_ERROR, $className . ' was not found!', '', 'Babel Plugin'); + } } + return; diff --git a/core/components/babel/elements/snippets/babellinks.snippet.php b/core/components/babel/elements/snippets/babellinks.snippet.php index b90889f..1f15eb5 100644 --- a/core/components/babel/elements/snippets/babellinks.snippet.php +++ b/core/components/babel/elements/snippets/babellinks.snippet.php @@ -1,175 +1,24 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ /** - * BabelLinks snippet to display links to translated resources - * - * Based on ideas of Sylvain Aerni - * - * @author Jakob Class - * goldsky + * BabelLinks * * @package babel + * @subpackage snippet * - * @param resourceId optional: id of resource of which links to translations should be displayed. Default: current resource - * @param tpl optional: Chunk to display a language link. Default: babelLink - * @param activeCls optional: CSS class name for the current active language. Default: active - * @param showUnpublished optional: flag whether to show unpublished translations. Default: 0 - * @param showCurrent optional: flag whether to show a link to a translation of the current language. Default: 1 + * @var modX $modx + * @var array $scriptProperties */ -$babel = $modx->getService('babel', 'Babel', $modx->getOption('babel.core_path', null, $modx->getOption('core_path').'components/babel/').'model/babel/', $scriptProperties); -/* be sure babel and babel TV is loaded */ -if (!($babel instanceof Babel) || !$babel->babelTv) - return; +use mikrobi\Babel\Snippets\BabelLinks; -/* get snippet properties */ -$resourceId = intval($modx->getOption('resourceId', $scriptProperties)); -if (empty($resourceId)) { - if (!empty($modx->resource) && is_object($modx->resource)) { - $resourceId = $modx->resource->get('id'); - } else { - return; - } -} -$tpl = $modx->getOption('tpl', $scriptProperties, 'babelLink'); -$wrapperTpl = $modx->getOption('wrapperTpl', $scriptProperties); -$activeCls = $modx->getOption('activeCls', $scriptProperties, 'active'); -$showUnpublished = $modx->getOption('showUnpublished', $scriptProperties, 0); -$showCurrent = $modx->getOption('showCurrent', $scriptProperties, 0); -$outputSeparator = $modx->getOption('outputSeparator', $scriptProperties, "\n"); -$includeUnlinked = $modx->getOption('includeUnlinked', $scriptProperties, 0); -$ignoreSiteStatus = $modx->getOption('ignoreSiteStatus', $scriptProperties, 0); - -if (!empty($modx->resource) && is_object($modx->resource) && $resourceId === $modx->resource->get('id')) { - $contextKeys = $babel->getGroupContextKeys($modx->resource->get('context_key')); - $resource = $modx->resource; -} else { - $resource = $modx->getObject('modResource', $resourceId); - if (!$resource) { - return; - } - $contextKeys = $babel->getGroupContextKeys($resource->get('context_key')); -} - -$linkedResources = $babel->getLinkedResources($resourceId); -$languages = $babel->getLanguages(); -$outputArray = []; -foreach ($contextKeys as $contextKey) { - if (!$showCurrent && $contextKey === $resource->get('context_key')) { - continue; - } - if (!$includeUnlinked && !isset($linkedResources[$contextKey])) { - continue; - } - $context = $modx->getObject('modContext', ['key' => $contextKey]); - if (!$context) { - $modx->log(modX::LOG_LEVEL_ERROR, 'Could not load context: '.$contextKey); - continue; - } - $context->prepare(); - if (!$context->getOption('site_status', null, true) && !$ignoreSiteStatus) { - continue; - } - $cultureKey = $context->getOption('cultureKey', $modx->getOption('cultureKey')); - $translationAvailable = false; - if (isset($linkedResources[$contextKey])) { - $c = $modx->newQuery('modResource'); - $c->where([ - 'id' => $linkedResources[$contextKey], - 'deleted:!=' => 1, - 'published:=' => 1, - ]); - if ($showUnpublished) { - $c->where([ - 'OR:published:=' => 0, - ]); - } - $count = $modx->getCount('modResource', $c); - if ($count) { - $translationAvailable = true; - } - } - $getRequest = $_GET; - unset($getRequest['id']); - unset($getRequest[$modx->getOption('request_param_alias', null, 'q')]); - unset($getRequest['cultureKey']); - if ($translationAvailable) { - $url = $context->makeUrl($linkedResources[$contextKey], $getRequest, 'full'); - $active = ($resource->get('context_key') == $contextKey) ? $activeCls : ''; - $placeholders = [ - 'cultureKey' => $cultureKey, - 'url' => $url, - 'active' => $active, - 'id' => $linkedResources[$contextKey], - 'language' => $languages[$cultureKey]['Description'], - ]; - - if (!empty($toArray)) { - $outputArray[] = $placeholders; - } else { - $chunk = $babel->getChunk($tpl, $placeholders); - if (!empty($chunk)) { - $outputArray[] = $chunk; - } - } - } elseif ($includeUnlinked) { - $url = $context->makeUrl($context->getOption('site_start'), $getRequest, 'full'); - $active = ($resource->get('context_key') == $contextKey) ? $activeCls : ''; - $placeholders = [ - 'cultureKey' => $cultureKey, - 'url' => $url, - 'active' => $active, - 'id' => $context->getOption('site_start'), - 'language' => $languages[$cultureKey]['Description'], - ]; - - if (!empty($toArray)) { - $outputArray[] = $placeholders; - } else { - $chunk = $babel->getChunk($tpl, $placeholders); - if (!empty($chunk)) { - $outputArray[] = $chunk; - } - } - } -} - -if (!empty($toArray)) { - return '
'.print_r($outputArray, 1).'
'; -} +$corePath = $modx->getOption('babel.core_path', null, $modx->getOption('core_path') . 'components/babel/'); +/** @var Babel $babel */ +$babel = $modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath +]); -$output = implode($outputSeparator, $outputArray); -if (!empty($wrapperTpl)) { - $output = $babel->getChunk($wrapperTpl, [ - 'babelLinks' => $output - ]); +$snippet = new BabelLinks($modx, $scriptProperties); +if ($snippet instanceof mikrobi\Babel\Snippets\BabelLinks) { + return $snippet->execute(); } - -if (!empty($toPlaceholder)) { - $modx->setPlaceholder($toPlaceholder, $output); - return; -} - -return $output; +return 'mikrobi\Babel\Snippets\BabelLinks class not found'; diff --git a/core/components/babel/elements/snippets/babeltranslation.snippet.php b/core/components/babel/elements/snippets/babeltranslation.snippet.php index 91611ce..8376c99 100644 --- a/core/components/babel/elements/snippets/babeltranslation.snippet.php +++ b/core/components/babel/elements/snippets/babeltranslation.snippet.php @@ -1,70 +1,24 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * BabelTranslation snippet to get the id of a translated resource in a given context. - * - * @author Jakob Class + * BabelTranslation * * @package babel + * @subpackage snippet * - * @param resourceId optional: id of resource of which a translated resource should be determined. Default: current resource - * @param contextKey optional: Key of context in which translated resource should be determined. - * @param cultureKey optional: Key of culture in which translated resource should be determined. Used only in case contextKey was not specified. If both omitted: uses currently set cultureKey. - * @param showUnpublished optional: flag whether to show unpublished translations. Default: 0 + * @var modX $modx + * @var array $scriptProperties */ -$babel = $modx->getService('babel', 'Babel', $modx->getOption('babel.core_path', null, $modx->getOption('core_path').'components/babel/').'model/babel/', $scriptProperties); -/* be sure babel and babel TV is loaded */ -if (!($babel instanceof Babel) || !$babel->babelTv) - return; +use mikrobi\Babel\Snippets\BabelTranslation; -/* get snippet properties */ -$resourceIds = $modx->getOption('resourceId', $scriptProperties); -if (empty($resourceIds)) { - if (!empty($modx->resource) && is_object($modx->resource)) { - $resourceIds = $modx->resource->get('id'); - } else { - return; - } -} -$resourceIds = array_map('trim', explode(',', $resourceIds));; -$contextKey = $modx->getOption('contextKey', $scriptProperties, '', true); -if (empty($contextKey)) { - $cultureKey = $modx->getOption('cultureKey', $scriptProperties, '', true); - $contextKey = $babel->getContextKey($cultureKey); -} -$showUnpublished = $modx->getOption('showUnpublished', $scriptProperties, 0, true); +$corePath = $modx->getOption('babel.core_path', null, $modx->getOption('core_path') . 'components/babel/'); +/** @var Babel $babel */ +$babel = $modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath +]); -/* determine ids of translated resource */ -$output = []; -foreach($resourceIds as $resourceId) { - $linkedResource = $babel->getLinkedResources($resourceId); - if (isset($linkedResource[$contextKey])) { - $resource = $modx->getObject('modResource', $linkedResource[$contextKey]); - if ($resource && ($showUnpublished || $resource->get('published') == 1)) { - $output[] = $resource->get('id'); - } - } +$snippet = new BabelTranslation($modx, $scriptProperties); +if ($snippet instanceof mikrobi\Babel\Snippets\BabelTranslation) { + return $snippet->execute(); } -return implode(',', $output); +return 'mikrobi\Babel\Snippets\BabelTranslation class not found'; diff --git a/core/components/babel/lexicon/cs/default.inc.php b/core/components/babel/lexicon/cs/default.inc.php index 86ad2e0..59e9605 100644 --- a/core/components/babel/lexicon/cs/default.inc.php +++ b/core/components/babel/lexicon/cs/default.inc.php @@ -1,89 +1,52 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Czech language file - * - * @author Pavel Železný - * - * @package babel - * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel.tv_caption'] = 'Překladové odkazy Babel Translation'; -$_lang['babel.tv_description'] = 'Spravováno pluginem Babel. Prosím neměnit!'; -$_lang['babel.create_translation'] = 'Vytvořit překlad'; -$_lang['babel.unlink_translation'] = 'Odpojit překlad'; -$_lang['babel.link_translation_manually'] = 'nebo přidělit odkaz ručně:'; -$_lang['babel.id_of_target'] = 'ID cílového dokumentu:'; -$_lang['babel.copy_tv_values'] = 'Zkopírovat synchronizované TV do cílového dokumentu'; -$_lang['babel.save'] = 'Uložit'; -$_lang['babel.translation_pending'] = '[čeká se na překlad]'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabština'; -$_lang['babel.language_bg'] = 'Bulharština'; -$_lang['babel.language_ca'] = 'Catalánština'; -$_lang['babel.language_cs'] = 'Čeština'; -$_lang['babel.language_da'] = 'Dánština'; -$_lang['babel.language_de'] = 'Němčina'; -$_lang['babel.language_en'] = 'Angličtina'; -$_lang['babel.language_es'] = 'Španělština'; -$_lang['babel.language_fa'] = 'Perština'; -$_lang['babel.language_fi'] = 'Finština'; -$_lang['babel.language_fr'] = 'Francouzština'; -$_lang['babel.language_he'] = 'Hebrejština'; -$_lang['babel.language_hu'] = 'Maďarština'; -$_lang['babel.language_id'] = 'Indonezština'; -$_lang['babel.language_it'] = 'Italština'; -$_lang['babel.language_ja'] = 'Japonština'; -$_lang['babel.language_ko'] = 'Korejština'; -$_lang['babel.language_lt'] = 'Litevština'; -$_lang['babel.language_ms'] = 'Malajština'; -$_lang['babel.language_nl'] = 'Holandština'; -$_lang['babel.language_no'] = 'Norština (Bokmål)'; -$_lang['babel.language_pl'] = 'Polština'; -$_lang['babel.language_pt'] = 'Portugalština'; -$_lang['babel.language_ro'] = 'Rumunština'; -$_lang['babel.language_ru'] = 'Ruština'; -$_lang['babel.language_sk'] = 'Slovenština'; -$_lang['babel.language_sl'] = 'Slovinština'; -$_lang['babel.language_sr'] = 'Serbština'; -$_lang['babel.language_sv'] = 'Švédština'; -$_lang['babel.language_tr'] = 'Turuečtina'; -$_lang['babel.language_uk'] = 'Ukrainština'; -$_lang['babel.language_vi'] = 'Vietnamština'; -$_lang['babel.language_zh'] = 'Čínština'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] není platný klíč kontextu'; -$_lang['error.invalid_resource_id'] = '[[+resource]] není platné id dokumentu.'; -$_lang['error.resource_from_other_context'] = 'Dokument [[+resource]] neexistuje v kontextu [[+context]].'; -$_lang['error.resource_already_linked'] = 'Dokument [[+resource]] je již propojen s jiným dokumentem.'; -$_lang['error.no_link_to_context'] = 'Neexistuje odkaz na kontext [[+context]].'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Odkaz na sebe sama nemůže být odebrán.'; -$_lang['error.translation_in_same_context'] = 'Překlad nemůže být vytvořen ve stejném kontextu.'; -$_lang['error.translation_already_exists'] = 'Překlad v kontextu [[+context]] již existuje.'; -$_lang['error.could_not_create_translation'] = 'Nastala chyba při vytváření překladu v kontextu [[+context]].'; \ No newline at end of file + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel'] = 'Babel'; +$_lang['babel.about'] = 'O společnosti Babel'; +$_lang['babel.all'] = 'Vše'; +$_lang['babel.context_err_invalid_key'] = '[[+context]] není platný klíč kontextu.'; +$_lang['babel.context_err_ns'] = 'Kontext nebyl specifikován.'; +$_lang['babel.contexts'] = 'Kontexty'; +$_lang['babel.contexts_desc'] = 'Správa odkazů mezi zdroji v různých kontextech/jazycích na jednom místě. K úpravě odkazů použijte následující tlačítka:'; +$_lang['babel.contexts_desc_create'] = 'Vytvoření nového prostředku, který má být propojen'; +$_lang['babel.contexts_desc_link'] = 'Odkaz na tento zdroj a související zdroje'; +$_lang['babel.contexts_desc_unlink'] = 'Přerušení spojení'; +$_lang['babel.contexts_desc_update'] = 'Aktualizace tohoto propojeného zdroje'; +$_lang['babel.copy_tv_values'] = 'Zkopírovat synchronizované TV do cílového dokumentu'; +$_lang['babel.create_translation'] = 'Vytvořit překlad'; +$_lang['babel.create_translation_confirm'] = 'Jste si jisti, že chcete vytvořit nový překlad tohoto zdroje na "[[+context]]" context?'; +$_lang['babel.debug_mode'] = 'Debug Mode'; +$_lang['babel.desc'] = 'Správa vícejazyčného systému'; +$_lang['babel.target_id'] = 'ID cíle'; +$_lang['babel.link_translation'] = 'Odkaz na existující zdroj'; +$_lang['babel.open'] = 'Otevřeno'; +$_lang['babel.or'] = '… nebo'; +$_lang['babel.target_pagetitle'] = '... nebo vyhledat název stránky cíle'; +$_lang['babel.please_wait'] = 'Počkejte prosím …'; +$_lang['babel.reset'] = 'Obnovení'; +$_lang['babel.resource_err_from_other_context'] = 'Dokument [[+resource]] neexistuje v kontextu "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] není platné id dokumentu.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Odkaz na samotný prostředek nelze propojit.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Odkaz na sebe sama nemůže být odebrán.'; +$_lang['babel.search'] = 'Vyhledávání …'; +$_lang['babel.select_context'] = 'Vyberte kontext'; +$_lang['babel.select_tree_node'] = 'Výběr uzlu ve stromu zdrojů'; +$_lang['babel.settings'] = 'Nastavení'; +$_lang['babel.settings_desc'] = 'Upravte nastavení aplikace Babel. Hodnotu nastavení systému můžete upravit dvojklikem na buňku tabulky "Hodnota" nebo kliknutím pravým tlačítkem myši do buňky tabulky.'; +$_lang['babel.sync_linked_tranlations'] = 'Synchronizovat všechny překlady z cílového'; +$_lang['babel.systemsetting_key_err_nv'] = 'Nastavení lze upravovat pouze s předponou babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Nastavení mohou měnit pouze uživatelé s oprávněním settings nebo settings_babel.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Nastala chyba při vytváření překladu v kontextu [[+context]].'; +$_lang['babel.translation_pending'] = '[čeká se na překlad]'; +$_lang['babel.tv_caption'] = 'Překladové odkazy Babel Translation'; +$_lang['babel.tv_description'] = 'Spravováno pluginem Babel. Prosím neměnit!'; +$_lang['babel.unlink'] = 'Odpojení'; +$_lang['babel.unlink_all_translations'] = 'Zrušení propojení všech překladů'; +$_lang['babel.unlink_all_translations_confirm'] = 'Opravdu chcete zrušit propojení všech překladů z tohoto zdroje?'; +$_lang['babel.unlink_translation_confirm'] = 'Jste si jisti, že chcete zrušit propojení překladu z tohoto zdroje na "[[+context]]" kontext?'; diff --git a/core/components/babel/lexicon/cs/languages.inc.php b/core/components/babel/lexicon/cs/languages.inc.php new file mode 100644 index 0000000..39f3f1d --- /dev/null +++ b/core/components/babel/lexicon/cs/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties Czech language file - * - * @author Pavel Železný - * - * @package babel - * @subpackage lexicon - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk pro vykreslení jazykových odkazů'; -$_lang['babellinks.activeCls'] = 'CSS třída pro aktivní jazykový odkaz'; -$_lang['babellinks.resourceId'] = 'Id dokumentu jehož překladové odkazy mají být zobrazeny'; -$_lang['babellinks.showUnpublished'] = 'Mají se zobrazovat nepřeložené jazykové varianty dokumentu'; -$_lang['babellinks.showCurrent'] = 'Má se zobrazovat odkaz na aktuální jazykovou mutaci'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID dokumentu který stanovuje překlad'; -$_lang['babeltranslation.contextKey'] = 'Jméno kontextu který stanovuje překlad'; -$_lang['babeltranslation.showUnpublished'] = 'Příznak, zda-li se má zobrazovat i nepublikovaný překlad'; \ No newline at end of file + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel.babellinks.activeCls'] = 'CSS třída pro aktivní jazykový odkaz.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Příznak, zda ignorovat site_status (když je web offline)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Příznak, zda se má zobrazit nepropojený kontext.'; +$_lang['babel.babellinks.resourceId'] = 'Id dokumentu jehož překladové odkazy mají být zobrazeny.'; +$_lang['babel.babellinks.restrictToGroup'] = 'Omezit kontexty v tlačítku Babel na skupinu aktuálního kontextu.'; +$_lang['babel.babellinks.showCurrent'] = 'Má se zobrazovat odkaz na aktuální jazykovou mutaci.'; +$_lang['babel.babellinks.showUnpublished'] = 'Příznak, zda-li se má zobrazovat i nepublikovaný překlad.'; +$_lang['babel.babellinks.toArray'] = 'Příznak, zda má být výstup vypsán jako pole.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Příznak, zda se má výstup vypsat do názvu daného zástupného symbolu.'; +$_lang['babel.babellinks.tpl'] = 'Chunk pro vykreslení jazykových odkazů.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Chunk pro zabalení všech jazykových odkazů. Zástupný symbol pro všechny odkazy je [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Jméno kontextu který stanovuje překlad.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Klíč kultury, ve které by měl být překladový zdroj určen. Používá se pouze v případě, že nebyl zadán contextKey. Pokud oba vynechá, použije se aktuálně nastavený cultureKey.'; +$_lang['babel.babeltranslation.resourceId'] = 'ID dokumentu který stanovuje překlad.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Příznak, zda-li se má zobrazovat i nepublikovaný překlad.'; diff --git a/core/components/babel/lexicon/de/cmp.inc.php b/core/components/babel/lexicon/de/cmp.inc.php deleted file mode 100644 index aacef26..0000000 --- a/core/components/babel/lexicon/de/cmp.inc.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel German language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * @language de - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Verwaltungssystem für mehrsprachige Sites'; -$_lang['babel.search...'] = 'Suche...'; -$_lang['babel.filter'] = 'Filtern'; -$_lang['babel.reset'] = 'Zurücksetzen'; -$_lang['babel.icon_descriptions'] = ' Verknüpfung zu dieser Ressource und den mit ihr verknüpften Ressourcen erstellen
' - . ' Alle Verknüpfungen lösen
' - . ' Diese verknüpfte Ressource bearbeiten
' - . ' Eine neue zu verknüpfende Ressource anlegen
'; diff --git a/core/components/babel/lexicon/de/default.inc.php b/core/components/babel/lexicon/de/default.inc.php index 1563e00..13948d0 100644 --- a/core/components/babel/lexicon/de/default.inc.php +++ b/core/components/babel/lexicon/de/default.inc.php @@ -1,118 +1,50 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel German language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * @language de - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Verwaltungssystem für mehrsprachige Sites'; -$_lang['babel.tv_caption'] = 'Babel-Übersetzungslinks'; -$_lang['babel.tv_description'] = 'Wird vom Babel-Plugin verwaltet. Bitte nicht ändern'; -$_lang['babel.create_translation'] = 'Übersetzung anlegen'; -$_lang['babel.create_translation_confirm'] = 'Sind Sie sicher, dass Sie eine neue Übersetzung für diese Ressource im Kontext "[[+context]]" anlegen möchten?'; -$_lang['babel.unlink'] = 'Verknüpfung lösen'; -$_lang['babel.unlink_translation'] = 'Verknüpfung der Übersetzung lösen'; -$_lang['babel.unlink_translation_confirm'] = 'Sind Sie sicher, dass Sie die Verknüpfung der Übersetzung im Kontext "[[+context]]" von dieser Ressource lösen möchten?'; -$_lang['babel.unlink_all_translations'] = 'Verknüpfungen aller Übersetzungen lösen'; -$_lang['babel.unlink_all_translations_confirm'] = 'Sind Sie sicher, dass Sie die Verknüpfungen aller Übersetzungen von dieser Ressource lösen möchten?'; -$_lang['babel.link_translation_manually'] = 'oder Übersetzung manuell verknüpfen:'; -$_lang['babel.link_translation'] = 'Mit einer existierenden Ressource verknüpfen'; -$_lang['babel.id_of_target'] = 'Ziel-ID:'; -$_lang['babel....or'] = '... oder'; -$_lang['babel.pagetitle_of_target'] = 'Seitentitel des Ziels:'; -$_lang['babel.copy_tv_values'] = 'Synchronisierte TVs zum Ziel kopieren'; -$_lang['babel.save'] = 'Speichern'; -$_lang['babel.translation_pending'] = '[Übersetzung ausstehend]'; -$_lang['babel.open'] = 'Öffnen'; -$_lang['babel.please_wait'] = 'Bitte warten...'; -$_lang['babel.sync_linked_tranlations'] = 'Alle Übersetzungen synchronisieren'; // from the target??? -$_lang['babel.select_tree_node'] = 'Wählen Sie einen Knoten des Ressourcen-Baumes'; -$_lang['babel.all'] = 'Alle'; - -/** - * DEPRECATED - */ -/* language names */ -$_lang['babel.language_ar'] = 'Arabisch'; -$_lang['babel.language_bg'] = 'Bulgarisch'; -$_lang['babel.language_ca'] = 'Katalanisch'; -$_lang['babel.language_cs'] = 'Tschechisch'; -$_lang['babel.language_da'] = 'Dänisch'; -$_lang['babel.language_de'] = 'Deutsch'; -$_lang['babel.language_en'] = 'Englisch'; -$_lang['babel.language_es'] = 'Spanisch'; -$_lang['babel.language_fa'] = 'Persisch'; -$_lang['babel.language_fi'] = 'Finnisch'; -$_lang['babel.language_fr'] = 'Französisch'; -$_lang['babel.language_he'] = 'Hebräisch'; -$_lang['babel.language_hu'] = 'Ungarisch'; -$_lang['babel.language_id'] = 'Indonesisch'; -$_lang['babel.language_it'] = 'Italienisch'; -$_lang['babel.language_ja'] = 'Japanisch'; -$_lang['babel.language_ko'] = 'Koreanisch'; -$_lang['babel.language_lt'] = 'Litauisch'; -$_lang['babel.language_ms'] = 'Malaiisch'; -$_lang['babel.language_nl'] = 'Niederländisch'; -$_lang['babel.language_no'] = 'Norwegisch'; -$_lang['babel.language_pl'] = 'Polnisch'; -$_lang['babel.language_pt'] = 'Portugiesisch'; -$_lang['babel.language_ro'] = 'Rumänisch'; -$_lang['babel.language_ru'] = 'Russisch'; -$_lang['babel.language_sk'] = 'Slowakisch'; -$_lang['babel.language_sl'] = 'Slowenisch'; -$_lang['babel.language_sr'] = 'Serbisch'; -$_lang['babel.language_sv'] = 'Schwedisch'; -$_lang['babel.language_tr'] = 'Türkisch'; -$_lang['babel.language_uk'] = 'Ukrainisch'; -$_lang['babel.language_vi'] = 'Vietnamesisch'; -$_lang['babel.language_zh'] = 'Chinesisch'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] ist kein gültiger Kontext-Schlüssel.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] ist keine gültige Ressourcen-ID.'; -$_lang['error.resource_from_other_context'] = 'Die Ressource [[+resource]] befindet sich nicht im Kontext [[+context]].'; -$_lang['error.resource_already_linked'] = 'Die Ressource [[+resource]] ist bereits mit anderen Ressourcen verknüpft.'; -$_lang['error.no_link_to_context'] = 'Für den Kontext [[+context]] existiert noch keine Verknüpfung.'; -$_lang['error.link_of_selflink_not_possible'] = 'Eine Verknüpfung mit einer Ressource kann selbst nicht verknüpft werden.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Die Verknüpfung einer Ressource auf sich selbst kann nicht entfernt werden.'; -$_lang['error.translation_in_same_context'] = 'Eine Übersetzung kann nicht im gleichen Kontext angelegt werden.'; -$_lang['error.translation_already_exists'] = 'Es existiert bereits eine Übersetzung im Kontext [[+context]].'; -$_lang['error.could_not_create_translation'] = 'Beim Erstellen der Übersetzung im Kontext [[+context]] ist ein Fehler aufgetreten.'; - -$_lang['babel.context_err_ns'] = 'Der Kontext wurde nicht angegeben.'; - -$_lang['setting_babel.contextKeys'] = 'Kontext-Schlüssel'; -$_lang['setting_babel.contextKeys_desc'] = 'Kommaseparierte Liste von Kontext-Schlüsseln, die verwendet werden sollen, um die Ressourcen der verschiedenen Sprachen zu verbinden.'; -$_lang['setting_babel.babelTvName'] = 'Babel-TV-Name'; -$_lang['setting_babel.babelTvName_desc'] = 'Name der Template-Variablen (TV), in der Babel die Links zwischen den Ressourcen der verschiedenen Sprachen speichern wird. Diese TV wird von Babel verwaltet.'; -$_lang['setting_babel.syncTvs'] = 'Zu synchronisierende TVs'; -$_lang['setting_babel.syncTvs_desc'] = 'Kommaseparierte Liste von IDs von Template-Variablen (TVs), die von Babel synchronisiert werden sollen.'; +"[[+context]]" anlegen möchten?'; +$_lang['babel.debug_mode'] = 'Debug Modus'; +$_lang['babel.desc'] = 'Verwaltungssystem für mehrsprachige Sites'; +$_lang['babel.target_id'] = 'Ziel-ID'; +$_lang['babel.link_translation'] = 'Mit einer existierenden Ressource verknüpfen'; +$_lang['babel.open'] = 'Öffnen'; +$_lang['babel.or'] = '… oder'; +$_lang['babel.target_pagetitle'] = 'Seitentitel des Ziels'; +$_lang['babel.please_wait'] = 'Bitte warten …'; +$_lang['babel.reset'] = 'Zurücksetzen'; +$_lang['babel.resource_err_from_other_context'] = 'Die Ressource [[+resource]] befindet sich nicht im Kontext "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] ist keine gültige Ressourcen-ID.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Eine Verknüpfung mit einer Ressource kann selbst nicht verknüpft werden.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Die Verknüpfung einer Ressource auf sich selbst kann nicht entfernt werden.'; +$_lang['babel.search'] = 'Suche …'; +$_lang['babel.select_context'] = 'Kontext auswählen'; +$_lang['babel.select_tree_node'] = 'Wählen Sie einen Knoten im Ressourcenbaum'; +$_lang['babel.settings'] = 'Einstellungen'; +$_lang['babel.settings_desc'] = 'Bearbeiten Sie die Einstellungen von Babel. Sie können den Wert einer Systemeinstellung mit einem Doppelklick auf die ‚Wert‘-Tabellenzelle oder die Systemeinstellung mit einem Rechtsklick in der Tabellenzelle bearbeiten.'; +$_lang['babel.sync_linked_tranlations'] = 'Alle Übersetzungen synchronisieren'; +$_lang['babel.systemsetting_key_err_nv'] = 'Sie können nur Einstellungen mit dem Präfix babel bearbeiten.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Nur Benutzer mit einer settings Berechtigung oder einer settings_babel Berechtigung können die Einstellungen ändern.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Beim Erstellen der Übersetzung im Kontext [[+context]] ist ein Fehler aufgetreten.'; +$_lang['babel.translation_pending'] = '[Übersetzung ausstehend]'; +$_lang['babel.tv_caption'] = 'Babel-Übersetzungslinks'; +$_lang['babel.tv_description'] = 'Wird vom Babel-Plugin verwaltet. Bitte nicht ändern!'; +$_lang['babel.unlink'] = 'Verknüpfung lösen'; +$_lang['babel.unlink_all_translations'] = 'Verknüpfungen aller Übersetzungen lösen'; +$_lang['babel.unlink_all_translations_confirm'] = 'Sind Sie sicher, dass Sie die Verknüpfungen aller Übersetzungen von dieser Ressource lösen möchten?'; +$_lang['babel.unlink_translation_confirm'] = 'Sind Sie sicher, dass Sie die Verknüpfung der Übersetzung im Kontext "[[+context]]" von dieser Ressource lösen möchten?'; diff --git a/core/components/babel/lexicon/de/languages.inc.php b/core/components/babel/lexicon/de/languages.inc.php new file mode 100644 index 0000000..c618e80 --- /dev/null +++ b/core/components/babel/lexicon/de/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties German language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * @language de - */ - -/* BabelLinks snippet */ -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk zur Darstellung eines Sprachen-Links'; -$_lang['babellinks.activeCls'] = 'CSS-Klasse für den Sprachen-Link der aktiven Sprache'; -$_lang['babellinks.resourceId'] = 'ID der Ressource, von der die Links zu Übersetzungen dargestellt werden sollen'; -$_lang['babellinks.showUnpublished'] = 'Gibt an, ob unveröffentlichte Übersetzungen angezeigt werden sollen'; -$_lang['babellinks.showCurrent'] = 'Gibt an, ob ein Link zu einer Übersetzung der aktuellen Sprache angezeigt werden soll'; -$_lang['babellinks.includeUnlinked'] = 'Gibt an, ob ein Kontext, dessen Verknüpfung gelöst wurde, angezeigt werden soll'; // ??? - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID der Ressource, von der eine Übersetzung erstellt werden soll'; -$_lang['babeltranslation.contextKey'] = 'Schlüssel des Kontexts, in dem eine Übersetzung erstellt werden soll'; -$_lang['babeltranslation.cultureKey'] = 'Kürzel der Sprache, in der eine Übersetzung der Ressource angelegt werden soll. Wird nur verwendet, wenn der contextKey nicht angegeben wird. Werden beide Werte nicht angegeben, wird der aktuelle cultureKey verwendet.'; -$_lang['babeltranslation.showUnpublished'] = 'Gibt an, ob unveröffentlichte Übersetzungen angezeigt werden sollen'; + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Managing multilingual system'; -$_lang['babel.search...'] = 'Search...'; -$_lang['babel.filter'] = 'Filter'; -$_lang['babel.reset'] = 'Reset'; -$_lang['babel.icon_descriptions'] = ' Link to this resource and its linked resources
' - . ' Break all links
' - . ' Edit this linked resource
' - . ' Create a new resource to be linked
'; diff --git a/core/components/babel/lexicon/en/default.inc.php b/core/components/babel/lexicon/en/default.inc.php index 10f0fcf..0af8470 100644 --- a/core/components/babel/lexicon/en/default.inc.php +++ b/core/components/babel/lexicon/en/default.inc.php @@ -1,118 +1,49 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Managing multilingual system'; -$_lang['babel.tv_caption'] = 'Babel Translation Links'; -$_lang['babel.tv_description'] = 'Maintained by Babel plugin. Please do not change!'; -$_lang['babel.create_translation'] = 'Create translation'; -$_lang['babel.create_translation_confirm'] = 'Are you sure you want to create new translation for this resource to "[[+context]]" context?'; -$_lang['babel.unlink'] = 'Unlink'; -$_lang['babel.unlink_translation'] = 'Unlink translation'; -$_lang['babel.unlink_translation_confirm'] = 'Are you sure you want to unlink translation from this resource to "[[+context]]" context?'; -$_lang['babel.unlink_all_translations'] = 'Unlink all translations'; -$_lang['babel.unlink_all_translations_confirm'] = 'Are you sure you want to unlink all translations from this resource?'; -$_lang['babel.link_translation_manually'] = 'or link translation manually:'; -$_lang['babel.link_translation'] = 'Link to existing resource'; -$_lang['babel.id_of_target'] = 'ID of target:'; -$_lang['babel....or'] = '... or'; -$_lang['babel.pagetitle_of_target'] = 'Pagetitle of target:'; -$_lang['babel.copy_tv_values'] = 'Copy synchronized TVs to target'; -$_lang['babel.save'] = 'Save'; -$_lang['babel.translation_pending'] = '[translations pending]'; -$_lang['babel.open'] = 'Open'; -$_lang['babel.please_wait'] = 'Please wait...'; -$_lang['babel.sync_linked_tranlations'] = 'Synchronize all translations from the target'; -$_lang['babel.select_tree_node'] = 'Select a node of the resource tree'; -$_lang['babel.all'] = 'All'; - -/** - * DEPRECATED - */ -/* language names */ -$_lang['babel.language_ar'] = 'Arabic'; -$_lang['babel.language_bg'] = 'Bulgarian'; -$_lang['babel.language_ca'] = 'Catalan'; -$_lang['babel.language_cs'] = 'Czech'; -$_lang['babel.language_da'] = 'Danish'; -$_lang['babel.language_de'] = 'German'; -$_lang['babel.language_en'] = 'English'; -$_lang['babel.language_es'] = 'Spanish'; -$_lang['babel.language_fa'] = 'Persian'; -$_lang['babel.language_fi'] = 'Finnish'; -$_lang['babel.language_fr'] = 'French'; -$_lang['babel.language_he'] = 'Hebrew'; -$_lang['babel.language_hu'] = 'Hungarian'; -$_lang['babel.language_id'] = 'Indonesian'; -$_lang['babel.language_it'] = 'Italian'; -$_lang['babel.language_ja'] = 'Japanese'; -$_lang['babel.language_ko'] = 'Korean'; -$_lang['babel.language_lt'] = 'Lithuanian'; -$_lang['babel.language_ms'] = 'Malay'; -$_lang['babel.language_nl'] = 'Dutch'; -$_lang['babel.language_no'] = 'Norwegian (Bokmål)'; -$_lang['babel.language_pl'] = 'Polish'; -$_lang['babel.language_pt'] = 'Portuguese'; -$_lang['babel.language_ro'] = 'Romanian'; -$_lang['babel.language_ru'] = 'Russian'; -$_lang['babel.language_sk'] = 'Slovak'; -$_lang['babel.language_sl'] = 'Slovenian'; -$_lang['babel.language_sr'] = 'Serbian'; -$_lang['babel.language_sv'] = 'Swedish'; -$_lang['babel.language_tr'] = 'Turkish'; -$_lang['babel.language_uk'] = 'Ukrainian'; -$_lang['babel.language_vi'] = 'Vietnamese'; -$_lang['babel.language_zh'] = 'Chinese'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] is no valid context key.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] is no valid resource id.'; -$_lang['error.resource_from_other_context'] = 'Resource [[+resource]] does not exist in context "[[+context]]".'; -$_lang['error.resource_already_linked'] = 'Resource [[+resource]] is already linked with other resources.'; -$_lang['error.no_link_to_context'] = 'There does not exist any link to context [[+context]].'; -$_lang['error.link_of_selflink_not_possible'] = 'A link to a resource itself can not be linked.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'A link to a resource itself can not be unlinked.'; -$_lang['error.translation_in_same_context'] = 'A translation can not be created within the same context.'; -$_lang['error.translation_already_exists'] = 'There is already a translation in context "[[+context]]": "[[+pagetitle]] ([[+resource]])"'; -$_lang['error.could_not_create_translation'] = 'An error occured while trying to create a translation in context [[+context]].'; - -$_lang['babel.context_err_ns'] = 'Context was not specified.'; - -$_lang['setting_babel.contextKeys'] = 'Context Keys'; -$_lang['setting_babel.contextKeys_desc'] = 'Comma separated list of context keys which should be used to link multilingual resources.'; -$_lang['setting_babel.babelTvName'] = 'Babel TV Name'; -$_lang['setting_babel.babelTvName_desc'] = 'Name of template variable (TV) in which Babel will store the links between multilingual resources. This TV will be maintained by Babel.'; -$_lang['setting_babel.syncTvs'] = 'TVs to be synchronized'; -$_lang['setting_babel.syncTvs_desc'] = 'Comma separated list of ids of template variables (TVs) which should be synchronized by Babel.'; +"[[+context]]" context?'; +$_lang['babel.debug_mode'] = 'Debug Mode'; +$_lang['babel.desc'] = 'Managing multilingual system'; +$_lang['babel.target_id'] = 'Target ID'; +$_lang['babel.link_translation'] = 'Link to existing resource'; +$_lang['babel.open'] = 'Open'; +$_lang['babel.target_pagetitle'] = '… or search for the pagetitle of the target'; +$_lang['babel.please_wait'] = 'Please wait …'; +$_lang['babel.reset'] = 'Reset'; +$_lang['babel.resource_err_from_other_context'] = 'Resource [[+resource]] does not exist in context "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] is no valid resource id.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'A link to a resource itself can not be linked.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'A link to a resource itself can not be unlinked.'; +$_lang['babel.search'] = 'Search …'; +$_lang['babel.select_context'] = 'Select Context'; +$_lang['babel.select_tree_node'] = 'Select a node in the resource tree'; +$_lang['babel.settings'] = 'Settings'; +$_lang['babel.settings_desc'] = 'Edit the settings of Babel. You can edit the value of a system setting by double-clicking the ‘Value’ table cell or by right-clicking in the table cell.'; +$_lang['babel.sync_linked_tranlations'] = 'Synchronize all translations from the target'; +$_lang['babel.systemsetting_key_err_nv'] = 'You can only edit settings with the prefix babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Only users with a settings permission or settings_babel permission can change the settings.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'An error occured while trying to create a translation in context [[+context]].'; +$_lang['babel.translation_pending'] = '[translations pending]'; +$_lang['babel.tv_caption'] = 'Babel Translation Links'; +$_lang['babel.tv_description'] = 'Maintained by Babel plugin. Please do not change!'; +$_lang['babel.unlink'] = 'Unlink'; +$_lang['babel.unlink_all_translations'] = 'Unlink all translations'; +$_lang['babel.unlink_all_translations_confirm'] = 'Are you sure you want to unlink all translations from this resource?'; +$_lang['babel.unlink_translation_confirm'] = 'Are you sure you want to unlink translation from this resource to "[[+context]]" context?'; diff --git a/core/components/babel/lexicon/en/languages.inc.php b/core/components/babel/lexicon/en/languages.inc.php new file mode 100644 index 0000000..a1fe323 --- /dev/null +++ b/core/components/babel/lexicon/en/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties English language file - * - * @author Jakob Class + * Properties Lexicon Entries for Babel * * @package babel * @subpackage lexicon */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk to display a language link'; -$_lang['babellinks.activeCls'] = 'CSS class for the active language link'; -$_lang['babellinks.resourceId'] = 'Id of resource of which links to translations should be displayed'; -$_lang['babellinks.showUnpublished'] = 'Flag whether to show unpublished translations'; -$_lang['babellinks.showCurrent'] = 'Flag whether to show a link to a translation of the current language'; -$_lang['babellinks.includeUnlinked'] = 'Flag whether to show unlinked context'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID of resource of which a translated resource should be determined'; -$_lang['babeltranslation.contextKey'] = 'Key of context in which translated resource should be determined'; -$_lang['babeltranslation.showUnpublished'] = 'Flag whether to show unpublished translations'; \ No newline at end of file +$_lang['babel.babellinks.activeCls'] = 'CSS class for the active language link.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Flag whether to ignore the site_status (when the site is offline)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Flag whether to show unlinked context.'; +$_lang['babel.babellinks.resourceId'] = 'Id of resource of which links to translations should be displayed.'; +$_lang['babel.babellinks.restrictToGroup'] = 'Restrict the contexts in the snippet output to the group of the current context.'; +$_lang['babel.babellinks.showCurrent'] = 'Flag whether to show a link to a translation of the current language.'; +$_lang['babel.babellinks.showUnpublished'] = 'Flag whether to show unpublished translations.'; +$_lang['babel.babellinks.toArray'] = 'Flag whether to dump the output as an array instead.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Flag whether to dump the output into the given placeholder\'s name.'; +$_lang['babel.babellinks.tpl'] = 'Chunk to display a language link.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Chunk to wrap all language links. The placeholder for all links is [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Key of context in which translated resource should be determined.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Key of culture in which translated resource should be determined. Used only in case contextKey was not specified. If both omitted the snippet the currently set cultureKey.'; +$_lang['babel.babeltranslation.resourceId'] = 'ID of resource of which a translated resource should be determined.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Flag whether to show unpublished translations.'; diff --git a/core/components/babel/lexicon/en/setting.inc.php b/core/components/babel/lexicon/en/setting.inc.php new file mode 100644 index 0000000..402a219 --- /dev/null +++ b/core/components/babel/lexicon/en/setting.inc.php @@ -0,0 +1,19 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel French language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel.tv_caption'] = 'Liens de traduction de Babel'; -$_lang['babel.tv_description'] = 'Mis à jour par le plugin Babel. Veuillez ne pas modifier!'; -$_lang['babel.create_translation'] = 'Créer une traduction'; -$_lang['babel.unlink_translation'] = 'Délier la traduction'; -$_lang['babel.link_translation_manually'] = 'ou lier manuellement une traduction:'; -$_lang['babel.id_of_target'] = 'ID of target:'; -$_lang['babel.copy_tv_values'] = 'Copy synchronized TVs to target'; -$_lang['babel.save'] = 'Sauvegarder'; -$_lang['babel.translation_pending'] = '[traduction en attente]'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabe'; -$_lang['babel.language_bg'] = 'Bulgare'; -$_lang['babel.language_ca'] = 'Catalan'; -$_lang['babel.language_cs'] = 'Tchèque'; -$_lang['babel.language_da'] = 'Danois'; -$_lang['babel.language_de'] = 'Allemand'; -$_lang['babel.language_en'] = 'Anglais'; -$_lang['babel.language_es'] = 'Espagnol'; -$_lang['babel.language_fa'] = 'Perse'; -$_lang['babel.language_fi'] = 'Finnois'; -$_lang['babel.language_fr'] = 'Français'; -$_lang['babel.language_he'] = 'Hébreu'; -$_lang['babel.language_hu'] = 'Hongrois'; -$_lang['babel.language_id'] = 'Indonésien'; -$_lang['babel.language_it'] = 'Italien'; -$_lang['babel.language_ja'] = 'Japonais'; -$_lang['babel.language_ko'] = 'Coréen'; -$_lang['babel.language_lt'] = 'Lituanien'; -$_lang['babel.language_ms'] = 'Malais'; -$_lang['babel.language_nl'] = 'Néerlandais'; -$_lang['babel.language_no'] = 'Norvégien'; -$_lang['babel.language_pl'] = 'Polonais'; -$_lang['babel.language_pt'] = 'Portugais'; -$_lang['babel.language_ro'] = 'Roumain'; -$_lang['babel.language_ru'] = 'Russe'; -$_lang['babel.language_sk'] = 'Slovaque'; -$_lang['babel.language_sl'] = 'Slovène'; -$_lang['babel.language_sr'] = 'Serbe'; -$_lang['babel.language_sv'] = 'Suédois'; -$_lang['babel.language_tr'] = 'Turc'; -$_lang['babel.language_uk'] = 'Ukrainien'; -$_lang['babel.language_vi'] = 'Vietnamien'; -$_lang['babel.language_zh'] = 'Chinois'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] n\'est pas une clé de context valide.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] n\'est pas un id valide de ressource.'; -$_lang['error.resource_from_other_context'] = 'La ressource [[+resource]] n\'existe pas dans le context [[+context]].'; -$_lang['error.resource_already_linked'] = 'La ressource [[+resource]] est déjà liée à d\'autres ressources.'; -$_lang['error.no_link_to_context'] = 'Il n\'existe aucun lien vers le contexte [[+context]].'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Un lien vers une « même ressource » ne être défait.'; -$_lang['error.translation_in_same_context'] = 'Une traduction ne peut être créée au sein d\'un même contexte.'; -$_lang['error.translation_already_exists'] = 'Il y a déjà une traduction dans le contexte [[+context]].'; -$_lang['error.could_not_create_translation'] = 'Une erreur est survenue lors de la création de traduction dans le contexte [[+context]].'; \ No newline at end of file +"[[+contexte]]" context ?'; +$_lang['babel.debug_mode'] = 'Mode débogage'; +$_lang['babel.desc'] = 'Gestion d\'un système multilingue'; +$_lang['babel.target_id'] = 'ID de la cible'; +$_lang['babel.link_translation'] = 'Lien vers une ressource existante'; +$_lang['babel.open'] = 'Ouvrir'; +$_lang['babel.or'] = '… ou'; +$_lang['babel.target_pagetitle'] = '... ou rechercher le titre de la page de la cible'; +$_lang['babel.please_wait'] = 'Veuillez patienter …'; +$_lang['babel.reset'] = 'Réinitialiser'; +$_lang['babel.resource_err_from_other_context'] = 'La ressource [[+resource]] n\'existe pas dans le context "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] n\'est pas un id valide de ressource.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Un lien vers une ressource elle-même ne peut pas être lié.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Un lien vers une « même ressource » ne être défait.'; +$_lang['babel.search'] = 'Recherche …'; +$_lang['babel.select_context'] = 'Sélectionner le contexte'; +$_lang['babel.select_tree_node'] = 'Sélectionner un nœud dans l\'arborescence des ressources'; +$_lang['babel.settings'] = 'Paramètres'; +$_lang['babel.settings_desc'] = 'Modifier les paramètres de Babel. Vous pouvez modifier la valeur d’un paramètre du système en double-cliquant sur la cellule du tableau ou en cliquant avec le bouton droit de la souris sur la cellule.'; +$_lang['babel.sync_linked_tranlations'] = 'Synchroniser toutes les traductions de la cible'; +$_lang['babel.systemsetting_key_err_nv'] = 'Vous ne pouvez modifier les paramètres qu’avec le préfixe babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Seuls les utilisateurs disposant d\'une autorisation settings ou settings_babel peuvent modifier les paramètres.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Une erreur est survenue lors de la création de traduction dans le contexte [[+context]].'; +$_lang['babel.translation_pending'] = '[traduction en attente]'; +$_lang['babel.tv_caption'] = 'Liens de traduction de Babel'; +$_lang['babel.tv_description'] = 'Mis à jour par le plugin Babel. Veuillez ne pas modifier !'; +$_lang['babel.unlink'] = 'Détacher'; +$_lang['babel.unlink_all_translations'] = 'Détacher toutes les traductions'; +$_lang['babel.unlink_all_translations_confirm'] = 'Êtes-vous sûr de vouloir dissocier toutes les traductions de cette ressource ?'; +$_lang['babel.unlink_translation_confirm'] = 'Êtes-vous sûr de vouloir dissocier la traduction de cette ressource du contexte "[[+contexte]]" ?'; diff --git a/core/components/babel/lexicon/fr/languages.inc.php b/core/components/babel/lexicon/fr/languages.inc.php new file mode 100644 index 0000000..4665231 --- /dev/null +++ b/core/components/babel/lexicon/fr/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties French language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk pour afficher un lien de langue'; -$_lang['babellinks.activeCls'] = 'Classe CSS pour les liens de la langue active'; -$_lang['babellinks.resourceId'] = 'Id of resource of which links to translations should be displayed'; -$_lang['babellinks.showUnpublished'] = 'Flag whether to show unpublished translations'; -$_lang['babellinks.showCurrent'] = 'Flag whether to show a link to a translation of the current language'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID of resource of which a translated resource should be determined'; -$_lang['babeltranslation.contextKey'] = 'Key of context in which translated resource should be determined'; -$_lang['babeltranslation.cultureKey'] = 'Key of culture in which translated resource should be determined. Used only in case contextKey was not specified. If both omitted: uses currently set cultureKey.'; -$_lang['babeltranslation.showUnpublished'] = 'Flag whether to show unpublished translations'; \ No newline at end of file + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Italian language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel.tv_caption'] = 'Links Traduzioni Babel'; -$_lang['babel.tv_description'] = 'Gestito dal plugin di Babel. Si prega di non cambiarlo!'; -$_lang['babel.create_translation'] = 'Crea traduzione'; -$_lang['babel.unlink_translation'] = 'Scollega traduzione'; -$_lang['babel.link_translation_manually'] = 'o collega la traduzione manualmente:'; -$_lang['babel.id_of_target'] = 'ID di destinazione:'; -$_lang['babel.copy_tv_values'] = 'Copia le TVs sincronizzate alla destinazione'; -$_lang['babel.save'] = 'Salva'; -$_lang['babel.translation_pending'] = '[traduzione in sospeso]'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabic'; -$_lang['babel.language_bg'] = 'Bulgarian'; -$_lang['babel.language_ca'] = 'Catalan'; -$_lang['babel.language_cs'] = 'Czech'; -$_lang['babel.language_da'] = 'Danish'; -$_lang['babel.language_de'] = 'German'; -$_lang['babel.language_en'] = 'English'; -$_lang['babel.language_es'] = 'Spanish'; -$_lang['babel.language_fa'] = 'Persian'; -$_lang['babel.language_fi'] = 'Finnish'; -$_lang['babel.language_fr'] = 'French'; -$_lang['babel.language_he'] = 'Hebrew'; -$_lang['babel.language_hu'] = 'Hungarian'; -$_lang['babel.language_id'] = 'Indonesian'; -$_lang['babel.language_it'] = 'Italiano'; -$_lang['babel.language_ja'] = 'Japanese'; -$_lang['babel.language_ko'] = 'Korean'; -$_lang['babel.language_lt'] = 'Lithuanian'; -$_lang['babel.language_ms'] = 'Malay'; -$_lang['babel.language_nl'] = 'Dutch'; -$_lang['babel.language_no'] = 'Norwegian (Bokmål)'; -$_lang['babel.language_pl'] = 'Polish'; -$_lang['babel.language_pt'] = 'Portuguese'; -$_lang['babel.language_ro'] = 'Romanian'; -$_lang['babel.language_ru'] = 'Russian'; -$_lang['babel.language_sk'] = 'Slovak'; -$_lang['babel.language_sl'] = 'Slovenian'; -$_lang['babel.language_sr'] = 'Serbian'; -$_lang['babel.language_sv'] = 'Swedish'; -$_lang['babel.language_tr'] = 'Turkish'; -$_lang['babel.language_uk'] = 'Ukrainian'; -$_lang['babel.language_vi'] = 'Vietnamese'; -$_lang['babel.language_zh'] = 'Chinese'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] non è una chiave di contesto valido.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] non è un id di risorsa valido.'; -$_lang['error.resource_from_other_context'] = 'La risorsa [[+resource]] non esiste nel contesto [[+context]].'; -$_lang['error.resource_already_linked'] = 'La risorsa [[+resource]] è già collegata con altre risorse.'; -$_lang['error.no_link_to_context'] = 'Non esisten alcun collegamento con il contesto [[+context]].'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Un link alla risorsa stessa non può essere scollegato.'; -$_lang['error.translation_in_same_context'] = 'Una traduzione non può essere creata dentro allo stesso contesto.'; -$_lang['error.translation_already_exists'] = 'Esiste già una traduzione nel contesto [[+context]].'; -$_lang['error.could_not_create_translation'] = 'Si è verificato un errore durante la creazione della traduzione nel contesto [[+context]].'; +"[[+context]]" contesto?'; +$_lang['babel.debug_mode'] = 'Debug Mode'; +$_lang['babel.desc'] = 'Gestione di un sistema multilingue'; +$_lang['babel.target_id'] = 'ID di destinazione'; +$_lang['babel.link_translation'] = 'Collegamento alla risorsa esistente'; +$_lang['babel.open'] = 'Aperto'; +$_lang['babel.or'] = '… o'; +$_lang['babel.target_pagetitle'] = 'Titolo della pagina di destinazione'; +$_lang['babel.please_wait'] = 'Attendere …'; +$_lang['babel.reset'] = 'Reset'; +$_lang['babel.resource_err_from_other_context'] = 'La risorsa [[+resource]] non esiste nel contesto "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] non è un id di risorsa valido.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Un collegamento a una risorsa non può essere collegato.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Un link alla risorsa stessa non può essere scollegato.'; +$_lang['babel.search'] = 'Ricerca …'; +$_lang['babel.select_context'] = 'Selezionare il contesto'; +$_lang['babel.select_tree_node'] = 'Selezionare un nodo nell\'albero delle risorse'; +$_lang['babel.settings'] = 'Impostazioni'; +$_lang['babel.settings_desc'] = 'Modifica delle impostazioni di Babel. È possibile modificare il valore di un\'impostazione di sistema facendo doppio clic sulla cella della tabella \'Valore\' o facendo clic con il pulsante destro del mouse sulla cella della tabella.'; +$_lang['babel.sync_linked_tranlations'] = 'Sincronizzare tutte le traduzioni dalla destinazione'; +$_lang['babel.systemsetting_key_err_nv'] = 'È possibile modificare solo le impostazioni con il prefisso babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Solo gli utenti con l\'autorizzazione settings o settings_babel possono modificare le impostazioni.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Si è verificato un errore durante la creazione della traduzione nel contesto [[+context]].'; +$_lang['babel.translation_pending'] = '[traduzione in sospeso]'; +$_lang['babel.tv_caption'] = 'Links Traduzioni Babel'; +$_lang['babel.tv_description'] = 'Gestito dal plugin di Babel. Si prega di non cambiarlo!'; +$_lang['babel.unlink'] = 'Unlink'; +$_lang['babel.unlink_all_translations'] = 'Scollegamento di tutte le traduzioni'; +$_lang['babel.unlink_all_translations_confirm'] = 'Siete sicuri di voler scollegare tutte le traduzioni da questa risorsa?'; +$_lang['babel.unlink_translation_confirm'] = 'Si è sicuri di voler scollegare la traduzione da questa risorsa a "[[+contesto]]" contesto?'; diff --git a/core/components/babel/lexicon/it/languages.inc.php b/core/components/babel/lexicon/it/languages.inc.php new file mode 100644 index 0000000..d2b54c3 --- /dev/null +++ b/core/components/babel/lexicon/it/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties Italian language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk per visualizzare il link della lingua'; -$_lang['babellinks.activeCls'] = 'Classe CSS per il link della lingua attiva'; -$_lang['babellinks.resourceId'] = 'Id della risorsa i cui links alla traduzione dovrebbero essere mostrati'; -$_lang['babellinks.showUnpublished'] = 'Flag se mostrare le traduzioni non pubblicate'; -$_lang['babellinks.showCurrent'] = 'Flag se mostrare un link alla traduzione per la lingua corrente'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID di una risorsa di cui una risorsa tradotta dovrebbe essere determinata'; -$_lang['babeltranslation.contextKey'] = 'Chiave del contesto in cui la risorsa tradotta dovrebbe essere determinata'; -$_lang['babeltranslation.showUnpublished'] = 'Flag se mostrare le traduzioni non pubblicate'; \ No newline at end of file + - * @author Wieger Sloot - * - * @package babel - * @subpackage lexicon - */ - -$_lang['babel.tv_caption'] = 'Babel Vertaal Links'; -$_lang['babel.tv_description'] = 'Onderhouden door Babel plugin. Gelieve niet te veranderen!'; -$_lang['babel.create_translation'] = 'Maak vertaling'; -$_lang['babel.create_translation_confirm'] = 'Weet je zeker dat je een nieuwe vertaling van deze pagina wil toevoegen in de "[[+context]]" channel?'; -$_lang['babel.unlink'] = 'Verwijder'; -$_lang['babel.unlink_translation'] = 'Verwijder vertaling'; -$_lang['babel.unlink_translation_confirm'] = 'Weet je zeker dat je deze vertaling wil verwijderen van deze pagina in de "[[+context]]" channel?'; -$_lang['babel.link_translation_manually'] = 'of vertaling handmatig koppelen:'; -$_lang['babel.link_translation'] = 'Koppelen aan bestaande pagina'; -$_lang['babel.id_of_target'] = 'Selecteer een pagina:'; -$_lang['babel.copy_tv_values'] = 'Kopieer template variabelen naar geselecteerde pagina'; -$_lang['babel.save'] = 'Opslaan'; -$_lang['babel.translation_pending'] = '[in afwachting van vertaling]'; -$_lang['babel.open'] = 'Openen'; -$_lang['babel.please_wait'] = 'Even wachten...'; - -$_lang['babel....or'] = 'Of'; -$_lang['babel.pagetitle_of_target'] = 'voer een pagina titel in:'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabisch'; -$_lang['babel.language_bg'] = 'Bulgaars'; -$_lang['babel.language_be'] = 'Vlaams'; -$_lang['babel.language_ca'] = 'Catalaans'; -$_lang['babel.language_cs'] = 'Tsjechisch'; -$_lang['babel.language_da'] = 'Deens'; -$_lang['babel.language_de'] = 'Duits'; -$_lang['babel.language_en'] = 'Engels'; -$_lang['babel.language_es'] = 'Spaans'; -$_lang['babel.language_fa'] = 'Perzisch'; -$_lang['babel.language_fi'] = 'Fins'; -$_lang['babel.language_fr'] = 'Frans'; -$_lang['babel.language_he'] = 'Hebreeuws'; -$_lang['babel.language_hu'] = 'Hongaars'; -$_lang['babel.language_id'] = 'Indonesisch'; -$_lang['babel.language_it'] = 'Italiaans'; -$_lang['babel.language_ja'] = 'Japanees'; -$_lang['babel.language_ko'] = 'Koreaans'; -$_lang['babel.language_lt'] = 'Litouws'; -$_lang['babel.language_ms'] = 'Maleis'; -$_lang['babel.language_nl'] = 'Nederlands'; -$_lang['babel.language_no'] = 'Noors (Bokmål)'; -$_lang['babel.language_pl'] = 'Pools'; -$_lang['babel.language_pt'] = 'Portugees'; -$_lang['babel.language_ro'] = 'Roemeens'; -$_lang['babel.language_ru'] = 'Russisch'; -$_lang['babel.language_sk'] = 'Slowaaks'; -$_lang['babel.language_sl'] = 'Sloveens'; -$_lang['babel.language_sr'] = 'Servisch'; -$_lang['babel.language_sv'] = 'Zweeds'; -$_lang['babel.language_tr'] = 'Turks'; -$_lang['babel.language_uk'] = 'Oekraïens'; -$_lang['babel.language_vi'] = 'Vietnamees'; -$_lang['babel.language_zh'] = 'Chinees'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] is geen geldige channel key.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] is geen geldige pagina id.'; -$_lang['error.resource_from_other_context'] = 'Resource [[+resource]] bestaat niet in channel [[+context]].'; -$_lang['error.resource_already_linked'] = 'Resource [[+resource]] is reeds gelinkt aan andere resources.'; -$_lang['error.no_link_to_context'] = 'Er bestaat geen enkele link naar channel [[+context]].'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Een link naar dezelfde pagina kan niet verwijderd worden.'; -$_lang['error.translation_in_same_context'] = 'Een vertaling kan in dezelfde channel gemaakt worden.'; -$_lang['error.translation_already_exists'] = 'Er is reeds een vertaling in channel [[+context]].'; -$_lang['error.could_not_create_translation'] = 'Er is een fout opgetreden tijdens het maken van een vertaling in channel [[+context]].'; - -$_lang['babel.context_err_ns'] = 'Channel is niet gespecificeerd.'; + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel'] = 'Babel'; +$_lang['babel.about'] = 'Over Babel'; +$_lang['babel.all'] = 'Alle'; +$_lang['babel.context_err_invalid_key'] = '[[+context]] is geen geldige channel key.'; +$_lang['babel.context_err_ns'] = 'Channel is niet gespecificeerd.'; +$_lang['babel.contexts'] = 'Contexten'; +$_lang['babel.contexts_desc'] = 'Beheer de links tussen de bronnen in verschillende contexten/talen op één plek. Gebruik de volgende knoppen om de links te bewerken:'; +$_lang['babel.contexts_desc_create'] = 'Maak een nieuwe bron aan die moet worden gekoppeld'; +$_lang['babel.contexts_desc_link'] = 'Link naar deze bron en de gekoppelde bronnen'; +$_lang['babel.contexts_desc_unlink'] = 'Verbinding verbreken'; +$_lang['babel.contexts_desc_update'] = 'Werk deze gekoppelde bron bij'; +$_lang['babel.copy_tv_values'] = 'Kopieer template variabelen naar geselecteerde pagina'; +$_lang['babel.create_translation'] = 'Maak vertaling'; +$_lang['babel.create_translation_confirm'] = 'Weet je zeker dat je een nieuwe vertaling van deze pagina wil toevoegen in de "[[+context]]" channel?'; +$_lang['babel.debug_mode'] = 'Debug Mode'; +$_lang['babel.desc'] = 'Meertalig systeem beheren'; +$_lang['babel.target_id'] = 'Doel-ID'; +$_lang['babel.link_translation'] = 'Koppelen aan bestaande pagina'; +$_lang['babel.open'] = 'Openen'; +$_lang['babel.or'] = '… of'; +$_lang['babel.target_pagetitle'] = '... of zoek naar de paginatitel van het doelwit'; +$_lang['babel.please_wait'] = 'Even wachten …'; +$_lang['babel.reset'] = 'Reset'; +$_lang['babel.resource_err_from_other_context'] = 'Resource [[+resource]] bestaat niet in channel "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] is geen geldige pagina id.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Een link naar een bron zelf kan niet gelinkt worden.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Een link naar dezelfde pagina kan niet verwijderd worden.'; +$_lang['babel.search'] = 'Zoeken …'; +$_lang['babel.select_context'] = 'Selecteer context'; +$_lang['babel.select_tree_node'] = 'Selecteer een knooppunt in de boomstructuur'; +$_lang['babel.settings'] = 'Instellingen'; +$_lang['babel.settings_desc'] = 'De instellingen van Babel bewerken. Je kunt de waarde van een systeeminstelling bewerken door te dubbelklikken op de tabelcel \'Waarde\' of door rechts te klikken in de tabelcel.'; +$_lang['babel.sync_linked_tranlations'] = 'Alle vertalingen van het doel synchroniseren'; +$_lang['babel.systemsetting_key_err_nv'] = 'Je kunt alleen instellingen bewerken met het voorvoegsel babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Alleen gebruikers met de rechten settings of settings_babel kunnen de instellingen wijzigen.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Er is een fout opgetreden tijdens het maken van een vertaling in channel [[+context]].'; +$_lang['babel.translation_pending'] = '[in afwachting van vertaling]'; +$_lang['babel.tv_caption'] = 'Babel Vertaal Links'; +$_lang['babel.tv_description'] = 'Onderhouden door Babel plugin. Gelieve niet te veranderen!'; +$_lang['babel.unlink'] = 'Verwijder'; +$_lang['babel.unlink_all_translations'] = 'Alle vertalingen ontkoppelen'; +$_lang['babel.unlink_all_translations_confirm'] = 'Weet je zeker dat je alle vertalingen uit deze bron wilt verwijderen?'; +$_lang['babel.unlink_translation_confirm'] = 'Weet je zeker dat je deze vertaling wil verwijderen van deze pagina in de "[[+context]]" channel?'; diff --git a/core/components/babel/lexicon/nl/languages.inc.php b/core/components/babel/lexicon/nl/languages.inc.php new file mode 100644 index 0000000..96d4a48 --- /dev/null +++ b/core/components/babel/lexicon/nl/languages.inc.php @@ -0,0 +1,41 @@ + - * - * @package babel - * @subpackage lexicon - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk voor de weergave van een taal link'; -$_lang['babellinks.activeCls'] = 'CSS class voor de actieve taal link'; -$_lang['babellinks.resourceId'] = 'Id van resource waarvan link naar vertaling moeten worden weergegeven'; -$_lang['babellinks.showUnpublished'] = 'Wel of niet tonen van ongepubliceerde vertalingen'; -$_lang['babellinks.showCurrent'] = 'Wel of niet tonen van link naar vertaling van de huidige taal'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID van resource waarvan een vertaalde resource dient te worden bepaald'; -$_lang['babeltranslation.contextKey'] = 'Context key waarin vertaalde bron dient te worden bepaald'; -$_lang['babeltranslation.showUnpublished'] = 'Wel of niet tonen van ongepubliceerde vertalingen'; \ No newline at end of file + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel.babellinks.activeCls'] = 'CSS class voor de actieve taal link.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Vlag of de site_status moet worden genegeerd (als de site offline is)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Vlag of niet-gelinkte context moet worden weergegeven.'; +$_lang['babel.babellinks.resourceId'] = 'Id van resource waarvan link naar vertaling moeten worden weergegeven.'; +$_lang['babel.babellinks.restrictToGroup'] = "Beperk de contexten in de knipseluitvoer tot de groep van de huidige context."; +$_lang['babel.babellinks.showCurrent'] = 'Wel of niet tonen van link naar vertaling van de huidige taal.'; +$_lang['babel.babellinks.showUnpublished'] = 'Wel of niet tonen van ongepubliceerde vertalingen.'; +$_lang['babel.babellinks.toArray'] = 'Vlag of de uitvoer als een matrix moet worden gedumpt.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Vlag of de uitvoer in de naam van de opgegeven plaatshouder moet worden gedumpt.'; +$_lang['babel.babellinks.tpl'] = 'Chunk voor de weergave van een taal link.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Chunk om alle taallinks in te pakken. De plaatshouder voor alle links is [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Context key waarin vertaalde bron dient te worden bepaald.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Sleutel van cultuur waarin vertaalde bron moet worden bepaald. Wordt alleen gebruikt als contextKey niet is opgegeven. Als beide weggelaten het knipsel de huidige ingestelde cultureKey.'; +$_lang['babel.babeltranslation.resourceId'] = 'ID van resource waarvan een vertaalde resource dient te worden bepaald.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Wel of niet tonen van ongepubliceerde vertalingen.'; diff --git a/core/components/babel/lexicon/pl/default.inc.php b/core/components/babel/lexicon/pl/default.inc.php index 304b770..8b70655 100644 --- a/core/components/babel/lexicon/pl/default.inc.php +++ b/core/components/babel/lexicon/pl/default.inc.php @@ -1,97 +1,52 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Polish language file - * * @author Jakub Kalina * * @package babel * @subpackage lexicon - * */ - -$_lang['babel.tv_caption'] = 'Łącza do tłumaczeń Babel'; -$_lang['babel.tv_description'] = 'Zarządzane przez wtyczkę Babel. Proszę nie modyfikować!'; +$_lang['babel'] = 'Babel'; +$_lang['babel.about'] = 'O Babel'; +$_lang['babel.all'] = 'Wszystkie'; +$_lang['babel.context_err_invalid_key'] = '[[+context]] nie jest poprawnym kluczem kontekstu.'; +$_lang['babel.context_err_ns'] = 'Nie zdefiniowano kontekstu.'; +$_lang['babel.contexts'] = 'Konteksty'; +$_lang['babel.contexts_desc'] = 'Zarządzaj linkami między zasobami w różnych kontekstach/językach w jednym miejscu. Użyj poniższych przycisków, aby edytować linki:'; +$_lang['babel.contexts_desc_create'] = 'Utwórz nowy zasób do połączenia'; +$_lang['babel.contexts_desc_link'] = 'Link do tego zasobu i powiązanych z nim zasobów'; +$_lang['babel.contexts_desc_unlink'] = 'Przerwać połączenie'; +$_lang['babel.contexts_desc_update'] = 'Zaktualizuj ten powiązany zasób'; +$_lang['babel.copy_tv_values'] = 'Skopiuj wartości synchronizowanych zmiennych szablonu (TV) do zasobu docelowego'; $_lang['babel.create_translation'] = 'Utwórz tłumaczenie'; $_lang['babel.create_translation_confirm'] = 'Czy jesteś pewien, że chcesz stworzyć nowe tłumaczenie tego zasobu dla kontekstu "[[+context]]"?'; -$_lang['babel.unlink'] = 'Odłącz'; -$_lang['babel.unlink_translation'] = 'Odłącz tłumaczenie'; -$_lang['babel.unlink_translation_confirm'] = 'Czy jesteś pewien, że chcesz odłączyć tłumaczenie tego zasobu dla kontekstu "[[+context]]"?'; -$_lang['babel.link_translation_manually'] = 'lub połącz tłumaczenia ręcznie:'; +$_lang['babel.debug_mode'] = 'Tryb debugowania'; +$_lang['babel.desc'] = 'Zarządzanie systemem wielojęzycznym'; +$_lang['babel.target_id'] = 'ID zasobu docelowego'; $_lang['babel.link_translation'] = 'Połącz z istniejącym zasobem'; -$_lang['babel.id_of_target'] = 'ID zasobu docelowego:'; -$_lang['babel.copy_tv_values'] = 'Skopiuj wartości synchronizowanych zmiennych szablonu (TV) do zasobu docelowego'; -$_lang['babel.save'] = 'Zapisz'; -$_lang['babel.translation_pending'] = '[wymaga przetłumaczenia]'; $_lang['babel.open'] = 'Otwórz'; -$_lang['babel.please_wait'] = 'Proszę czekać...'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabski'; -$_lang['babel.language_bg'] = 'Bułgarski'; -$_lang['babel.language_ca'] = 'Kataloński'; -$_lang['babel.language_cs'] = 'Czeski'; -$_lang['babel.language_da'] = 'Duński'; -$_lang['babel.language_de'] = 'Niemiecki'; -$_lang['babel.language_en'] = 'Angielski'; -$_lang['babel.language_es'] = 'Hiszpański'; -$_lang['babel.language_fa'] = 'Perski'; -$_lang['babel.language_fi'] = 'Fiński'; -$_lang['babel.language_fr'] = 'Francuski'; -$_lang['babel.language_he'] = 'Hebrajski'; -$_lang['babel.language_hu'] = 'Węgierski'; -$_lang['babel.language_id'] = 'Indonezyjski'; -$_lang['babel.language_it'] = 'Włoski'; -$_lang['babel.language_ja'] = 'Japoński'; -$_lang['babel.language_ko'] = 'Koreański'; -$_lang['babel.language_lt'] = 'Litewski'; -$_lang['babel.language_ms'] = 'Malajski'; -$_lang['babel.language_nl'] = 'Holenderski'; -$_lang['babel.language_no'] = 'Norweski (Bokmål)'; -$_lang['babel.language_pl'] = 'Polski'; -$_lang['babel.language_pt'] = 'Portugalski'; -$_lang['babel.language_ro'] = 'Rumuński'; -$_lang['babel.language_ru'] = 'Rosyjski'; -$_lang['babel.language_sk'] = 'Słowacki'; -$_lang['babel.language_sl'] = 'Słoweński'; -$_lang['babel.language_sr'] = 'Serbski'; -$_lang['babel.language_sv'] = 'Szwedzki'; -$_lang['babel.language_tr'] = 'Turecki'; -$_lang['babel.language_uk'] = 'Ukraiński'; -$_lang['babel.language_vi'] = 'Wietnamski'; -$_lang['babel.language_zh'] = 'Chiński'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] nie jest poprawnym kluczem kontekstu.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] nie jest poprawnym ID zasobu.'; -$_lang['error.resource_from_other_context'] = 'Zasób [[+resource]] nie istnieje dla kontekstu "[[+context]]".'; -$_lang['error.resource_already_linked'] = 'Zasób [[+resource]] jest już połączony z innymi zasobami.'; -$_lang['error.no_link_to_context'] = 'Nie istnieje łącze dla kontekstu [[+context]].'; -$_lang['error.link_of_selflink_not_possible'] = 'Zasób nie może był połączony ze samym sobą.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Zasób nie może być odłączony od samego siebie.'; -$_lang['error.translation_in_same_context'] = 'Tłumaczenie nie może być tworzone dla tego samego kontekstu.'; -$_lang['error.translation_already_exists'] = 'W kontekście "[[+context]]" istnieje już tłumaczenie: "[[+pagetitle]] ([[+resource]])"'; -$_lang['error.could_not_create_translation'] = 'Wystąpił błąd podczas próby utworzenia tłumaczenia dla kontekstu [[+context]].'; - -$_lang['babel.context_err_ns'] = 'Nie zdefiniowano kontekstu.'; \ No newline at end of file +$_lang['babel.or'] = '… lub'; +$_lang['babel.target_pagetitle'] = 'Tytuł strony docelowej'; +$_lang['babel.please_wait'] = 'Proszę czekać …'; +$_lang['babel.reset'] = 'Reset'; +$_lang['babel.resource_err_from_other_context'] = 'Zasób [[+resource]] nie istnieje dla kontekstu "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] nie jest poprawnym ID zasobu.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Zasób nie może był połączony ze samym sobą.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Zasób nie może być odłączony od samego siebie.'; +$_lang['babel.search'] = 'Szukaj …'; +$_lang['babel.select_context'] = 'Wybierz kontekst'; +$_lang['babel.select_tree_node'] = 'Wybierz węzeł w drzewie zasobów'; +$_lang['babel.settings'] = 'Ustawienia'; +$_lang['babel.settings_desc'] = 'Edycja ustawień Babel. Wartość ustawienia systemowego można edytować, klikając dwukrotnie komórkę tabeli "Wartość" lub klikając prawym przyciskiem myszy komórkę tabeli.'; +$_lang['babel.sync_linked_tranlations'] = 'Synchronizacja wszystkich tłumaczeń z pliku docelowego'; +$_lang['babel.systemsetting_key_err_nv'] = 'Edytować można tylko ustawienia z przedrostkiem babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Tylko użytkownicy z uprawnieniami settings lub settings_babel mogą zmieniać ustawienia.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Wystąpił błąd podczas próby utworzenia tłumaczenia dla kontekstu [[+context]].'; +$_lang['babel.translation_pending'] = '[wymaga przetłumaczenia]'; +$_lang['babel.tv_caption'] = 'Łącza do tłumaczeń Babel'; +$_lang['babel.tv_description'] = 'Zarządzane przez wtyczkę Babel. Proszę nie modyfikować!'; +$_lang['babel.unlink'] = 'Odłącz'; +$_lang['babel.unlink_all_translations'] = 'Odłącz wszystkie tłumaczenia'; +$_lang['babel.unlink_all_translations_confirm'] = 'Czy na pewno chcesz usunąć wszystkie tłumaczenia z tego zasobu?'; +$_lang['babel.unlink_translation_confirm'] = 'Czy jesteś pewien, że chcesz odłączyć tłumaczenie tego zasobu dla kontekstu "[[+context]]"?'; diff --git a/core/components/babel/lexicon/pl/languages.inc.php b/core/components/babel/lexicon/pl/languages.inc.php new file mode 100644 index 0000000..98f7451 --- /dev/null +++ b/core/components/babel/lexicon/pl/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties Polish language file - * * @author Jakub Kalina * * @package babel * @subpackage lexicon */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Fragment wyświetlający łącze do zmiany języka'; -$_lang['babellinks.activeCls'] = 'Klasa CSS używana przez aktywne łącze do zmiany języka'; -$_lang['babellinks.resourceId'] = 'ID zasobu, dla którego wyświetlać łącza przetłumaczonych wersji'; -$_lang['babellinks.showUnpublished'] = 'Pokazuj nieopublikowane tłumaczenia'; -$_lang['babellinks.showCurrent'] = 'Wyświetl łącze do aktywnego języka'; -$_lang['babellinks.includeUnlinked'] = 'Pokazuj odłączone konteksty'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID zasobu, dla którego zwrócić ID przetłumaczonego zasobu'; -$_lang['babeltranslation.contextKey'] = 'Klucz kontekstu, dla którego zwrócić ID przetłumaczonego zasobu'; -$_lang['babeltranslation.showUnpublished'] = 'Pokazuj nieopublikowane tłumaczenia'; \ No newline at end of file +$_lang['babel.babellinks.activeCls'] = 'Klasa CSS używana przez aktywne łącze do zmiany języka.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Flaga, czy ignorować site_status (gdy witryna jest w trybie offline)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Pokazuj odłączone konteksty.'; +$_lang['babel.babellinks.resourceId'] = 'ID zasobu, dla którego wyświetlać łącza przetłumaczonych wersji.'; +$_lang['babel.babellinks.restrictToGroup'] = 'Ogranicz konteksty w wyjściu snippetu do grupy bieżącego kontekstu'; +$_lang['babel.babellinks.showCurrent'] = 'Wyświetl łącze do aktywnego języka.'; +$_lang['babel.babellinks.showUnpublished'] = 'Pokazuj nieopublikowane tłumaczenia.'; +$_lang['babel.babellinks.toArray'] = 'Flaga określająca, czy zamiast tego dane wyjściowe mają być zrzucane jako tablica.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Flaga określająca, czy dane wyjściowe mają być zrzucane do nazwy podanego symbolu zastępczego.'; +$_lang['babel.babellinks.tpl'] = 'Fragment wyświetlający łącze do zmiany języka.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Fragment do zawijania wszystkich linków językowych. Symbol zastępczy dla wszystkich linków to [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Klucz kontekstu, dla którego zwrócić ID przetłumaczonego zasobu.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Klucz kultury, w której powinien zostać określony przetłumaczony zasób. Używany tylko w przypadku, gdy contextKey nie został określony. Jeśli oba pominięto, snippet aktualnie ustawiony cultureKey.'; +$_lang['babel.babeltranslation.resourceId'] = 'ID zasobu, dla którego zwrócić ID przetłumaczonego zasobu.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Pokazuj nieopublikowane tłumaczenia.'; diff --git a/core/components/babel/lexicon/pt-br/cmp.inc.php b/core/components/babel/lexicon/pt-br/cmp.inc.php deleted file mode 100644 index 9850a42..0000000 --- a/core/components/babel/lexicon/pt-br/cmp.inc.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Gerir sistema multilíngue'; -$_lang['babel.search...'] = 'Pesquisar...'; -$_lang['babel.filter'] = 'Filtrar'; -$_lang['babel.reset'] = 'Repor'; -$_lang['babel.icon_descriptions'] = ' Ligar a esta página (recurso) e respectivas páginas ligadas
' - . ' Limpar todas as ligações
' - . ' Edite esta página (recurso) ligada
' - . ' Crie uma nova página (recurso) a ser ligado
'; diff --git a/core/components/babel/lexicon/pt-br/default.inc.php b/core/components/babel/lexicon/pt-br/default.inc.php index 05536d1..a5bd7aa 100644 --- a/core/components/babel/lexicon/pt-br/default.inc.php +++ b/core/components/babel/lexicon/pt-br/default.inc.php @@ -1,119 +1,52 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Gerir sistema multilingue'; -$_lang['babel.tv_caption'] = 'Ligações de Tradução do Babel'; -$_lang['babel.tv_description'] = 'Gerido pelo plugin Babel. Por favor, não modificar!'; -$_lang['babel.create_translation'] = 'Criar tradução'; -$_lang['babel.create_translation_confirm'] = 'Tem a certeza de que deseja criar uma nova tradução para esta página (recurso) para o contexto "[[+context]]"?'; -$_lang['babel.unlink'] = 'Separar'; -$_lang['babel.unlink_translation'] = 'Separar tradução'; -$_lang['babel.unlink_translation_confirm'] = 'Tem a certeza de que deseja separar a tradução para esta página (recurso) para o contexto "[[+context]]"?'; -$_lang['babel.unlink_all_translations'] = 'Separar todas as traduções'; -$_lang['babel.unlink_all_translations_confirm'] = 'Tem a certeza de que deseja separar todas as traduções para esta página (recurso)?'; -$_lang['babel.link_translation_manually'] = 'ou ligar tradução manualmente:'; -$_lang['babel.link_translation'] = 'Ligar a página (recurso) existente'; -$_lang['babel.id_of_target'] = 'ID do destino:'; -$_lang['babel....or'] = '... ou'; -$_lang['babel.pagetitle_of_target'] = 'Título da página do destino:'; -$_lang['babel.copy_tv_values'] = 'Copiar TVs sincronizados para o destino'; -$_lang['babel.save'] = 'Guardar'; -$_lang['babel.translation_pending'] = '[traduções pendentes]'; -$_lang['babel.open'] = 'Abrir'; -$_lang['babel.please_wait'] = 'Por favor, aguarde...'; -$_lang['babel.sync_linked_tranlations'] = 'Sincronizar todas as traduções a partir do destino'; -$_lang['babel.select_tree_node'] = 'Selecione um elemento da árvore de páginas (recursos)'; -$_lang['babel.all'] = 'Tudo'; - -/** - * DEPRECATED - */ -/* language names */ -$_lang['babel.language_ar'] = 'Árabe'; -$_lang['babel.language_bg'] = 'Búlgaro'; -$_lang['babel.language_ca'] = 'Catalão'; -$_lang['babel.language_cs'] = 'Checo'; -$_lang['babel.language_da'] = 'Dinamarquês'; -$_lang['babel.language_de'] = 'Alemão'; -$_lang['babel.language_en'] = 'Inglês'; -$_lang['babel.language_es'] = 'Espanhol'; -$_lang['babel.language_fa'] = 'Persa'; -$_lang['babel.language_fi'] = 'Finlandês'; -$_lang['babel.language_fr'] = 'Francês'; -$_lang['babel.language_he'] = 'Hebraico'; -$_lang['babel.language_hu'] = 'Húngaro'; -$_lang['babel.language_id'] = 'Indonésio'; -$_lang['babel.language_it'] = 'Italiano'; -$_lang['babel.language_ja'] = 'Japonês'; -$_lang['babel.language_ko'] = 'Coreano'; -$_lang['babel.language_lt'] = 'Lituano'; -$_lang['babel.language_ms'] = 'Malaio'; -$_lang['babel.language_nl'] = 'Holandês'; -$_lang['babel.language_no'] = 'Norueguês (Bokmål)'; -$_lang['babel.language_pl'] = 'Polaco'; -$_lang['babel.language_pt'] = 'Português'; -$_lang['babel.language_ro'] = 'Romeno'; -$_lang['babel.language_ru'] = 'Russo'; -$_lang['babel.language_sk'] = 'Eslovaco'; -$_lang['babel.language_sl'] = 'Esloveno'; -$_lang['babel.language_sr'] = 'Sérvio'; -$_lang['babel.language_sv'] = 'Sueco'; -$_lang['babel.language_tr'] = 'Turco'; -$_lang['babel.language_uk'] = 'Ucraniano'; -$_lang['babel.language_vi'] = 'Vietnamita'; -$_lang['babel.language_zh'] = 'Chinês'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] não é uma chave de contexto válida.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] não é um ID de página (recurso) válida.'; -$_lang['error.resource_from_other_context'] = 'A Página (recurso) [[+resource]] não existe no contexto "[[+context]]".'; -$_lang['error.resource_already_linked'] = 'A Página (recurso) [[+resource]] já está ligada a outras páginas.'; -$_lang['error.no_link_to_context'] = 'Não existe nenhuma ligação para o contexto [[+context]].'; -$_lang['error.link_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser criada.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser eliminada.'; -$_lang['error.translation_in_same_context'] = 'Uma tradução não pode ser criada dentro do mesmo contexto.'; -$_lang['error.translation_already_exists'] = 'Já existe uma tradução no contexto "[[+context]]": "[[+pagetitle]] ([[+resource]])"'; -$_lang['error.could_not_create_translation'] = 'Ocorreu um erro ao tentar criar uma tradução no contexto [[+context]].'; - -$_lang['babel.context_err_ns'] = 'Não foi especificado um contexto.'; - -$_lang['setting_babel.contextKeys'] = 'Chaves de Contextos'; -$_lang['setting_babel.contextKeys_desc'] = 'Lista separada por vírgulas de chaves de contextos que devem ser utilizadas para ligar páginas (recursos) multilíngues.'; -$_lang['setting_babel.babelTvName'] = 'Nome do TV do Babel'; -$_lang['setting_babel.babelTvName_desc'] = 'Nome do TV onde o Babel irá guardar as ligações entre páginas (recursos) multilíngue. Este TV será gerido pelo Babel.'; -$_lang['setting_babel.syncTvs'] = 'TVs a serem sincronizados'; -$_lang['setting_babel.syncTvs_desc'] = 'Lista separada por vírgulas de IDs de TVs que deverão ser sincronizados pelo Babel.'; +"[[+context]]"?'; +$_lang['babel.debug_mode'] = 'Modo de depuração'; +$_lang['babel.desc'] = 'Gerir sistema multilingue'; +$_lang['babel.target_id'] = 'ID do destino'; +$_lang['babel.link_translation'] = 'Ligar a página (recurso) existente'; +$_lang['babel.open'] = 'Abrir'; +$_lang['babel.or'] = '… ou'; +$_lang['babel.target_pagetitle'] = '... ou pesquisar o título da página de destino'; +$_lang['babel.please_wait'] = 'Por favor, aguarde …'; +$_lang['babel.reset'] = 'Repor'; +$_lang['babel.resource_err_from_other_context'] = 'A Página (recurso) [[+resource]] não existe no contexto "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] não é um ID de página (recurso) válida.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser criada.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser eliminada.'; +$_lang['babel.search'] = 'Pesquisar …'; +$_lang['babel.select_context'] = 'Selecionar contexto'; +$_lang['babel.select_tree_node'] = 'Selecione um nó na árvore de recursos'; +$_lang['babel.settings'] = 'Configurações'; +$_lang['babel.settings_desc'] = 'Editar as configurações do Babel. Você pode editar o valor de uma configuração do sistema clicando duas vezes na célula da tabela "Valor" ou clicando com o botão direito do mouse na célula da tabela.'; +$_lang['babel.sync_linked_tranlations'] = 'Sincronizar todas as traduções a partir do destino'; +$_lang['babel.systemsetting_key_err_nv'] = 'Você só pode editar configurações com o prefixo babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Somente usuários com a permissão settings ou settings_babel podem alterar as configurações.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Ocorreu um erro ao tentar criar uma tradução no contexto [[+context]].'; +$_lang['babel.translation_pending'] = '[traduções pendentes]'; +$_lang['babel.tv_caption'] = 'Ligações de Tradução do Babel'; +$_lang['babel.tv_description'] = 'Gerido pelo plugin Babel. Por favor, não modificar!'; +$_lang['babel.unlink'] = 'Separar'; +$_lang['babel.unlink_all_translations'] = 'Separar todas as traduções'; +$_lang['babel.unlink_all_translations_confirm'] = 'Tem a certeza de que deseja separar todas as traduções para esta página (recurso)?'; +$_lang['babel.unlink_translation_confirm'] = 'Tem a certeza de que deseja separar a tradução para esta página (recurso) para o contexto "[[+context]]"?'; diff --git a/core/components/babel/lexicon/pt-br/languages.inc.php b/core/components/babel/lexicon/pt-br/languages.inc.php new file mode 100644 index 0000000..b19d57a --- /dev/null +++ b/core/components/babel/lexicon/pt-br/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties English language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk para apresentar a hiperligação da língua'; -$_lang['babellinks.activeCls'] = 'Classe de CSS para a hiperligação da língua ativa'; -$_lang['babellinks.resourceId'] = 'Id da página (recurso) para a qual as hiperligações das traduções devam ser apresentadas'; -$_lang['babellinks.showUnpublished'] = 'Indicar se deseja apresentar traduções não publicadas'; -$_lang['babellinks.showCurrent'] = 'Indicar se deseja apresentar uma hiperligação para uma tradução do idioma atual'; -$_lang['babellinks.includeUnlinked'] = 'Indicar se deseja apresentar contextos sem associação'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID da página (recurso) para a qual uma pãgina (recurso) traduzida deva ser determinado'; -$_lang['babeltranslation.contextKey'] = 'Chave do contexto em que a página (recurso) traduzida deva ser determinado'; -$_lang['babeltranslation.showUnpublished'] = 'Indicar se deseja apresentar traduções não publicadas'; \ No newline at end of file + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Gerir sistema multilíngue'; -$_lang['babel.search...'] = 'Pesquisar...'; -$_lang['babel.filter'] = 'Filtrar'; -$_lang['babel.reset'] = 'Repor'; -$_lang['babel.icon_descriptions'] = ' Ligar a esta página (recurso) e respectivas páginas ligadas
' - . ' Limpar todas as ligações
' - . ' Edite esta página (recurso) ligada
' - . ' Crie uma nova página (recurso) a ser ligado
'; diff --git a/core/components/babel/lexicon/pt/default.inc.php b/core/components/babel/lexicon/pt/default.inc.php index 05536d1..7fa6f04 100644 --- a/core/components/babel/lexicon/pt/default.inc.php +++ b/core/components/babel/lexicon/pt/default.inc.php @@ -1,119 +1,52 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel English language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Gerir sistema multilingue'; -$_lang['babel.tv_caption'] = 'Ligações de Tradução do Babel'; -$_lang['babel.tv_description'] = 'Gerido pelo plugin Babel. Por favor, não modificar!'; -$_lang['babel.create_translation'] = 'Criar tradução'; -$_lang['babel.create_translation_confirm'] = 'Tem a certeza de que deseja criar uma nova tradução para esta página (recurso) para o contexto "[[+context]]"?'; -$_lang['babel.unlink'] = 'Separar'; -$_lang['babel.unlink_translation'] = 'Separar tradução'; -$_lang['babel.unlink_translation_confirm'] = 'Tem a certeza de que deseja separar a tradução para esta página (recurso) para o contexto "[[+context]]"?'; -$_lang['babel.unlink_all_translations'] = 'Separar todas as traduções'; -$_lang['babel.unlink_all_translations_confirm'] = 'Tem a certeza de que deseja separar todas as traduções para esta página (recurso)?'; -$_lang['babel.link_translation_manually'] = 'ou ligar tradução manualmente:'; -$_lang['babel.link_translation'] = 'Ligar a página (recurso) existente'; -$_lang['babel.id_of_target'] = 'ID do destino:'; -$_lang['babel....or'] = '... ou'; -$_lang['babel.pagetitle_of_target'] = 'Título da página do destino:'; -$_lang['babel.copy_tv_values'] = 'Copiar TVs sincronizados para o destino'; -$_lang['babel.save'] = 'Guardar'; -$_lang['babel.translation_pending'] = '[traduções pendentes]'; -$_lang['babel.open'] = 'Abrir'; -$_lang['babel.please_wait'] = 'Por favor, aguarde...'; -$_lang['babel.sync_linked_tranlations'] = 'Sincronizar todas as traduções a partir do destino'; -$_lang['babel.select_tree_node'] = 'Selecione um elemento da árvore de páginas (recursos)'; -$_lang['babel.all'] = 'Tudo'; - -/** - * DEPRECATED - */ -/* language names */ -$_lang['babel.language_ar'] = 'Árabe'; -$_lang['babel.language_bg'] = 'Búlgaro'; -$_lang['babel.language_ca'] = 'Catalão'; -$_lang['babel.language_cs'] = 'Checo'; -$_lang['babel.language_da'] = 'Dinamarquês'; -$_lang['babel.language_de'] = 'Alemão'; -$_lang['babel.language_en'] = 'Inglês'; -$_lang['babel.language_es'] = 'Espanhol'; -$_lang['babel.language_fa'] = 'Persa'; -$_lang['babel.language_fi'] = 'Finlandês'; -$_lang['babel.language_fr'] = 'Francês'; -$_lang['babel.language_he'] = 'Hebraico'; -$_lang['babel.language_hu'] = 'Húngaro'; -$_lang['babel.language_id'] = 'Indonésio'; -$_lang['babel.language_it'] = 'Italiano'; -$_lang['babel.language_ja'] = 'Japonês'; -$_lang['babel.language_ko'] = 'Coreano'; -$_lang['babel.language_lt'] = 'Lituano'; -$_lang['babel.language_ms'] = 'Malaio'; -$_lang['babel.language_nl'] = 'Holandês'; -$_lang['babel.language_no'] = 'Norueguês (Bokmål)'; -$_lang['babel.language_pl'] = 'Polaco'; -$_lang['babel.language_pt'] = 'Português'; -$_lang['babel.language_ro'] = 'Romeno'; -$_lang['babel.language_ru'] = 'Russo'; -$_lang['babel.language_sk'] = 'Eslovaco'; -$_lang['babel.language_sl'] = 'Esloveno'; -$_lang['babel.language_sr'] = 'Sérvio'; -$_lang['babel.language_sv'] = 'Sueco'; -$_lang['babel.language_tr'] = 'Turco'; -$_lang['babel.language_uk'] = 'Ucraniano'; -$_lang['babel.language_vi'] = 'Vietnamita'; -$_lang['babel.language_zh'] = 'Chinês'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] não é uma chave de contexto válida.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] não é um ID de página (recurso) válida.'; -$_lang['error.resource_from_other_context'] = 'A Página (recurso) [[+resource]] não existe no contexto "[[+context]]".'; -$_lang['error.resource_already_linked'] = 'A Página (recurso) [[+resource]] já está ligada a outras páginas.'; -$_lang['error.no_link_to_context'] = 'Não existe nenhuma ligação para o contexto [[+context]].'; -$_lang['error.link_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser criada.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser eliminada.'; -$_lang['error.translation_in_same_context'] = 'Uma tradução não pode ser criada dentro do mesmo contexto.'; -$_lang['error.translation_already_exists'] = 'Já existe uma tradução no contexto "[[+context]]": "[[+pagetitle]] ([[+resource]])"'; -$_lang['error.could_not_create_translation'] = 'Ocorreu um erro ao tentar criar uma tradução no contexto [[+context]].'; - -$_lang['babel.context_err_ns'] = 'Não foi especificado um contexto.'; - -$_lang['setting_babel.contextKeys'] = 'Chaves de Contextos'; -$_lang['setting_babel.contextKeys_desc'] = 'Lista separada por vírgulas de chaves de contextos que devem ser utilizadas para ligar páginas (recursos) multilíngues.'; -$_lang['setting_babel.babelTvName'] = 'Nome do TV do Babel'; -$_lang['setting_babel.babelTvName_desc'] = 'Nome do TV onde o Babel irá guardar as ligações entre páginas (recursos) multilíngue. Este TV será gerido pelo Babel.'; -$_lang['setting_babel.syncTvs'] = 'TVs a serem sincronizados'; -$_lang['setting_babel.syncTvs_desc'] = 'Lista separada por vírgulas de IDs de TVs que deverão ser sincronizados pelo Babel.'; +"[[+context]]"?'; +$_lang['babel.debug_mode'] = 'Modo de depuração'; +$_lang['babel.desc'] = 'Gerir sistema multilingue'; +$_lang['babel.target_id'] = 'ID do destino'; +$_lang['babel.link_translation'] = 'Ligar a página (recurso) existente'; +$_lang['babel.open'] = 'Abrir'; +$_lang['babel.or'] = '… ou'; +$_lang['babel.target_pagetitle'] = '... ou procurar o título da página de destino'; +$_lang['babel.please_wait'] = 'Por favor, aguarde …'; +$_lang['babel.reset'] = 'Reiniciar'; +$_lang['babel.resource_err_from_other_context'] = 'A Página (recurso) [[+resource]] não existe no contexto "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] não é um ID de página (recurso) válida.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser criada.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Uma ligação para a própria página (recurso) não pode ser eliminada.'; +$_lang['babel.search'] = 'Pesquisar …'; +$_lang['babel.select_context'] = 'Selecionar contexto'; +$_lang['babel.select_tree_node'] = 'Selecionar um nó na árvore de recursos'; +$_lang['babel.settings'] = 'Definições'; +$_lang['babel.settings_desc'] = 'Editar as definições da Babel. Pode editar o valor de uma definição do sistema fazendo duplo clique na célula da tabela "Valor" ou clicando com o botão direito do rato na célula da tabela.'; +$_lang['babel.sync_linked_tranlations'] = 'Sincronizar todas as traduções a partir do destino'; +$_lang['babel.systemsetting_key_err_nv'] = 'Só é possível editar definições com o prefixo babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Apenas os utilizadores com uma permissão de definições ou uma permissão settings_babel podem alterar as definições.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Ocorreu um erro ao tentar criar uma tradução no contexto [[+context]].'; +$_lang['babel.translation_pending'] = '[traduções pendentes]'; +$_lang['babel.tv_caption'] = 'Ligações de Tradução do Babel'; +$_lang['babel.tv_description'] = 'Gerido pelo plugin Babel. Por favor, não modificar!'; +$_lang['babel.unlink'] = 'Separar'; +$_lang['babel.unlink_all_translations'] = 'Separar todas as traduções'; +$_lang['babel.unlink_all_translations_confirm'] = 'Tem a certeza de que deseja separar todas as traduções para esta página (recurso)?'; +$_lang['babel.unlink_translation_confirm'] = 'Tem a certeza de que deseja separar a tradução para esta página (recurso) para o contexto "[[+context]]"?'; diff --git a/core/components/babel/lexicon/pt/languages.inc.php b/core/components/babel/lexicon/pt/languages.inc.php new file mode 100644 index 0000000..b19d57a --- /dev/null +++ b/core/components/babel/lexicon/pt/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties English language file - * - * @author Jakob Class - * - * @package babel - * @subpackage lexicon - * @language pt (Translated by João Nogueira - JANogueira) - * - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Chunk para apresentar a hiperligação da língua'; -$_lang['babellinks.activeCls'] = 'Classe de CSS para a hiperligação da língua ativa'; -$_lang['babellinks.resourceId'] = 'Id da página (recurso) para a qual as hiperligações das traduções devam ser apresentadas'; -$_lang['babellinks.showUnpublished'] = 'Indicar se deseja apresentar traduções não publicadas'; -$_lang['babellinks.showCurrent'] = 'Indicar se deseja apresentar uma hiperligação para uma tradução do idioma atual'; -$_lang['babellinks.includeUnlinked'] = 'Indicar se deseja apresentar contextos sem associação'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID da página (recurso) para a qual uma pãgina (recurso) traduzida deva ser determinado'; -$_lang['babeltranslation.contextKey'] = 'Chave do contexto em que a página (recurso) traduzida deva ser determinado'; -$_lang['babeltranslation.showUnpublished'] = 'Indicar se deseja apresentar traduções não publicadas'; \ No newline at end of file + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Romanian language file - * - * @author Stefan Moldoveanu - * - * @package babel - * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language - */ - -$_lang['babel.tv_caption'] = 'Babel - legăturile către resursele traduse'; -$_lang['babel.tv_description'] = 'Menținut de pluginul Babel. Vă rugăm nu modificați!'; -$_lang['babel.create_translation'] = 'Crează traducere'; -$_lang['babel.unlink_translation'] = 'Anulează legătura către pagina tradusă'; -$_lang['babel.link_translation_manually'] = 'sau asociază pagina tradusă manual:'; -$_lang['babel.id_of_target'] = 'IDul paginii țintă:'; -$_lang['babel.copy_tv_values'] = 'Copiază TV sincronizate la țintă'; -$_lang['babel.save'] = 'Salvează'; -$_lang['babel.translation_pending'] = '[traducere în curs]'; - -/* language names */ -$_lang['babel.language_ar'] = 'Arabă'; -$_lang['babel.language_bg'] = 'Bulgară'; -$_lang['babel.language_ca'] = 'Catalană'; -$_lang['babel.language_cs'] = 'Cehă'; -$_lang['babel.language_da'] = 'Daneză'; -$_lang['babel.language_de'] = 'Germană'; -$_lang['babel.language_en'] = 'Engleză'; -$_lang['babel.language_es'] = 'Spaniolă'; -$_lang['babel.language_fa'] = 'Persană'; -$_lang['babel.language_fi'] = 'Finlandeză'; -$_lang['babel.language_fr'] = 'Franceză'; -$_lang['babel.language_he'] = 'Ebraică'; -$_lang['babel.language_hu'] = 'Maghiară'; -$_lang['babel.language_id'] = 'Indoneziană'; -$_lang['babel.language_it'] = 'Italiană'; -$_lang['babel.language_ja'] = 'Japoneză'; -$_lang['babel.language_ko'] = 'Coreeană'; -$_lang['babel.language_lt'] = 'Lituaniană'; -$_lang['babel.language_ms'] = 'Malaieză'; -$_lang['babel.language_nl'] = 'Olandeză'; -$_lang['babel.language_no'] = 'Norvegiană (Bokmål)'; -$_lang['babel.language_pl'] = 'Poloneză'; -$_lang['babel.language_pt'] = 'Portugheză'; -$_lang['babel.language_ro'] = 'Română'; -$_lang['babel.language_ru'] = 'Rusă'; -$_lang['babel.language_sk'] = 'Slovacă'; -$_lang['babel.language_sl'] = 'Slovenă'; -$_lang['babel.language_sr'] = 'Sârbă'; -$_lang['babel.language_sv'] = 'Suedeză'; -$_lang['babel.language_tr'] = 'Turcă'; -$_lang['babel.language_uk'] = 'Ucraineană'; -$_lang['babel.language_vi'] = 'Vietnameză'; -$_lang['babel.language_zh'] = 'Chineză'; - -/* error messages */ -$_lang['error.invalid_context_key'] = '[[+context]] nu este o cheie de context validă.'; -$_lang['error.invalid_resource_id'] = '[[+resource]] nu este un id vaild.'; -$_lang['error.resource_from_other_context'] = 'Resursa [[+resource]] nu există în contextul [[+context]].'; -$_lang['error.resource_already_linked'] = 'Resursa [[+resource]] este deja asociată cu alte resurse.'; -$_lang['error.no_link_to_context'] = 'Nu există legătură către contextul [[+context]].'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Nu se poate asocia resursa cu ea însăși.'; -$_lang['error.translation_in_same_context'] = 'Nu se poate crea o traducere în același context.'; -$_lang['error.translation_already_exists'] = 'Există deja o traducere în contextul [[+context]].'; -$_lang['error.could_not_create_translation'] = 'Eroare la crearea documentului de tradus în contextul [[+context]].'; + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel'] = 'Babel'; +$_lang['babel.about'] = 'Despre Babel'; +$_lang['babel.all'] = 'Toate'; +$_lang['babel.context_err_invalid_key'] = '[[+context]] nu este o cheie de context validă.'; +$_lang['babel.context_err_ns'] = 'Contextul nu a fost specificat.'; +$_lang['babel.contexts'] = 'Contexte'; +$_lang['babel.contexts_desc'] = 'Gestionați legăturile dintre resursele din diferite contexte/limbi într-un singur loc. Utilizați următoarele butoane pentru a edita legăturile:'; +$_lang['babel.contexts_desc_create'] = 'Creați o nouă resursă care să fie legată'; +$_lang['babel.contexts_desc_link'] = 'Legătura cu această resursă și cu resursele legate de aceasta'; +$_lang['babel.contexts_desc_unlink'] = 'Întrerupeți legătura'; +$_lang['babel.contexts_desc_update'] = 'Actualizați această resursă legată'; +$_lang['babel.copy_tv_values'] = 'Copiază TV sincronizate la țintă'; +$_lang['babel.create_translation'] = 'Crează traducere'; +$_lang['babel.create_translation_confirm'] = 'Sunteți sigur că doriți să creați o nouă traducere pentru această resursă pentru "[[+context]]" context?'; +$_lang['babel.debug_mode'] = 'Modul Debug'; +$_lang['babel.desc'] = 'Gestionarea sistemului multilingv'; +$_lang['babel.target_id'] = 'IDul paginii țintă'; +$_lang['babel.link_translation'] = 'Legătura cu resursa existentă'; +$_lang['babel.open'] = 'Deschideți'; +$_lang['babel.or'] = '… sau'; +$_lang['babel.target_pagetitle'] = '... sau căutați titlul paginii țintă'; +$_lang['babel.please_wait'] = 'Vă rugăm să așteptați …'; +$_lang['babel.reset'] = 'Resetare'; +$_lang['babel.resource_err_from_other_context'] = 'Resursa [[+resource]] nu există în contextul "[[+context]]".'; +$_lang['babel.resource_err_invalid_id'] = '[[+resource]] nu este un id vaild.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'O legătură către o resursă nu poate fi legată.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Nu se poate asocia resursa cu ea însăși.'; +$_lang['babel.search'] = 'Căutare …'; +$_lang['babel.select_context'] = 'Selectați contextul'; +$_lang['babel.select_tree_node'] = 'Selectați un nod din arborele de resurse'; +$_lang['babel.settings'] = 'Setări'; +$_lang['babel.settings_desc'] = 'Modificați setările din Babel. Puteți edita valoarea unei setări de sistem făcând dublu clic pe celula de tabel "Value" (Valoare) sau făcând clic dreapta în celula de tabel.'; +$_lang['babel.sync_linked_tranlations'] = 'Sincronizarea tuturor traducerilor de la țintă'; +$_lang['babel.systemsetting_key_err_nv'] = 'Puteți edita numai setările cu prefixul babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Numai utilizatorii care au permisiunea settings sau settings_babel pot modifica setările.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Eroare la crearea documentului de tradus în contextul [[+context]].'; +$_lang['babel.translation_pending'] = '[traducere în curs]'; +$_lang['babel.tv_caption'] = 'Babel - legăturile către resursele traduse'; +$_lang['babel.tv_description'] = 'Menținut de pluginul Babel. Vă rugăm nu modificați!'; +$_lang['babel.unlink'] = 'Dezlegare'; +$_lang['babel.unlink_all_translations'] = 'Dezlegarea tuturor traducerilor'; +$_lang['babel.unlink_all_translations_confirm'] = 'Sunteți sigur că doriți să dezlipiți toate traducerile din această resursă?'; +$_lang['babel.unlink_translation_confirm'] = 'Sunteți sigur că doriți să dezlipiți traducerea din această resursă la "[[+context]]" context?'; diff --git a/core/components/babel/lexicon/ro/languages.inc.php b/core/components/babel/lexicon/ro/languages.inc.php new file mode 100644 index 0000000..5b814b2 --- /dev/null +++ b/core/components/babel/lexicon/ro/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties Romanian language file - * - * @author Stefan Moldoveanu - * - * @package babel - * @subpackage lexicon - */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Elementul chunk ce afișează legăturile către resursele traduse'; -$_lang['babellinks.activeCls'] = 'Clasa CSS pentru legătura activă către resursele traduse'; -$_lang['babellinks.resourceId'] = 'Id-ul resursei de afișat'; -$_lang['babellinks.showUnpublished'] = 'Afișează traducerile nepublicate'; -$_lang['babellinks.showCurrent'] = 'Afișează o legătură către limba curentă'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'IDul resursei de tradus'; -$_lang['babeltranslation.contextKey'] = 'Cheia de context a resursei de tradus'; -$_lang['babeltranslation.cultureKey'] = 'Key of culture in which translated resource should be determined. Used only in case contextKey was not specified. If both omitted: uses currently set cultureKey.'; -$_lang['babeltranslation.showUnpublished'] = 'Afișează traducerile nepublicate'; \ No newline at end of file + + * + * @package babel + * @subpackage lexicon + */ +$_lang['babel.babellinks.activeCls'] = 'Clasa CSS pentru legătura activă către resursele traduse.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Semnalizează dacă se ignoră statusul site-ului (atunci când site-ul este offline)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Semnalizează dacă se afișează sau nu contextul fără legătură.'; +$_lang['babel.babellinks.resourceId'] = 'Id-ul resursei de afișat.'; +$_lang['babel.babellinks.restrictToGroup'] = 'Restrânge contextele din extrasul de fragment la grupul contextului curent.'; +$_lang['babel.babellinks.showCurrent'] = 'Afișează o legătură către limba curentă.'; +$_lang['babel.babellinks.showUnpublished'] = 'Afișează traducerile nepublicate.'; +$_lang['babel.babellinks.toArray'] = 'Semnalizează dacă se dorește să se arunce ieșirea sub formă de matrice.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Semnalizează dacă trebuie să se arunce ieșirea în numele de placeholder dat.'; +$_lang['babel.babellinks.tpl'] = 'Elementul chunk ce afișează legăturile către resursele traduse.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Bucată pentru a înfășura toate legăturile de limbă. Locul pentru toate legăturile este [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Cheia de context a resursei de tradus.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Cheia de cultură în care ar trebui să fie determinată resursa tradusă. Se utilizează numai în cazul în care nu s-a specificat contextKey. În cazul în care ambele sunt omise, se utilizează cultureKey setată în prezent.'; +$_lang['babel.babeltranslation.resourceId'] = 'IDul resursei de tradus.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Afișează traducerile nepublicate.'; diff --git a/core/components/babel/lexicon/ru/cmp.inc.php b/core/components/babel/lexicon/ru/cmp.inc.php deleted file mode 100644 index 806c5ab..0000000 --- a/core/components/babel/lexicon/ru/cmp.inc.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Russian language file - * - * @author Jakob Class - * goldsky - * - * @package babel - * @subpackage lexicon - * - */ - -$_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Управление мультиязычной системой'; -$_lang['babel.search...'] = 'Поиск...'; -$_lang['babel.filter'] = 'Фильтр'; -$_lang['babel.reset'] = 'Сбросить'; -$_lang['babel.icon_descriptions'] = ' Связь ресурса и связанных с ним ресурсов
' - . ' Отвязать все связи
' - . ' Редактировать связанный ресурс
' - . ' Создать новый связанный ресурс
'; diff --git a/core/components/babel/lexicon/ru/default.inc.php b/core/components/babel/lexicon/ru/default.inc.php index 8d6f108..ca18c4d 100644 --- a/core/components/babel/lexicon/ru/default.inc.php +++ b/core/components/babel/lexicon/ru/default.inc.php @@ -1,115 +1,50 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel Russian language file - * - * @author Jakob Class - * goldsky + * Default Lexicon Entries for Babel * * @package babel * @subpackage lexicon - * - * @todo complete babel.language_xx entries for every language */ - $_lang['babel'] = 'Babel'; -$_lang['babel.desc'] = 'Управление мультиязычной системой'; -$_lang['babel.tv_caption'] = 'Babel Translation Links'; -$_lang['babel.tv_description'] = 'Используется плагином Babel. Не изменяйте!'; +$_lang['babel.about'] = 'О Бабеле'; +$_lang['babel.all'] = 'Все'; +$_lang['babel.context_err_invalid_key'] = 'Контекст «[[+context]]» не найден.'; +$_lang['babel.context_err_ns'] = 'Не указан контекст.'; +$_lang['babel.contexts'] = 'Контексты'; +$_lang['babel.contexts_desc'] = 'Управляйте связями между ресурсами в разных контекстах/языках в одном месте. Используйте следующие кнопки для редактирования ссылок:'; +$_lang['babel.contexts_desc_create'] = 'Создайте новый ресурс, который необходимо связать'; +$_lang['babel.contexts_desc_link'] = 'Ссылка на этот ресурс и связанные с ним ресурсы'; +$_lang['babel.contexts_desc_unlink'] = 'Разрывная связь'; +$_lang['babel.contexts_desc_update'] = 'Обновите этот связанный ресурс'; +$_lang['babel.copy_tv_values'] = 'Копировать значения синхронизируемых TV'; $_lang['babel.create_translation'] = 'Создать перевод'; $_lang['babel.create_translation_confirm'] = 'Вы уверены, что хотите создать перевод в контексте «[[+context]]» для данного ресурса?'; -$_lang['babel.unlink'] = 'Отвязать'; -$_lang['babel.unlink_translation'] = 'Отвязать перевод'; -$_lang['babel.unlink_translation_confirm'] = 'Вы уверены, что хотите отвязать перевод в контексте «[[+context]]» для данного ресурса?'; -$_lang['babel.unlink_all_translations'] = 'Отвязать все переводы'; -$_lang['babel.unlink_all_translations_confirm'] = 'Вы уверены, что хотите отвязать все переводы для данного ресурса?'; -$_lang['babel.link_translation_manually'] = 'или связать перевод вручную:'; +$_lang['babel.debug_mode'] = 'Режим отладки'; +$_lang['babel.desc'] = 'Управление мультиязычной системой'; +$_lang['babel.target_id'] = 'Идентификатор цели'; $_lang['babel.link_translation'] = 'Связать с существующим ресурсом'; -$_lang['babel.id_of_target'] = 'ID целевого ресурса:'; -$_lang['babel....or'] = '... или'; -$_lang['babel.pagetitle_of_target'] = 'Заголовок целевого ресурса:'; -$_lang['babel.copy_tv_values'] = 'Копировать значения синхронизируемых TV'; -$_lang['babel.save'] = 'Сохранить'; -$_lang['babel.translation_pending'] = '[ожидает перевода]'; $_lang['babel.open'] = 'Открыть'; -$_lang['babel.please_wait'] = 'Пожалуйста, подождите...'; +$_lang['babel.or'] = '... или'; +$_lang['babel.target_pagetitle'] = '... или поиск по заголовку целевой страницы'; +$_lang['babel.please_wait'] = 'Пожалуйста, подождите …'; +$_lang['babel.reset'] = 'Сбросить'; +$_lang['babel.resource_err_from_other_context'] = 'Ресурс [[+resource]] не существует в контексте «[[+context]]».'; +$_lang['babel.resource_err_invalid_id'] = 'Ресурс с ID [[+resource]] не найден.'; +$_lang['babel.resource_err_link_of_selflink_not_possible'] = 'Ресурс не может быть связан с самим собой.'; +$_lang['babel.resource_err_unlink_of_selflink_not_possible'] = 'Ресурс не может быть отвязан от самого себя.'; +$_lang['babel.search'] = 'Поиск …'; +$_lang['babel.select_context'] = 'Выберите контекст'; +$_lang['babel.select_tree_node'] = 'Выберите узел в дереве ресурсов'; +$_lang['babel.settings'] = 'Настройки'; +$_lang['babel.settings_desc'] = 'Редактирование настроек Babel. Вы можете изменить значение системного параметра, дважды щелкнув ячейку таблицы "Значение" или щелкнув правой кнопкой мыши в ячейке таблицы.'; $_lang['babel.sync_linked_tranlations'] = 'Синхронизировать все переводы с целевого ресурса'; -$_lang['babel.select_tree_node'] = 'Выберите узел (контекст) в дереве ресурсов'; -$_lang['babel.all'] = 'Все'; - -/* language names */ -$_lang ['babel.language_ar'] = 'Арабский'; -$_lang ['babel.language_bg'] = 'Болгарский'; -$_lang ['babel.language_ca'] = 'Каталонский'; -$_lang ['babel.language_cs'] = 'Чешский'; -$_lang ['babel.language_da'] = 'Датский'; -$_lang ['babel.language_de'] = 'Немецкий'; -$_lang ['babel.language_en'] = 'Английский'; -$_lang ['babel.language_es'] = 'Испанский'; -$_lang ['babel.language_fa'] = 'Персидский'; -$_lang ['babel.language_fi'] = 'Финский'; -$_lang ['babel.language_fr'] = 'Французский'; -$_lang ['babel.language_he'] = 'Иврит'; -$_lang ['babel.language_hu'] = 'Венгерский'; -$_lang ['babel.language_id'] = 'Индонезийский'; -$_lang ['babel.language_it'] = 'Итальянский'; -$_lang ['babel.language_ja'] = 'Японский'; -$_lang ['babel.language_ko'] = 'Корейский'; -$_lang ['babel.language_lt'] = 'Литовский'; -$_lang ['babel.language_ms'] = 'Малайский'; -$_lang ['babel.language_nl'] = 'Голландский'; -$_lang ['babel.language_no'] = 'Норвежский (Bokmål)'; -$_lang ['babel.language_pl'] = 'Польский'; -$_lang ['babel.language_pt'] = 'Португальский'; -$_lang ['babel.language_ro'] = 'Румынский'; -$_lang ['babel.language_ru'] = 'Русский'; -$_lang ['babel.language_sk'] = 'Словацкий'; -$_lang ['babel.language_sl'] = 'Словенский'; -$_lang ['babel.language_sr'] = 'Сербский'; -$_lang ['babel.language_sv'] = 'Шведский'; -$_lang ['babel.language_tr'] = 'Турецкий'; -$_lang ['babel.language_uk'] = 'Украинский'; -$_lang ['babel.language_vi'] = 'Вьетнамский'; -$_lang ['babel.language_zh'] = 'Китайский'; - -/* error messages */ -$_lang['error.invalid_context_key'] = 'Контекст «[[+context]]» не найден.'; -$_lang['error.invalid_resource_id'] = 'Ресурс с ID [[+resource]] не найден.'; -$_lang['error.resource_from_other_context'] = 'Ресурс [[+resource]] не существует в контексте «[[+context]]».'; -$_lang['error.resource_already_linked'] = 'Ресурс [[+resource]] уже связан с другими ресурсами.'; -$_lang['error.no_link_to_context'] = 'В контексте «[[+context]]» нет связанных ресурсов.'; -$_lang['error.link_of_selflink_not_possible'] = 'Ресурс не может быть связан с самим собой.'; -$_lang['error.unlink_of_selflink_not_possible'] = 'Ресурс не может быть отвязан от самого себя.'; -$_lang['error.translation_in_same_context'] = 'Перевод не может быть создан в том же контексте.'; -$_lang['error.translation_already_exists'] = 'Перевод в контексте «[[+context]]» уже есть: «[[+pagetitle]] ([[+resource]])»'; -$_lang['error.could_not_create_translation'] = 'Произошла ошибка при попытке создать перевод в контексте «[[+context]]».'; - -$_lang['babel.context_err_ns'] = 'Не указан контекст.'; - -$_lang['setting_babel.contextKeys'] = 'Ключи контекста'; -$_lang['setting_babel.contextKeys_desc'] = 'Список ключей, разделенных запятыми, которые должны использоваться для связи мультиязычных ресурсов.'; -$_lang['setting_babel.babelTvName'] = 'Название Babel TV'; -$_lang['setting_babel.babelTvName_desc'] = 'Название TV, в которой Babel будет хранить ссылки между мультиязычными ресурсами, TV будет использоваться Babel.'; -$_lang['setting_babel.syncTvs'] = 'TV для синхронизации'; -$_lang['setting_babel.syncTvs_desc'] = 'Список TV, разделенных запятыми, которые необходимо синхронизировать Babel.'; +$_lang['babel.systemsetting_key_err_nv'] = 'Вы можете редактировать настройки только с префиксом babel.'; +$_lang['babel.systemsetting_usergroup_err_nv'] = 'Изменять настройки могут только пользователи с правами settings или settings_babel.'; +$_lang['babel.translation_err_could_not_create_resource'] = 'Произошла ошибка при попытке создать перевод в контексте «[[+context]]».'; +$_lang['babel.translation_pending'] = '[ожидает перевода]'; +$_lang['babel.tv_caption'] = 'Ссылки на перевод Babel'; +$_lang['babel.tv_description'] = 'Используется плагином Babel. Не изменяйте!'; +$_lang['babel.unlink'] = 'Отвязать'; +$_lang['babel.unlink_all_translations'] = 'Отвязать все переводы'; +$_lang['babel.unlink_all_translations_confirm'] = 'Вы уверены, что хотите отвязать все переводы для данного ресурса?'; +$_lang['babel.unlink_translation_confirm'] = 'Вы уверены, что хотите отвязать перевод в контексте «[[+context]]» для данного ресурса?'; diff --git a/core/components/babel/lexicon/ru/languages.inc.php b/core/components/babel/lexicon/ru/languages.inc.php new file mode 100644 index 0000000..b817a67 --- /dev/null +++ b/core/components/babel/lexicon/ru/languages.inc.php @@ -0,0 +1,40 @@ + - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ -/** - * Babel properties Russian language file - * - * @author Jakob Class + * Properties Lexicon Entries for Babel * * @package babel * @subpackage lexicon */ - -/* BabelLinks snippet */ -$_lang['babellinks.tpl'] = 'Чанк-шаблон ссылки на перевод'; -$_lang['babellinks.activeCls'] = 'CSS-класс активной ссылки на перевод'; -$_lang['babellinks.resourceId'] = 'ID ресурсов, ссылки на перевод которых должны отображаться'; -$_lang['babellinks.showUnpublished'] = 'Показывать неопубликованные ресурсы'; -$_lang['babellinks.showCurrent'] = 'Показывать ссылку на перевод текущего языка'; -$_lang['babellinks.includeUnlinked'] = 'Показывать несвязанный контекст'; - -/* BabelTranslation snippet */ -$_lang['babeltranslation.resourceId'] = 'ID ресурса, для которого нужно получить ресурс с переводом'; -$_lang['babeltranslation.contextKey'] = 'Ключ контекста, для которого нужно получить ресурс с переводом'; -$_lang['babeltranslation.showUnpublished'] = 'Показывать неопубликованные ресурсы с переводом'; +$_lang['babel.babellinks.activeCls'] = 'CSS-класс активной ссылки на перевод.'; +$_lang['babel.babellinks.ignoreSiteStatus'] = 'Флаг, игнорировать ли site_status (когда сайт не в сети)'; +$_lang['babel.babellinks.includeUnlinked'] = 'Флаг, показывать ли несвязанный контекст.'; +$_lang['babel.babellinks.resourceId'] = 'ID ресурсов, ссылки на перевод которых должны отображаться.'; +$_lang['babel.babellinks.restrictToGroup'] = 'Ограничьте контексты в выводе сниппета группой текущего контекста'; +$_lang['babel.babellinks.showCurrent'] = 'Показывать ссылку на перевод текущего языка.'; +$_lang['babel.babellinks.showUnpublished'] = 'Показывать неопубликованные ресурсы.'; +$_lang['babel.babellinks.toArray'] = 'Флаг, следует ли выводить вывод в виде массива.'; +$_lang['babel.babellinks.toPlaceholder'] = 'Флаг, сбрасывать ли вывод в имя заданного плейсхолдера.'; +$_lang['babel.babellinks.tpl'] = 'Чанк для отображения языковой ссылки.'; +$_lang['babel.babellinks.wrapperTpl'] = 'Чанк для обертывания всех языковых ссылок. Заполнителем для всех ссылок является [[+babelLinks]].'; +$_lang['babel.babeltranslation.contextKey'] = 'Ключ контекста, в котором должен быть определен переведенный ресурс.'; +$_lang['babel.babeltranslation.cultureKey'] = 'Ключ культуры, в которой должен быть определен переведенный ресурс. Используется только в том случае, если contextKey не был указан. Если оба значения опущены, то в сниппете используется текущий ключ cultureKey.'; +$_lang['babel.babeltranslation.resourceId'] = 'Идентификатор ресурса, для которого должен быть определен переведенный ресурс.'; +$_lang['babel.babeltranslation.showUnpublished'] = 'Флаг, показывать ли неопубликованные переводы.'; diff --git a/core/components/babel/model/babel/babel.class.php b/core/components/babel/model/babel/babel.class.php index fab63b9..76a8cea 100644 --- a/core/components/babel/model/babel/babel.class.php +++ b/core/components/babel/model/babel/babel.class.php @@ -1,9 +1,8 @@ + * Copyright 2010-2024 by Jakob Class * * This file is part of Babel. * @@ -21,618 +20,14 @@ * Suite 330, Boston, MA 02111-1307 USA * * @package babel + * @subpackage classfile */ +require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; + /** - * This file is the main class file for Babel. - * - * Based on ideas of Sylvain Aerni - * - * @author Jakob Class - * goldsky - * - * @package babel + * Class Babel */ -class Babel +class Babel extends \mikrobi\Babel\Babel { - - const VERSION = '3.1.0'; - const RELEASE = 'pl'; - - /** - * @access protected - * @var array A collection of preprocessed chunk values. - */ - protected $chunks = []; - - /** - * @access public - * @var modX A reference to the modX object. - */ - public $modx = null; - - /** - * @access public - * @var array A collection of properties to adjust Babel behaviour. - */ - public $config = []; - - /** - * @access public - * @var modTemplateVar A reference to the babel TV which is used to store linked resources. - * The linked resources are stored using this syntax: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] - * Example: web:1;de:4;es:7;fr:10 - */ - public $babelTv = null; - protected $contextKeyToGroup; - - /** - * The Babel Constructor. - * - * This method is used to create a new Babel object. - * - * @param modX &$modx A reference to the modX object. - * @param array $config A collection of properties that modify Babel - * behaviour. - * @return Babel A unique Babel instance. - */ - function __construct(modX &$modx, array $config = []) - { - $this->modx = & $modx; - - $corePath = $this->modx->getOption('babel.core_path', null, $modx->getOption('core_path').'components/babel/'); - $assetsUrl = $this->modx->getOption('babel.assets_url', null, $modx->getOption('assets_url').'components/babel/'); - - $contextKeysOption = $this->modx->getOption('babel.contextKeys', $config, ''); - $this->contextKeyToGroup = $this->decodeContextKeySetting($contextKeysOption); - $syncTvsOption = $this->modx->getOption('babel.syncTvs', $config, ''); - $syncTvs = []; - if (!empty($syncTvsOption)) { - $syncTvs = explode(',', $syncTvsOption); - $syncTvs = array_map('intval', $syncTvs); - } - $babelTvName = $this->modx->getOption('babel.babelTvName', $config, 'babelLanguageLinks'); - - $this->config = array_merge([ - 'version' => self::VERSION.'-'.self::RELEASE, - 'basePath' => $corePath, - 'corePath' => $corePath, - 'modelPath' => $corePath.'model/', - 'processorsPath' => $corePath.'processors/', - 'chunksPath' => $corePath.'elements/chunks/', - 'chunkSuffix' => '.chunk.tpl', - 'templatesPath' => $corePath.'templates/', - 'cssUrl' => $assetsUrl.'css/', - 'jsUrl' => $assetsUrl.'js/', - 'syncTvs' => $syncTvs, - 'babelTvName' => $babelTvName, - 'connectorUrl' => $assetsUrl.'conn/mgr.php', - ], $config); - - /* load babel lexicon */ - if (!$this->modx->lexicon) { - $this->modx->getService('lexicon', 'modLexicon'); - } - $this->modx->lexicon->load('babel:default'); - - /* load babel TV */ - $this->babelTv = $modx->getObject('modTemplateVar', ['name' => $babelTvName]); - if (!$this->babelTv) { - $this->modx->log(modX::LOG_LEVEL_WARN, 'Could not load babel TV: '.$babelTvName.' will try to create it...'); - $fields = [ - 'name' => $babelTvName, - 'type' => 'hidden', - 'default_text' => '', - 'caption' => $this->modx->lexicon('babel.tv_caption'), - 'description' => $this->modx->lexicon('babel.tv_description') - ]; - $this->babelTv = $modx->newObject('modTemplateVar', $fields); - if ($this->babelTv->save()) { - $this->modx->log(modX::LOG_LEVEL_INFO, 'Created babel TV: '.$babelTvName); - } else { - $this->modx->log(modX::LOG_LEVEL_ERROR, 'Could not create babel TV: '.$babelTvName); - } - } - } - - /** - * Synchronizes the TVs of the specified resource with its translated resources. - * - * @param int $resourceId id of resource. - */ - public function synchronizeTvs($resourceId) - { - $linkedResources = $this->getLinkedResources($resourceId); - /* check if Babel TV has been initiated for the specified resource */ - if (empty($linkedResources)) { - $linkedResources = $this->initBabelTvById($resourceId); - } - - /* synchronize the TVs of linked resources */ - $syncTvs = $this->config['syncTvs']; - if (empty($syncTvs) || !is_array($syncTvs)) { - /* there are no TVs to synchronize */ - return; - } - - foreach ($syncTvs as $tvId) { - /* go through each TV which should be synchronized */ - $tv = $this->modx->getObject('modTemplateVar', $tvId); - if (!$tv) { - continue; - } - $tvValue = $tv->getValue($resourceId); - foreach ($linkedResources as $linkedResourceId) { - /* go through each linked resource */ - if ($resourceId == $linkedResourceId) { - /* don't synchronize resource with itself */ - continue; - } - $tv->setValue($linkedResourceId, $tvValue); - } - $tv->save(); - } - - $this->modx->cacheManager->refresh(); - } - - /** - * Returns an array with the context keys of the specified context's group. - * - * @param string $contextKey key of context. - */ - public function getGroupContextKeys($contextKey) - { - $contextKeys = []; - if (isset($this->contextKeyToGroup[$contextKey]) && is_array($this->contextKeyToGroup[$contextKey])) { - $contextKeys = $this->contextKeyToGroup[$contextKey]; - } - return $contextKeys; - } - - /** - * Creates a duplicate of the specified resource in the specified context. - * - * @param modResource $resource - * @param string $contextKey - */ - public function duplicateResource(&$resource, $contextKey) - { - /* determine parent id of new resource */ - $newParentId = null; - $parentId = $resource->get('parent'); - if ($parentId != null) { - $linkedParentResources = $this->getLinkedResources($parentId); - if (isset($linkedParentResources[$contextKey])) { - $newParentId = $linkedParentResources[$contextKey]; - } - } - /* create new resource */ - $newResource = $this->modx->newObject($resource->get('class_key')); - $newResource->fromArray($resource->toArray('', true), '', false, true); - $newResource->set('id', 0); - $newResource->set('pagetitle', $resource->get('pagetitle').' '.$this->modx->lexicon('babel.translation_pending')); - $newResource->set('parent', intval($newParentId)); - $newResource->set('createdby', $this->modx->user->get('id')); - $newResource->set('createdon', time()); - $newResource->set('editedby', 0); - $newResource->set('editedon', 0); - $newResource->set('deleted', false); - $newResource->set('deletedon', 0); - $newResource->set('deletedby', 0); - $newResource->set('published', false); - $newResource->set('publishedon', 0); - $newResource->set('publishedby', 0); - $newResource->set('context_key', $contextKey); - if ($newResource->save()) { - /* copy all TV values */ - $templateVarResources = $resource->getMany('TemplateVarResources'); - foreach ($templateVarResources as $oldTemplateVarResource) { - $newTemplateVarResource = $this->modx->newObject('modTemplateVarResource'); - $newTemplateVarResource->set('contentid', $newResource->get('id')); - $newTemplateVarResource->set('tmplvarid', $oldTemplateVarResource->get('tmplvarid')); - $newTemplateVarResource->set('value', $oldTemplateVarResource->get('value')); - $newTemplateVarResource->save(); - } - - /* set parent of duplicate as a folder */ - if ($newParentId) { - $newParent = $this->modx->getObject('modResource', $newParentId); - if ($newParent) { - $newParent->set('isfolder', 1); - $newParent->save(); - } - } - - /* invoke OnDocFormSave event */ - $this->modx->invokeEvent('OnDocFormSave', [ - 'mode' => modSystemEvent::MODE_NEW, - 'id' => $newResource->get('id'), - 'resource' => &$newResource - ]); - } else { - $this->modx->log(modX::LOG_LEVEL_ERROR, 'Could not duplicate resource: '.$resource->get('id').' in context: '.$contextKey); - $newResource = null; - } - return $newResource; - } - - /** - * Creates an associative array which maps context keys to there - * context groups out of an $contextKeyString - * - * @param string $contextKeyString example: ctx1,ctx2;ctx3,ctx4,ctx5;ctx5,ctx6 - * - * @return array associative array which maps context keys to there - * context groups. - */ - public function decodeContextKeySetting($contextKeyString) - { - $contextKeyToGroup = []; - if (!empty($contextKeyString)) { - $contextGroups = explode(';', $contextKeyString); - $contextGroups = array_map('trim', $contextGroups); - foreach ($contextGroups as $contextGroup) { - $groupContextKeys = explode(',', $contextGroup); - $groupContextKeys = array_map('trim', $groupContextKeys); - foreach ($groupContextKeys as $contextKey) { - if (!empty($contextKey)) { - $contextKeyToGroup[$contextKey] = $groupContextKeys; - } - } - } - } - return $contextKeyToGroup; - } - - /** - * Init/reset the Babel TV of the specified resource. - * - * @param modResource $resource resource object. - * - * @return array associative array with linked resources (array contains only the resource itself). - */ - public function initBabelTv($resource) - { - $linkedResources = [$resource->get('context_key') => $resource->get('id')]; - $this->updateBabelTv($resource->get('id'), $linkedResources, false); - return $linkedResources; - } - - /** - * Run \Babel\initBabelTv recursively - * - * @author https://github.com/manu37 - * - * @param object $modx - * @param object $babel - * @param int $id - * @param int $depth - * - * @return void - */ - public function initBabelTvsRecursive(&$modx, &$babel, $id = null, $depth = 100) - { - if ($id && $depth > 0) { - $q = $modx->newQuery('modResource'); - $q->select(['id']); - $q->where(['parent' => $id]); - $children = $modx->getCollection('modResource', $q); - foreach ($children as $child) { - $processDepth = $depth - 1; - $this->initBabelTvsRecursive($modx, $babel, $child->get('id'), $processDepth); - } - $this->initBabelTvById($id); - } - } - - /** - * Init/reset the Babel TV of a resource specified by the id of the resource. - * - * @param int $resourceId id of resource (int). - */ - public function initBabelTvById($resourceId) - { - $resource = $this->modx->getObject('modResource', $resourceId); - return $this->initBabelTv($resource); - } - - /** - * Updates the Babel TV of the specified resource(s). - * - * @param mixed $resourceIds id of resource or array of resource ids which should be updated. - * @param array $linkedResources associative array with linked resources: [contextKey] = resourceId - * @param boolean $clearCache flag to empty cache after update. - */ - public function updateBabelTv($resourceIds, $linkedResources, $clearCache = true) - { - if (!is_array($resourceIds)) { - $resourceIds = [intval($resourceIds)]; - } - $newValue = $this->encodeTranslationLinks($linkedResources); - foreach ($resourceIds as $resourceId) { - $this->babelTv->setValue($resourceId, $newValue); - } - $this->babelTv->save(); - if ($clearCache) { - $this->modx->cacheManager->refresh(); - } - return; - } - - /** - * Returns an associative array of the linked resources of the specified resource. - * - * @param int $resourceId id of resource. - * - * @return array associative array with linked resources: [contextKey] = resourceId. - */ - public function getLinkedResources($resourceId) - { - return $this->decodeTranslationLinks($this->babelTv->getValue($resourceId)); - } - - /** - * Creates an associative array of linked resources out of string. - * - * @param string $linkedResourcesString string which contains the translation links: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] - * - * @return array associative array with linked resources: [contextKey] = resourceId. - */ - public function decodeTranslationLinks($linkedResourcesString) - { - $linkedResources = []; - if (!empty($linkedResourcesString)) { - $contextResourcePairs = explode(';', $linkedResourcesString); - foreach ($contextResourcePairs as $contextResourcePair) { - $contextResourcePair = explode(':', $contextResourcePair); - $contextKey = $contextResourcePair[0]; - $resourceId = intval($contextResourcePair[1]); - $linkedResources[$contextKey] = $resourceId; - } - } - return $linkedResources; - } - - /** - * Creates an string which contains the translation links out of an associative array. - * - * @param array $linkedResources associative array with linked resources: [contextKey] = resourceId - * - * return string which contains the translation links: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] - */ - public function encodeTranslationLinks($linkedResources) - { - if (!is_array($linkedResources)) { - return; - } - $contextResourcePairs = []; - foreach ($linkedResources as $contextKey => $resourceId) { - $contextResourcePairs[] = $contextKey.':'.intval($resourceId); - } - return implode(';', $contextResourcePairs); - } - - /** - * Removes all translation links to the specified resource. - * - * @param int $resourceId id of resource. - */ - public function removeLanguageLinksToResource($resourceId) - { - /* search for resource which contain a ':$resourceId' in their Babel TV */ - $templateVarResources = $this->modx->getCollection('modTemplateVarResource', [ - 'value:LIKE' => '%:'.$resourceId.'%' - ]); - if (!is_array($templateVarResources)) { - return; - } - foreach ($templateVarResources as $templateVarResource) { - /* go through each resource and remove the link of the specified resource */ - $oldValue = $templateVarResource->get('value'); - $linkedResources = $this->decodeTranslationLinks($oldValue); - /* array maps context keys to resource ids - * -> search for the context key of the specified resource id */ - $contextKey = array_search($resourceId, $linkedResources); - /* sanity check, is the contextKey really a context in babel's settings? */ - if (array_key_exists($contextKey, $this->contextKeyToGroup)) { - unset($linkedResources[$contextKey]); - $newValue = $this->encodeTranslationLinks($linkedResources); - $templateVarResource->set('value', $newValue); - $templateVarResource->save(); - } - } - } - - /** - * Removes all translation links to the specified context. - * - * @param int $contextKey key of context. - */ - public function removeLanguageLinksToContext($contextKey) - { - /* search for resource which contain a '$contextKey:' in their Babel TV */ - $templateVarResources = $this->modx->getCollection('modTemplateVarResource', [ - 'value:LIKE' => '%'.$contextKey.':%' - ]); - if (!is_array($templateVarResources)) { - return; - } - foreach ($templateVarResources as $templateVarResource) { - /* go through each resource and remove the link of the specified context */ - $oldValue = $templateVarResource->get('value'); - $linkedResources = $this->decodeTranslationLinks($oldValue); - /* array maps context keys to resource ids */ - unset($linkedResources[$contextKey]); - $newValue = $this->encodeTranslationLinks($linkedResources); - $templateVarResource->set('value', $newValue); - $templateVarResource->save(); - } - /* finaly clean the babel.contextKeys setting */ - $setting = $this->modx->getObject('modSystemSetting', [ - 'key' => 'babel.contextKeys' - ]); - if ($setting) { - /* remove all spaces */ - $newValue = str_replace(' ', '', $setting->get('value')); - /* replace context key with leading comma */ - $newValue = str_replace(','.$contextKey, '', $newValue); - /* replace context key without leading comma (if still present) */ - $newValue = str_replace($contextKey, '', $newValue); - $setting->set('value', $newValue); - if ($setting->save()) { - $this->modx->reloadConfig(); - $this->modx->cacheManager->deleteTree($this->modx->getOption('core_path', null, MODX_CORE_PATH).'cache/mgr/smarty/', [ - 'deleteTop' => false, - 'skipDirs' => false, - 'extensions' => ['.cache.php', '.php'], - ]); - } - } - } - - /** - * Gets the contextKey by cultureKey - * - * @param string $cultureKey the culture key - * @return string context key - */ - public function getContextKey($cultureKey) - { - /* Search for Context Setting */ - $ctxSetting = $this->modx->getObject("modContextSetting", [ - "key" => "cultureKey", - "value" => $cultureKey - ]); - return (($ctxSetting) ? $ctxSetting->get("context_key") : false); - } - - /** - * Gets a Chunk and caches it; also falls back to file-based templates - * for easier debugging. - * - * @access public - * @param string $name The name of the Chunk - * @param array $properties The properties for the Chunk - * @return string The processed content of the Chunk - */ - public function getChunk($name, array $properties = []) - { - $chunk = null; - if (!isset($this->chunks[$name])) { - $chunk = $this->modx->getObject('modChunk', ['name' => $name], true); - if (empty($chunk)) { - $chunk = $this->_getTplChunk($name, $this->config['chunkSuffix']); - if ($chunk == false) - return false; - } - $this->chunks[$name] = $chunk->getContent(); - } else { - $o = $this->chunks[$name]; - $chunk = $this->modx->newObject('modChunk'); - $chunk->setContent($o); - } - $chunk->setCacheable(false); - return $chunk->process($properties); - } - - /** - * Returns a modChunk object from a template file. - * - * @access private - * @param string $name The name of the Chunk. Will parse to name.chunk.tpl by default. - * @param string $suffix The suffix to add to the chunk filename. - * @return modChunk/boolean Returns the modChunk object if found, otherwise - * false. - */ - private function _getTplChunk($name, $suffix = '.chunk.tpl') - { - $chunk = false; - $f = $this->config['chunksPath'].strtolower($name).$suffix; - if (file_exists($f)) { - $o = file_get_contents($f); - $chunk = $this->modx->newObject('modChunk'); - $chunk->set('name', $name); - $chunk->setContent($o); - } - return $chunk; - } - - /** - * Get placeholders to create language selection menu. - * Used in plugin and processors. - * - * @param object $resource - * @return array menu - */ - public function getMenu($resource) - { - $menu = []; - $contextKeys = $this->getGroupContextKeys($resource->get('context_key')); - $linkedResources = $this->getLinkedResources($resource->get('id')); - if (empty($linkedResources)) { - /* always be sure that the Babel TV is set */ - $this->initBabelTv($resource); - } - - $languages = $this->getLanguages(); - foreach ($contextKeys as $contextKey) { - /* for each (valid/existing) context of the context group a button will be displayed */ - $context = $this->modx->getObject('modContext', ['key' => $contextKey]); - if (!$context) { - $this->modx->log(modX::LOG_LEVEL_ERROR, 'Could not load context: '.$contextKey); - continue; - } - $context->prepare(); - $cultureKey = $context->getOption('cultureKey', $this->modx->getOption('cultureKey')); - $linkResource = null; - if (isset($linkedResources[$contextKey])) { - $resourceId = $linkedResources[$contextKey]; - $linkResource = $this->modx->getObject('modResource', $resourceId); - } - if ($linkResource) { - $resourceUrl = '?a=resource/update&id='.$resourceId; - $resourceTitle = $linkResource->get('pagetitle'); - } else { - $resourceId = ''; - $resourceUrl = '#'; - $resourceTitle = ''; - } - $placeholders = [ - 'resourceId' => $resourceId, - 'resourceUrl' => $resourceUrl, - 'resourceTitle' => $resourceTitle, - 'displayText' => $languages[$cultureKey]['Description'].' ('.(!empty($cultureKey) ? $cultureKey : $contextKey).')', - ]; - $menu[$contextKey] = $placeholders; - } - - return $menu; - } - - /** - * Get all languages in array - * - * @return array Languages' info - */ - public function getLanguages() { - $cacheOptions = [ - xPDO::OPT_CACHE_KEY => 'babel', - xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), - xPDO::OPT_CACHE_FORMAT => (integer) $this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), - ]; - $languages = $this->modx->cacheManager->get('languages', $cacheOptions); - if (!$languages) { - include_once $this->config['corePath'].'vendor/iana-language-subtag-registry/language-subtag-registry.php'; - $ianaLstr = new LanguageSubtagRegistry(); - $ianaLstr->readSource($this->config['corePath'].'vendor/iana-language-subtag-registry/language-subtag-registry'); - $languages = $ianaLstr->languagesAssocArray('Subtag'); - $this->modx->cacheManager->set('languages', $languages, 0, $cacheOptions); - } - foreach ($languages as $k => $v) { - $languages[$k]['Description'] = $v['Description'][0]; - } - - return $languages; - } } diff --git a/core/components/babel/processors/mgr/context/getlist.class.php b/core/components/babel/processors/mgr/context/getlist.class.php index 4c8b162..e23a859 100644 --- a/core/components/babel/processors/mgr/context/getlist.class.php +++ b/core/components/babel/processors/mgr/context/getlist.class.php @@ -1,61 +1,72 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ /** - * Processor file for Babel. - * - * @author goldsky + * Get list contexts * * @package babel + * @subpackage processors */ -if (!class_exists('\MODX\Revolution\modX')) { - include_once MODX_CORE_PATH.'model/modx/processors/context/getlist.class.php'; -} else { - class_alias(\MODX\Revolution\Processors\Context\GetList::class, \modContextGetListProcessor::class); -} -class BabelContextGetListProcessor extends modContextGetListProcessor +use mikrobi\Babel\Processors\ObjectGetListProcessor; + +class BabelContextGetListProcessor extends ObjectGetListProcessor { + public $classKey = 'modContext'; + public $defaultSortField = 'key'; + public $objectType = 'babel.context'; + public $languageTopics = ['context', 'babel:default']; + public $permission = 'view_context'; + + protected $search = ['key', 'name']; + /** + * {@inheritDoc} + * @return boolean + */ public function initialize() { - $initialized = parent::initialize(); + $success = parent::initialize(); + $this->setDefaultProperties([ - 'search' => '', + 'search' => '', 'exclude' => 'mgr', - ]); - $this->canEdit = false; - $this->canRemove = false; - return $initialized; + ]); + + return $success; } + /** + * {@inheritDoc} + * @param xPDOQuery $c + * @return xPDOQuery + */ + public function prepareQueryBeforeCount(xPDOQuery $c) + { + $c = parent::prepareQueryBeforeCount($c); + + $exclude = $this->getProperty('exclude') ? array_map('trim', explode(',', $this->getProperty('exclude'))) : []; + if ($exclude) { + $c->where([ + 'key:NOT IN' => $exclude + ]); + } + $c->where([ + 'key:IN' => $this->babel->getOption('contexts') + ]); + + return $c; + } + + /** + * {@inheritDoc} + * @param array $list + * @return array + */ public function beforeIteration(array $list) { - if ($this->getProperty('combo', false)) { - $empty = [ - 'key' => '', - 'name' => ' ', + if (!$this->getProperty('id') && $this->getBooleanProperty('combo', false)) { + $empty = [ + 'key' => '', + 'name' => $this->modx->lexicon('babel.all'), ]; $list[] = $empty; } @@ -63,19 +74,23 @@ public function beforeIteration(array $list) return $list; } + /** + * {@inheritDoc} + * @param xPDOObject $object + * @return array + */ public function prepareRow(xPDOObject $object) { $objectArray = parent::prepareRow($object); - if ($this->getProperty('combo', false)) { + if ($this->getBooleanProperty('combo', false)) { $objectArray = [ - 'key' => $objectArray['key'], + 'key' => $objectArray['key'], 'name' => $objectArray['name'], ]; } return $objectArray; } - } return 'BabelContextGetListProcessor'; diff --git a/core/components/babel/processors/mgr/resource/duplicate.class.php b/core/components/babel/processors/mgr/resource/duplicate.class.php index 2776501..57271b9 100644 --- a/core/components/babel/processors/mgr/resource/duplicate.class.php +++ b/core/components/babel/processors/mgr/resource/duplicate.class.php @@ -1,102 +1,62 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA + * Duplicate resource * * @package babel + * @subpackage processors */ -/** - * Processor file for Babel. - * - * @author goldsky - * - * @package babel - */ +use mikrobi\Babel\Processors\ObjectUpdateProcessor; -class BabelDuplicateResourceProcessor extends modObjectProcessor +class BabelDuplicateResourceProcessor extends ObjectUpdateProcessor { - /** @var Babel $babel */ - public $babel; - - public $classKey = 'modResource'; + public $classKey = 'modResource'; + public $objectType = 'resource'; public $languageTopics = ['resource', 'babel:default']; - public $objectType = 'resource'; + public $permission = 'resource_duplicate'; - /** @var modAccessibleObject|xPDOObject|modResource $object The object */ - public $object; /** @var xPDOObject $newObject The newly duplicated object */ - public $newObject; - - function __construct(modX & $modx,array $properties = array()) - { - parent::__construct($modx, $properties); - - $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); - $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); - } - - public function checkPermissions() - { - return $this->modx->hasPermission('resource_duplicate'); - } + protected $newObject; + /** + * {@inheritDoc} + * @return boolean + */ public function initialize() { - $primaryKey = $this->getProperty($this->primaryKeyField, false); - if (empty($primaryKey)) { - return $this->modx->lexicon($this->objectType.'_err_ns'); - } - - $this->object = $this->modx->getObject($this->classKey, $primaryKey); - if (empty($this->object)) { - return $this->modx->lexicon($this->objectType.'_err_nfs', [$this->primaryKeyField => $primaryKey]); - } - - if ($this->object instanceof modAccessibleObject && !$this->object->checkPolicy('save')) { - return $this->modx->lexicon('access_denied'); - } + $success = parent::initialize(); $contextKey = $this->getProperty('context_key', false); if (empty($contextKey)) { return $this->modx->lexicon('babel.context_err_ns'); } - - $context = $this->modx->getObject('modContext', ['key' => $contextKey]); + $context = $this->modx->getObject('modContext', [ + 'key' => $contextKey + ]); if (!$context) { - return $this->modx->lexicon('error.invalid_context_key', ['context' => $contextKey]); + return $this->modx->lexicon('babel.context_err_invalid_key', [ + 'context' => $contextKey + ]); } - return true; + return $success; } + /** + * {@inheritDoc} + * @return mixed + */ public function process() { - $contextKey = $this->getProperty('context_key'); + $contextKey = $this->getProperty('context_key'); $this->newObject = $this->babel->duplicateResource($this->object, $contextKey); if (!$this->newObject) { - /* error: translation could not be created */ - return $this->failure($this->modx->lexicon('error.could_not_create_translation', ['context' => $contextKey])); + return $this->failure($this->modx->lexicon('babel.translation_err_could_not_create_resource', [ + 'context' => $contextKey + ])); } - $linkedResources = $this->babel->getLinkedResources($this->object->get('id')); + $linkedResources = $this->babel->getLinkedResources($this->object->get('id')); $linkedResources[$contextKey] = $this->newObject->get('id'); $this->babel->updateBabelTv($linkedResources, $linkedResources); @@ -107,38 +67,34 @@ public function process() /** * Fire the OnBabelDuplicate event - * @return void */ public function fireDuplicateEvent() { $this->modx->invokeEvent('OnBabelDuplicate', [ - 'context_key' => $this->getProperty('context_key'), - 'original_id' => $this->object->get('id'), - 'original_resource' => &$this->object, - 'duplicate_id' => $this->newObject->get('id'), + 'context_key' => $this->getProperty('context_key'), + 'original_id' => $this->object->get('id'), + 'original_resource' => &$this->object, + 'duplicate_id' => $this->newObject->get('id'), 'duplicate_resource' => &$this->newObject, ]); } /** * Log a manager action - * @return void */ public function logManagerAction() { - $this->modx->logManagerAction($this->objectType.'_duplicate', $this->classKey, $this->newObject->get('id')); + $this->modx->logManagerAction($this->objectType . '_duplicate', $this->classKey, $this->newObject->get('id')); } /** - * Cleanup and return a response. - * + * {@inheritDoc} * @return array */ public function cleanup() { return $this->success('', $this->newObject); } - } return 'BabelDuplicateResourceProcessor'; diff --git a/core/components/babel/processors/mgr/resource/getlist.class.php b/core/components/babel/processors/mgr/resource/getlist.class.php index 81a3e50..4aec29f 100644 --- a/core/components/babel/processors/mgr/resource/getlist.class.php +++ b/core/components/babel/processors/mgr/resource/getlist.class.php @@ -1,68 +1,56 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ - /** - * Processor file for Babel. - * - * @author goldsky + * Get list resources * * @package babel + * @subpackage processors */ -if (!class_exists('\MODX\Revolution\modX')) { - include_once MODX_CORE_PATH.'model/modx/processors/resource/getlist.class.php'; -} else { - class_alias(\MODX\Revolution\Processors\Resource\GetList::class, \modResourceGetListProcessor::class); -} +use mikrobi\Babel\Processors\ObjectGetListProcessor; -class BabelResourceGetListProcessor extends modResourceGetListProcessor +class BabelResourceGetListProcessor extends ObjectGetListProcessor { + public $classKey = 'modResource'; + public $defaultSortField = 'pagetitle'; + public $objectType = 'babel.resource'; + public $languageTopics = ['resource', 'babel:default']; + public $permission = 'view'; + + protected $search = ['pagetitle']; + + /** + * {@inheritDoc} + * @param xPDOQuery $c + * @return xPDOQuery + */ public function prepareQueryBeforeCount(xPDOQuery $c) { $c = parent::prepareQueryBeforeCount($c); - $query = $this->getProperty('query'); - if (!empty($query)) { - $c->where([ - 'pagetitle:LIKE' => '%' . $query . '%' - ]); - } $ctx = $this->getProperty('context'); - if (!empty($ctx)) { + if ($ctx) { $c->where([ 'context_key:=' => $ctx ]); + } else { + $c->where([ + 'context_key:IN' => $this->babel->getOption('contexts') + ]); } + return $c; } + /** + * {@inheritDoc} + * @param array $list + * @return array + */ public function beforeIteration(array $list) { - if ($this->getProperty('combo', false)) { - $empty = [ - 'id' => 0, + if (!$this->getProperty('id') && $this->getBooleanProperty('combo', false)) { + $empty = [ + 'id' => 0, 'pagetitle' => '', ]; $list[] = $empty; @@ -71,19 +59,23 @@ public function beforeIteration(array $list) return $list; } + /** + * {@inheritDoc} + * @param xPDOObject $object + * @return array + */ public function prepareRow(xPDOObject $object) { $objectArray = parent::prepareRow($object); - if ($this->getProperty('combo', false)) { + if ($this->getBooleanProperty('combo', false)) { $objectArray = [ - 'id' => $objectArray['id'], + 'id' => $objectArray['id'], 'pagetitle' => $objectArray['pagetitle'], ]; } return $objectArray; } - } return 'BabelResourceGetListProcessor'; diff --git a/core/components/babel/processors/mgr/resource/getmatrixlist.class.php b/core/components/babel/processors/mgr/resource/getmatrixlist.class.php index b80fe0d..b93ca83 100644 --- a/core/components/babel/processors/mgr/resource/getmatrixlist.class.php +++ b/core/components/babel/processors/mgr/resource/getmatrixlist.class.php @@ -1,104 +1,80 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - * @package babel - */ - /** - * Processor file for Babel. - * - * @author goldsky + * Get list resource matrix * * @package babel + * @subpackage processors */ -if (!class_exists('\MODX\Revolution\modX')) { - include_once MODX_CORE_PATH.'model/modx/processors/resource/getlist.class.php'; -} else { - class_alias(\MODX\Revolution\Processors\Resource\GetList::class, \modResourceGetListProcessor::class); -} +use mikrobi\Babel\Processors\ObjectGetListProcessor; -class BabelResourceGetMatrixListProcessor extends modResourceGetListProcessor +class BabelResourceGetMatrixListProcessor extends ObjectGetListProcessor { - /** @var Babel $babel */ - public $babel; - + public $classKey = 'modResource'; public $defaultSortField = 'id'; - private $_contexts = []; - - function __construct(modX & $modx,array $properties = array()) - { - parent::__construct($modx, $properties); + public $objectType = 'babel.resource'; + public $languageTopics = ['resource', 'babel:default']; + public $permission = 'view'; - $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); - $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); - } + protected $search = ['pagetitle']; + protected $contexts = []; + /** + * {@inheritDoc} + * @return bool + */ public function initialize() { - $this->_contexts = array_map('trim', @explode(',', $this->getProperty('contexts'))); + $this->contexts = array_map('trim', explode(',', $this->getProperty('contexts'))); return parent::initialize(); } + /** + * {@inheritDoc} + * @param xPDOQuery $c + * @return xPDOQuery + */ public function prepareQueryBeforeCount(xPDOQuery $c) { $c = parent::prepareQueryBeforeCount($c); - $query = $this->getProperty('query'); - if (!empty($query)) { - $c->where([ - 'pagetitle:LIKE' => '%' . $query . '%' - ]); - } $ctx = $this->getProperty('context'); - if (!empty($ctx)) { + if ($ctx) { $c->where([ 'context_key:=' => $ctx ]); + } else { + $c->where([ + 'context_key:IN' => $this->babel->getOption('contexts') + ]); } + return $c; } + /** + * {@inheritDoc} + * @param xPDOObject $object + * @return array + */ public function prepareRow(xPDOObject $object) { - $objectArray = $object->toArray(); - // 'id' conflicts with Indonesian's ISO code 'id' + $objectArray = parent::prepareRow($object); $linkedResources = $this->babel->getLinkedResources($objectArray['id']); - foreach ($this->_contexts as $ctx) { - // 'id' conflicts with Indonesian's ISO code 'id' - // prepend with a suffix - $objectArray['linkedres_id_'.$ctx] = ''; - $objectArray['linkedres_pagetitle_'.$ctx] = ''; + foreach ($this->contexts as $ctx) { + $objectArray['linkedres_id_' . $ctx] = ''; + $objectArray['linkedres_pagetitle_' . $ctx] = ''; if ($objectArray['context_key'] === $ctx) { - $objectArray['linkedres_id_'.$ctx] = 'x'; - $objectArray['linkedres_pagetitle_'.$ctx] = 'x'; + $objectArray['linkedres_id_' . $ctx] = 'x'; + $objectArray['linkedres_pagetitle_' . $ctx] = 'x'; } else { if (isset($linkedResources[$ctx]) && !empty($linkedResources[$ctx])) { - $objectArray['linkedres_id_'.$ctx] = $linkedResources[$ctx]; - $resource = $this->modx->getObject('modResource', $linkedResources[$ctx]); + $objectArray['linkedres_id_' . $ctx] = $linkedResources[$ctx]; + $resource = $this->modx->getObject('modResource', $linkedResources[$ctx]); if ($resource) { - $objectArray['linkedres_pagetitle_'.$ctx] = $resource->get('pagetitle'); + $objectArray['linkedres_pagetitle_' . $ctx] = $resource->get('pagetitle'); } } } @@ -106,7 +82,6 @@ public function prepareRow(xPDOObject $object) return $objectArray; } - } return 'BabelResourceGetMatrixListProcessor'; diff --git a/core/components/babel/processors/mgr/resource/link.class.php b/core/components/babel/processors/mgr/resource/link.class.php index 01ce6b9..fe4b80e 100644 --- a/core/components/babel/processors/mgr/resource/link.class.php +++ b/core/components/babel/processors/mgr/resource/link.class.php @@ -1,96 +1,62 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA + * Link resource * * @package babel + * @subpackage processors */ -/** - * Processor file for Babel. - * - * @author goldsky - * - * @package babel - */ +use mikrobi\Babel\Processors\ObjectUpdateProcessor; -class BabelLinkResourceProcessor extends modObjectGetProcessor +class BabelLinkResourceProcessor extends ObjectUpdateProcessor { - /** @var Babel $babel */ - public $babel; - - public $classKey = 'modResource'; + public $classKey = 'modResource'; + public $objectType = 'resource'; public $languageTopics = ['resource', 'babel:default']; - public $objectType = 'resource'; - public $targetResource; - - /** @var modAccessibleObject|xPDOObject|modResource $object The object */ - public $object; - function __construct(modX & $modx,array $properties = array()) - { - parent::__construct($modx, $properties); - - $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); - $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); - } + /** @var modResource $targetResource The link target */ + protected $targetResource; + /** + * {@inheritDoc} + * @return boolean + */ public function initialize() { + $success = parent::initialize(); + $target = $this->getProperty('target', false); if (empty($target)) { return $this->modx->lexicon($this->objectType . '_err_ns'); } - $primaryKey = $this->getProperty($this->primaryKeyField, false); - if (empty($primaryKey)) { - return $this->modx->lexicon($this->objectType . '_err_ns'); - } - if ($target === $primaryKey) { - return $this->modx->lexicon('error.link_of_selflink_not_possible'); + return $this->modx->lexicon('babel.resource_err_link_of_selflink_not_possible'); } - - $this->targetResource = $this->modx->getObject('modResource', intval($target)); + $this->targetResource = $this->modx->getObject('modResource', $target); if (!$this->targetResource) { - return $this->modx->lexicon('error.invalid_resource_id', ['resource' => $target]); + return $this->modx->lexicon('babel.resource_err_invalid_id', [ + 'resource' => $target + ]); } - $contextKey = $this->getProperty('context', false); if (empty($contextKey)) { return $this->modx->lexicon('babel.context_err_ns'); } - $context = $this->modx->getObject('modContext', ['key' => $contextKey]); if (!$context) { - return $this->modx->lexicon('error.invalid_context_key', ['context' => $contextKey]); + return $this->modx->lexicon('babel.context_err_invalid_key', [ + 'context' => $contextKey + ]); } - if ($this->targetResource->get('context_key') !== $contextKey) { - return $this->modx->lexicon('error.resource_from_other_context', [ - 'resource' => $this->targetResource->get('id'), - 'context' => $contextKey + return $this->modx->lexicon('babel.resource_err_from_other_context', [ + 'resource' => $this->targetResource->get('id'), + 'context' => $contextKey ]); } - return parent::initialize(); + return $success; } /** @@ -99,53 +65,41 @@ public function initialize() */ public function process() { - $props = $this->getProperties(); - - $targetResources = $this->babel->getLinkedResources($props['target']); -// if (count($targetResources) > 1 && isset($targetResources[$this->object->get('context_key')])) { -// return $this->failure($this->modx->lexicon('error.translation_already_exists', array( -// 'context' => $props['context'], -// 'resource' => $targetResources[$props['context']], -// 'pagetitle' => $this->modx->getObject('modResource', $targetResources[$props['context']])->get('pagetitle'), -// ))); -// } - + $targetResources = $this->babel->getLinkedResources($this->getProperty('target')); $linkedResources = $this->babel->getLinkedResources($this->object->get('id')); if (empty($linkedResources)) { /* always be sure that the Babel TV is set */ $this->babel->initBabelTv($this->object); } + $context = $this->getProperty('context'); /* add or change a translation link */ - if (isset($linkedResources[$props['context']])) { - /* existing link has been changed: - * -> reset Babel TV of old resource */ - $this->babel->initBabelTvById($linkedResources[$props['context']]); + if (isset($linkedResources[$context])) { + /* If the existing link has been changed, reset the Babel TV of the old resource */ + $this->babel->initBabelTvById($linkedResources[$context]); } - $linkedResources[$props['context']] = $this->targetResource->get('id'); + $linkedResources[$context] = $this->targetResource->get('id'); - if (isset($props['sync-linked-tranlations']) && intval($props['sync-linked-tranlations']) == 1) { - /** - * Join all existing linked resources from both resources - */ + $syncLinkedTranslations = $this->getProperty('sync-linked-tranlations'); + if ($syncLinkedTranslations == 1) { + /* Join all existing linked resources from both resources */ $mergedResources = array_merge($targetResources, $linkedResources); $this->babel->updateBabelTv($mergedResources, $mergedResources); } else { - /** - * Only join between 2 resources - */ - $merge1 = array_merge($linkedResources, [ - $props['context'] => $this->targetResource->get('id') + /* Only join between 2 resources */ + $mergeLinked = array_merge($linkedResources, [ + $this->getProperty('context') => $this->targetResource->get('id') ]); - $this->babel->updateBabelTv($this->object->get('id'), $merge1); - $merge2 = array_merge($targetResources, [ + $this->babel->updateBabelTv($this->object->get('id'), $mergeLinked); + $mergeTarget = array_merge($targetResources, [ $this->object->get('context_key') => $this->object->get('id') ]); - $this->babel->updateBabelTv($this->targetResource->get('id'), $merge2); + $this->babel->updateBabelTv($this->targetResource->get('id'), $mergeTarget); } - /* copy values of synchronized TVs to target resource */ - if (isset($props['copy-tv-values']) && intval($props['copy-tv-values']) == 1) { + $copyTvValues = $this->getProperty('copy-tv-values'); + if ($copyTvValues == 1) { + /* copy values of synchronized TVs to target resource */ $this->babel->synchronizeTvs($this->object->get('id')); } @@ -155,21 +109,20 @@ public function process() /** * Fire the OnBabelLink event - * @return void */ public function fireLinkEvent() { $this->modx->invokeEvent('OnBabelLink', [ - 'context_key' => $this->getProperty('context'), - 'original_id' => $this->object->get('id'), + 'context_key' => $this->getProperty('context'), + 'original_id' => $this->object->get('id'), 'original_resource' => &$this->object, - 'target_id' => $this->targetResource->get('id'), - 'target_resource' => &$this->targetResource + 'target_id' => $this->targetResource->get('id'), + 'target_resource' => &$this->targetResource ]); } /** - * Return the response + * {@inheritDoc} * @return array */ public function cleanup() diff --git a/core/components/babel/processors/mgr/resource/unlink.class.php b/core/components/babel/processors/mgr/resource/unlink.class.php index c8d6386..b1b5fc3 100644 --- a/core/components/babel/processors/mgr/resource/unlink.class.php +++ b/core/components/babel/processors/mgr/resource/unlink.class.php @@ -1,70 +1,53 @@ - * - * This file is part of Babel. - * - * Babel 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. - * - * Babel 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 - * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA + * Unink resource * * @package babel + * @subpackage processors */ -/** - * Processor file for Babel. - * - * @author goldsky - * - * @package babel - */ +use mikrobi\Babel\Processors\ObjectUpdateProcessor; -class BabelUnlinkResourceProcessor extends modObjectGetProcessor +class BabelUnlinkResourceProcessor extends ObjectUpdateProcessor { - /** @var Babel $babel */ - public $babel; - - public $classKey = 'modResource'; + public $classKey = 'modResource'; + public $objectType = 'resource'; public $languageTopics = ['resource', 'babel:default']; - public $objectType = 'resource'; - public $targetResource; - /** @var modAccessibleObject|xPDOObject|modResource $object The object */ - public $object; - - function __construct(modX & $modx,array $properties = array()) - { - parent::__construct($modx, $properties); - - $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); - $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); - } + /** @var modResource $targetResource The link target */ + protected $targetResource; + /** + * {@inheritDoc} + * @return boolean + */ public function initialize() { + $success = parent::initialize(); + $target = $this->getProperty('target', false); + $contextKey = $this->getProperty('context', false); + if (empty($target) && !empty($contextKey)) { + return $this->modx->lexicon($this->objectType . '_err_ns'); + } $primaryKey = $this->getProperty($this->primaryKeyField, false); - if (empty($primaryKey)) { - return $this->modx->lexicon($this->objectType.'_err_ns'); + if ($target === $primaryKey) { + return $this->modx->lexicon('babel.resource_err_unlink_of_selflink_not_possible'); } - if ($target === $primaryKey) { - return $this->modx->lexicon('error.unlink_of_selflink_not_possible'); + if ($target) { + if (empty($contextKey)) { + return $this->modx->lexicon('babel.context_err_ns'); + } + $context = $this->modx->getObject('modContext', ['key' => $contextKey]); + if (!$context) { + return $this->modx->lexicon('babel.context_err_invalid_key', [ + 'context' => $contextKey + ]); + } } - return parent::initialize(); + return $success; } /** @@ -73,54 +56,41 @@ public function initialize() */ public function process() { - $props = $this->getProperties(); - + $targetResources = $this->babel->getLinkedResources($this->getProperty('target')); $linkedResources = $this->babel->getLinkedResources($this->object->get('id')); if (empty($linkedResources)) { + /* always be sure that the Babel TV is set */ $this->babel->initBabelTv($this->object); } - /** - * Unlinked this resource to all resources - */ - if (empty($props['target'])) { - foreach ($linkedResources as $k => $v) { - $targetResources = $this->babel->getLinkedResources($v); - $diff = array_diff($targetResources, [ + $target = $this->getProperty('target'); + if (empty($target)) { + /* Unlink this resource from all resources */ + foreach ($linkedResources as $v) { + $resources = $this->babel->getLinkedResources($v); + $diff = array_diff($resources, [ $this->object->get('context_key') => $this->object->get('id') ]); $this->babel->updateBabelTv($v, $diff); } - $this->babel->updateBabelTv($this->object->get('id'), []); return $this->cleanup(); } - $target = $this->getProperty('target', false); - $this->targetResource = $this->modx->getObject('modResource', intval($target)); + $this->targetResource = $this->modx->getObject('modResource', $target); if (!$this->targetResource) { - return $this->failure($this->modx->lexicon('error.invalid_resource_id', ['resource' => $target])); - } - - $contextKey = $this->getProperty('context', false); - if (empty($contextKey)) { - return $this->failure($this->modx->lexicon('babel.context_err_ns')); + return $this->failure($this->modx->lexicon('babel.resource_err_invalid_id', [ + 'resource' => $target + ])); } - $context = $this->modx->getObject('modContext', ['key' => $contextKey]); - if (!$context) { - return $this->failure($this->modx->lexicon('error.invalid_context_key', ['context' => $contextKey])); - } - - $targetResources = $this->babel->getLinkedResources($props['target']); if (empty($targetResources)) { $this->babel->initBabelTv($this->targetResource); } unset($targetResources[$this->object->get('context_key')]); $this->babel->updateBabelTv($targetResources, $targetResources); - - unset($linkedResources[$props['context']]); + unset($linkedResources[$this->getProperty('context')]); $this->babel->updateBabelTv($this->object->get('id'), $linkedResources); $this->fireUnlinkEvent(); @@ -129,21 +99,20 @@ public function process() /** * Fire the OnBabelUnlink event - * @return void */ public function fireUnlinkEvent() { $this->modx->invokeEvent('OnBabelUnlink', [ - 'context_key' => $this->getProperty('context'), - 'original_id' => $this->object->get('id'), + 'context_key' => $this->getProperty('context'), + 'original_id' => $this->object->get('id'), 'original_resource' => &$this->object, - 'target_id' => $this->targetResource->get('id'), - 'target_resource' => &$this->targetResource + 'target_id' => $this->targetResource->get('id'), + 'target_resource' => &$this->targetResource ]); } /** - * Return the response + * {@inheritDoc} * @return array */ public function cleanup() diff --git a/core/components/babel/processors/mgr/settings/getlist.class.php b/core/components/babel/processors/mgr/settings/getlist.class.php new file mode 100644 index 0000000..882a7f8 --- /dev/null +++ b/core/components/babel/processors/mgr/settings/getlist.class.php @@ -0,0 +1,35 @@ + 'babel']; + } +} + +return 'BabelSystemSettingsGetlistProcessor'; diff --git a/core/components/babel/processors/mgr/settings/update.class.php b/core/components/babel/processors/mgr/settings/update.class.php new file mode 100644 index 0000000..9b6dd3c --- /dev/null +++ b/core/components/babel/processors/mgr/settings/update.class.php @@ -0,0 +1,62 @@ +setProperty('namespace', 'babel'); + $this->checkForBooleanValue(); + $this->checkCanSave(); + return parent::beforeSave(); + } + + /** + * {@inheritDoc} + * @return bool + */ + public function afterSave() + { + $this->updateTranslations($this->getProperties()); + $this->clearCache(); + return parent::afterSave(); + } + + /** + * Verify the namespace passed is a valid namespace + */ + protected function checkCanSave() + { + $key = $this->getProperty('key'); + if (strpos($key, 'babel.') !== 0) { + $this->addFieldError('key', $this->modx->lexicon('babel.systemsetting_key_err_nv')); + } + if (!$this->modx->hasPermission('settings') && !$this->modx->hasPermission('babel_settings')) { + $this->addFieldError('usergroup', $this->modx->lexicon('babel.systemsetting_usergroup_err_nv')); + } + } +} + +return 'BabelSystemSettingsUpdateProcessor'; diff --git a/core/components/babel/processors/mgr/settings/updatefromgrid.class.php b/core/components/babel/processors/mgr/settings/updatefromgrid.class.php new file mode 100644 index 0000000..7bc1546 --- /dev/null +++ b/core/components/babel/processors/mgr/settings/updatefromgrid.class.php @@ -0,0 +1,31 @@ +getProperty('data'); + if (empty($data)) return $this->modx->lexicon('invalid_data'); + $properties = json_decode($data, true); + $this->setProperties($properties); + $this->unsetProperty('data'); + + return parent::initialize(); + } +} + +return 'BabelSystemSettingsUpdateFromGridProcessor'; diff --git a/core/components/babel/src/Babel.php b/core/components/babel/src/Babel.php new file mode 100644 index 0000000..bb11977 --- /dev/null +++ b/core/components/babel/src/Babel.php @@ -0,0 +1,759 @@ + + * + * This file is part of Babel. + * + * Babel 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. + * + * Babel 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 + * Babel; if not, write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + * Based on ideas of Sylvain Aerni + * + * @author Jakob Class + * @author Rico Goldsky + * @author Joshua Luckers + * @author Thomas Jakobi + * + * @package babel + * @subpackage classfile + */ + +namespace mikrobi\Babel; + +use mikrobi\Babel\Helper\Parse; +use mikrobi\Babel\LanguageSubtagRegistry\LanguageSubtagRegistry; +use modChunk; +use modResource; +use modSystemEvent; +use modTemplateVar; +use modX; +use MODX\Revolution\modContext; +use xPDO; +use xPDOCacheManager; + +class Babel +{ + /** + * A reference to the modX instance + * @var modX $modx + */ + public $modx; + + /** + * The namespace + * @var string $namespace + */ + public $namespace = 'babel'; + + /** + * The package name + * @var string $packageName + */ + public $packageName = 'Babel'; + + /** + * The version + * @var string $version + */ + public $version = '3.2.0'; + + /** + * The class config + * @var array $config + */ + public $config = []; + + /** + * A collection of preprocessed chunk values. + * @var array + */ + protected $chunks = []; + + /** + * A reference to the babel TV which is used to store linked resources. + * The linked resources are stored using this syntax: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] + * Example: web:1;de:4;es:7;fr:10 + * @var modTemplateVar $babelTv + */ + public $babelTv = null; + + /** + * An associative array which maps context keys to the context groups. + * @var array $contextKeyToGroup + */ + protected $contextKeyToGroup = []; + + /** + * @var Parse $parse + */ + public $parse = null; + + /** + * Babel constructor + * + * @param modX $modx A reference to the modX instance. + * @param array $config An array of config. Optional. + */ + public function __construct(modX &$modx, array $config = []) + { + $this->modx =& $modx; + $this->namespace = $this->getOption('namespace', $config, $this->namespace); + + $corePath = $this->getOption('core_path', $config, $this->modx->getOption('core_path', null, MODX_CORE_PATH) . 'components/' . $this->namespace . '/'); + $assetsPath = $this->getOption('assets_path', $config, $this->modx->getOption('assets_path', null, MODX_ASSETS_PATH) . 'components/' . $this->namespace . '/'); + $assetsUrl = $this->getOption('assets_url', $config, $this->modx->getOption('assets_url', null, MODX_ASSETS_URL) . 'components/' . $this->namespace . '/'); + $modxversion = $this->modx->getVersionData(); + + // Load some default paths for easier management + $this->config = array_merge([ + 'namespace' => $this->namespace, + 'version' => $this->version, + 'corePath' => $corePath, + 'modelPath' => $corePath . 'model/', + 'vendorPath' => $corePath . 'vendor/', + 'chunksPath' => $corePath . 'elements/chunks/', + 'pagesPath' => $corePath . 'elements/pages/', + 'snippetsPath' => $corePath . 'elements/snippets/', + 'pluginsPath' => $corePath . 'elements/plugins/', + 'controllersPath' => $corePath . 'controllers/', + 'processorsPath' => $corePath . 'processors/', + 'templatesPath' => $corePath . 'templates/', + 'assetsPath' => $assetsPath, + 'assetsUrl' => $assetsUrl, + 'jsUrl' => $assetsUrl . 'js/', + 'cssUrl' => $assetsUrl . 'css/', + 'imagesUrl' => $assetsUrl . 'images/', + 'connectorUrl' => $assetsUrl . 'connector.php' + ], $config); + + $lexicon = $this->modx->getService('lexicon', 'modLexicon'); + $lexicon->load($this->namespace . ':default'); + + $this->packageName = $this->modx->lexicon('babel'); + + // Add default config + $this->config = array_merge($this->config, [ + 'debug' => $this->getBooleanOption('debug', [], false), + 'modxversion' => $modxversion['version'], + 'permissions' => $this->getPermissions(), + 'contextKeys' => $this->modx->getOption($this->namespace . '.contextKeys', null, ''), + 'restrictToGroup' => $this->getBooleanOption('restrictToGroup', [], true), + 'displayText' => $this->modx->getOption($this->namespace . '.displayText', null, 'language'), + 'syncTvs' => $this->modx->getOption($this->namespace . '.syncTvs', null, ''), + 'babelTvName' => $this->modx->getOption($this->namespace . '.babelTvName', null, 'babelLanguageLinks'), + ]); + + $contextKeys = $this->getOption('contextKeys'); + $this->contextKeyToGroup = $this->decodeContextKeySetting($contextKeys); + $this->config['contexts'] = array_keys($this->contextKeyToGroup); + + $babelTvName = $this->getOption('babelTvName'); + $this->babelTv = $modx->getObject('modTemplateVar', ['name' => $babelTvName]); + if (!$this->babelTv) { + $this->modx->log(xPDO::LOG_LEVEL_WARN, 'Could not load babel TV: ' . $babelTvName . ' will try to create it ...'); + $fields = [ + 'name' => $babelTvName, + 'type' => 'hidden', + 'default_text' => '', + 'caption' => $this->modx->lexicon('babel.tv_caption'), + 'description' => $this->modx->lexicon('babel.tv_description') + ]; + $this->babelTv = $modx->newObject('modTemplateVar', $fields); + if ($this->babelTv->save()) { + $this->modx->log(xPDO::LOG_LEVEL_INFO, 'Created babel TV: ' . $babelTvName); + } else { + $this->modx->log(xPDO::LOG_LEVEL_ERROR, 'Could not create babel TV: ' . $babelTvName); + } + } + + $this->parse = new Parse($modx); + } + + /** + * Get a local configuration option or a namespaced system setting by key. + * + * @param string $key The option key to search for. + * @param array $config An array of config that override local config. + * @param mixed $default The default value returned if the option is not found locally or as a + * namespaced system setting; by default this value is null. + * @return mixed The option value or the default value specified. + */ + public function getOption(string $key, array $config = [], $default = null) + { + $option = $default; + if (!empty($key) && is_string($key)) { + if ($config != null && array_key_exists($key, $config)) { + $option = $config[$key]; + } elseif (array_key_exists($key, $this->config)) { + $option = $this->config[$key]; + } elseif (array_key_exists("$this->namespace.$key", $this->modx->config)) { + $option = $this->modx->getOption("$this->namespace.$key"); + } + } + return $option; + } + + /** + * Get Boolean Option + * + * @param string $key + * @param array $config + * @param mixed $default + * @return bool + */ + public function getBooleanOption(string $key, array $config = [], $default = null): bool + { + $option = $this->getOption($key, $config, $default); + return ($option === 'true' || $option === true || $option === '1' || $option === 1); + } + + /** + * Set a local configuration option. + * + * @param string $key The option key to be set. + * @param mixed $value The value. + */ + public function setOption(string $key, $value) + { + $this->config[$key] = $value; + } + + /** + * @return array + */ + public function getPermissions() + { + $access = []; + $perms = [ + 'babel_settings', + 'settings', + ]; + foreach ($perms as $p) { + $access[$p] = $this->modx->hasPermission($p); + } + return $access; + } + + /** + * Creates an associative array which maps context keys to there + * context groups out of an $contextKeyString + * + * @param string $contextKeyString Example: ctx1,ctx2;ctx3,ctx4,ctx5;ctx5,ctx6 + * @return array An associative array which maps context keys to the context groups. + */ + public function decodeContextKeySetting($contextKeyString) + { + $contextKeyToGroup = []; + if (!empty($contextKeyString)) { + $contextGroups = explode(';', $contextKeyString); + $contextGroups = array_map('trim', $contextGroups); + foreach ($contextGroups as $contextGroup) { + $groupContextKeys = explode(',', $contextGroup); + $groupContextKeys = array_map('trim', $groupContextKeys); + foreach ($groupContextKeys as $contextKey) { + if (!empty($contextKey)) { + $contextKeyToGroup[$contextKey] = $groupContextKeys; + } + } + } + } + return $contextKeyToGroup; + } + + /** + * Synchronizes the TVs of the specified resource with its translated resources. + * + * @param int $resourceId id of resource. + */ + public function synchronizeTvs($resourceId) + { + $linkedResources = $this->getLinkedResources($resourceId); + /* check if Babel TV has been initiated for the specified resource */ + if (empty($linkedResources)) { + $linkedResources = $this->initBabelTvById($resourceId); + } + + /* synchronize the TVs of linked resources */ + $syncTvs = $this->getOption('syncTvs'); + if (empty($syncTvs) || !is_array($syncTvs)) { + /* there are no TVs to synchronize */ + return; + } + + foreach ($syncTvs as $tvId) { + /* go through each TV which should be synchronized */ + $tv = $this->modx->getObject('modTemplateVar', $tvId); + if (!$tv) { + continue; + } + $tvValue = $tv->getValue($resourceId); + foreach ($linkedResources as $linkedResourceId) { + /* go through each linked resource */ + if ($resourceId == $linkedResourceId) { + /* don't synchronize resource with itself */ + continue; + } + $tv->setValue($linkedResourceId, $tvValue); + } + $tv->save(); + } + + $this->modx->cacheManager->refresh(); + } + + /** + * Returns an array with the context keys of the specified context's group. + * + * @param string $contextKey key of context. + * @param bool $restrictToGroup restrict to context's group. + */ + public function getGroupContextKeys($contextKey, $restrictToGroup = true) + { + $contextKeys = []; + if ($restrictToGroup) { + if (isset($this->contextKeyToGroup[$contextKey]) && is_array($this->contextKeyToGroup[$contextKey])) { + $contextKeys = $this->contextKeyToGroup[$contextKey]; + } + } else { + $contextKeys = $this->getOption('contexts'); + } + return $contextKeys; + } + + /** + * Creates a duplicate of the specified resource in the specified context. + * + * @param modResource $resource + * @param string $contextKey + */ + public function duplicateResource($resource, $contextKey) + { + /* determine parent id of new resource */ + $newParentId = null; + $parentId = $resource->get('parent'); + if ($parentId != null) { + $linkedParentResources = $this->getLinkedResources($parentId); + if (isset($linkedParentResources[$contextKey])) { + $newParentId = $linkedParentResources[$contextKey]; + } + } + /* create new resource */ + $newResource = $this->modx->newObject($resource->get('class_key')); + $newResource->fromArray($resource->toArray('', true), '', false, true); + $newResource->set('id', 0); + $newResource->set('pagetitle', $resource->get('pagetitle') . ' ' . $this->modx->lexicon('babel.translation_pending')); + $newResource->set('parent', intval($newParentId)); + $newResource->set('createdby', $this->modx->user->get('id')); + $newResource->set('createdon', time()); + $newResource->set('editedby', 0); + $newResource->set('editedon', 0); + $newResource->set('deleted', false); + $newResource->set('deletedon', 0); + $newResource->set('deletedby', 0); + $newResource->set('published', false); + $newResource->set('publishedon', 0); + $newResource->set('publishedby', 0); + $newResource->set('context_key', $contextKey); + if ($newResource->save()) { + /* copy all TV values */ + $templateVarResources = $resource->getMany('TemplateVarResources'); + foreach ($templateVarResources as $oldTemplateVarResource) { + $newTemplateVarResource = $this->modx->newObject('modTemplateVarResource'); + $newTemplateVarResource->set('contentid', $newResource->get('id')); + $newTemplateVarResource->set('tmplvarid', $oldTemplateVarResource->get('tmplvarid')); + $newTemplateVarResource->set('value', $oldTemplateVarResource->get('value')); + $newTemplateVarResource->save(); + } + + /* set parent of duplicate as a folder */ + if ($newParentId) { + $newParent = $this->modx->getObject('modResource', $newParentId); + if ($newParent) { + $newParent->set('isfolder', 1); + $newParent->save(); + } + } + + /* invoke OnDocFormSave event */ + $this->modx->invokeEvent('OnDocFormSave', [ + 'mode' => modSystemEvent::MODE_NEW, + 'id' => $newResource->get('id'), + 'resource' => &$newResource + ]); + } else { + $this->modx->log(xPDO::LOG_LEVEL_ERROR, 'Could not duplicate resource: ' . $resource->get('id') . ' in context: ' . $contextKey); + $newResource = null; + } + return $newResource; + } + + /** + * Init/reset the Babel TV of the specified resource. + * + * @param modResource $resource resource object. + * @return array associative array with linked resources (array contains only the resource itself). + */ + public function initBabelTv($resource) + { + $linkedResources = [$resource->get('context_key') => $resource->get('id')]; + $this->updateBabelTv($resource->get('id'), $linkedResources, false); + return $linkedResources; + } + + /** + * Run \Babel\initBabelTv recursively + * + * @author https://github.com/manu37 + * + * @param object $modx + * @param object $babel + * @param int $id + * @param int $depth + * @return void + */ + public function initBabelTvsRecursive(&$modx, &$babel, $id = null, $depth = 100) + { + if ($id && $depth > 0) { + $q = $modx->newQuery('modResource'); + $q->select(['id']); + $q->where(['parent' => $id]); + $children = $modx->getCollection('modResource', $q); + foreach ($children as $child) { + $processDepth = $depth - 1; + $this->initBabelTvsRecursive($modx, $babel, $child->get('id'), $processDepth); + } + $this->initBabelTvById($id); + } + } + + /** + * Init/reset the Babel TV of a resource specified by the id of the resource. + * + * @param int $resourceId id of resource (int). + */ + public function initBabelTvById($resourceId) + { + /** @var modResource $resource */ + $resource = $this->modx->getObject('modResource', $resourceId); + return $this->initBabelTv($resource); + } + + /** + * Updates the Babel TV of the specified resource(s). + * + * @param mixed $resourceIds id of resource or array of resource ids which should be updated. + * @param array $linkedResources associative array with linked resources: [contextKey] = resourceId + * @param boolean $clearCache flag to empty cache after update. + */ + public function updateBabelTv($resourceIds, $linkedResources, $clearCache = true) + { + if (!is_array($resourceIds)) { + $resourceIds = [intval($resourceIds)]; + } + $newValue = $this->encodeTranslationLinks($linkedResources); + foreach ($resourceIds as $resourceId) { + $this->babelTv->setValue($resourceId, $newValue); + } + $this->babelTv->save(); + if ($clearCache) { + $this->modx->cacheManager->refresh(); + } + } + + /** + * Returns an associative array of the linked resources of the specified resource. + * + * @param int $resourceId id of resource. + * @return array associative array with linked resources: [contextKey] = resourceId. + */ + public function getLinkedResources($resourceId) + { + return $this->decodeTranslationLinks($this->babelTv->getValue($resourceId)); + } + + /** + * Creates an associative array of linked resources out of string. + * + * @param string $linkedResourcesString string which contains the translation links: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] + * @return array associative array with linked resources: [contextKey] = resourceId. + */ + public function decodeTranslationLinks($linkedResourcesString) + { + $linkedResources = []; + if (!empty($linkedResourcesString)) { + $contextResourcePairs = explode(';', $linkedResourcesString); + foreach ($contextResourcePairs as $contextResourcePair) { + $contextResourcePair = explode(':', $contextResourcePair); + $contextKey = $contextResourcePair[0]; + $resourceId = intval($contextResourcePair[1]); + $linkedResources[$contextKey] = $resourceId; + } + } + return $linkedResources; + } + + /** + * Creates a string which contains the translation links out of an associative array. + * + * @param array $linkedResources associative array with linked resources: [contextKey] = resourceId + * @return string which contains the translation links: [contextKey1]:[resourceId1];[contextKey2]:[resourceId2] + */ + public function encodeTranslationLinks($linkedResources) + { + if (!is_array($linkedResources)) { + return ''; + } + $contextResourcePairs = []; + foreach ($linkedResources as $contextKey => $resourceId) { + $contextResourcePairs[] = $contextKey . ':' . intval($resourceId); + } + return implode(';', $contextResourcePairs); + } + + /** + * Removes all translation links to the specified resource. + * + * @param int $resourceId id of resource. + */ + public function removeLanguageLinksToResource($resourceId) + { + /* search for resource which contain a ':$resourceId' in their Babel TV */ + $templateVarResources = $this->modx->getCollection('modTemplateVarResource', [ + 'value:LIKE' => '%:' . $resourceId . '%' + ]); + if (!is_array($templateVarResources)) { + return; + } + foreach ($templateVarResources as $templateVarResource) { + /* go through each resource and remove the link of the specified resource */ + $oldValue = $templateVarResource->get('value'); + $linkedResources = $this->decodeTranslationLinks($oldValue); + /* array maps context keys to resource ids + * -> search for the context key of the specified resource id */ + $contextKey = array_search($resourceId, $linkedResources); + /* sanity check, is the contextKey really a context in babel's settings? */ + if (array_key_exists($contextKey, $this->contextKeyToGroup)) { + unset($linkedResources[$contextKey]); + $newValue = $this->encodeTranslationLinks($linkedResources); + $templateVarResource->set('value', $newValue); + $templateVarResource->save(); + } + } + } + + /** + * Removes all translation links to the specified context. + * + * @param int $contextKey key of context. + */ + public function removeLanguageLinksToContext($contextKey) + { + /* search for resource which contain a '$contextKey:' in their Babel TV */ + $templateVarResources = $this->modx->getCollection('modTemplateVarResource', [ + 'value:LIKE' => '%' . $contextKey . ':%' + ]); + if (!is_array($templateVarResources)) { + return; + } + foreach ($templateVarResources as $templateVarResource) { + /* go through each resource and remove the link of the specified context */ + $oldValue = $templateVarResource->get('value'); + $linkedResources = $this->decodeTranslationLinks($oldValue); + /* array maps context keys to resource ids */ + unset($linkedResources[$contextKey]); + $newValue = $this->encodeTranslationLinks($linkedResources); + $templateVarResource->set('value', $newValue); + $templateVarResource->save(); + } + /* finaly clean the babel.contextKeys setting */ + $setting = $this->modx->getObject('modSystemSetting', [ + 'key' => 'babel.contextKeys' + ]); + if ($setting) { + /* remove all spaces */ + $newValue = str_replace(' ', '', $setting->get('value')); + /* replace context key with leading comma */ + $newValue = str_replace(',' . $contextKey, '', $newValue); + /* replace context key without leading comma (if still present) */ + $newValue = str_replace($contextKey, '', $newValue); + $setting->set('value', $newValue); + if ($setting->save()) { + $this->modx->reloadConfig(); + $this->modx->cacheManager->deleteTree($this->modx->getOption('core_path', null, MODX_CORE_PATH) . 'cache/mgr/smarty/', [ + 'deleteTop' => false, + 'skipDirs' => false, + 'extensions' => ['.cache.php', '.php'], + ]); + } + } + } + + /** + * Gets the contextKey by cultureKey + * + * @param string $cultureKey the culture key + * @return string context key + */ + public function getContextKey($cultureKey) + { + /* Search for Context Setting */ + $ctxSetting = $this->modx->getObject("modContextSetting", [ + "key" => "cultureKey", + "value" => $cultureKey + ]); + return (($ctxSetting) ? $ctxSetting->get("context_key") : false); + } + + /** + * Gets a Chunk and caches it; also falls back to file-based templates + * for easier debugging. + * + * @access public + * @param string $name The name of the Chunk + * @param array $properties The properties for the Chunk + * @return string The processed content of the Chunk + */ + public function getChunk($name, array $properties = []) + { + if (!isset($this->chunks[$name])) { + $chunk = $this->modx->getObject('modChunk', ['name' => $name]); + if (empty($chunk)) { + $chunk = $this->_getTplChunk($name, $this->getOption('chunkSuffix')); + if (!$chunk) { + return false; + } + } + $this->chunks[$name] = $chunk->getContent(); + } else { + $o = $this->chunks[$name]; + $chunk = $this->modx->newObject('modChunk'); + $chunk->setContent($o); + } + $chunk->setCacheable(false); + return $chunk->process($properties); + } + + /** + * Returns a modChunk object from a template file. + * + * @access private + * @param string $name The name of the Chunk. Will parse to name.chunk.tpl by default. + * @param string $suffix The suffix to add to the chunk filename. + * @return modChunk/boolean Returns the modChunk object if found, otherwise + * false. + */ + private function _getTplChunk($name, $suffix = '.chunk.tpl') + { + $chunk = false; + $f = $this->getOption('chunksPath') . strtolower($name) . $suffix; + if (file_exists($f)) { + $o = file_get_contents($f); + /** @var modChunk $chunk */ + $chunk = $this->modx->newObject('modChunk'); + $chunk->set('name', $name); + $chunk->setContent($o); + } + return $chunk; + } + + /** + * Get placeholders to create language selection menu. + * Used in plugin and processors. + * + * @param modResource $resource + * @return array menu + */ + public function getMenu($resource) + { + $menu = []; + $contextKeys = $this->getGroupContextKeys($resource->get('context_key'), $this->getOption('restrictToGroup')); + $linkedResources = $this->getLinkedResources($resource->get('id')); + if (empty($linkedResources)) { + /* always be sure that the Babel TV is set */ + $this->initBabelTv($resource); + } + + $languages = $this->getLanguages(); + foreach ($contextKeys as $contextKey) { + /* for each (valid/existing) context of the context group a button will be displayed */ + /** @var modContext $context */ + $context = $this->modx->getObject('modContext', ['key' => $contextKey]); + if (!$context) { + $this->modx->log(xPDO::LOG_LEVEL_ERROR, 'Could not load context: ' . $contextKey); + continue; + } + $context->prepare(); + $cultureKey = $context->getOption('cultureKey', $this->modx->getOption('cultureKey')); + $linkResource = null; + $resourceId = 0; + if (isset($linkedResources[$contextKey])) { + $resourceId = $linkedResources[$contextKey]; + /** @var modResource $linkResource */ + $linkResource = $this->modx->getObject('modResource', $resourceId); + } + if ($linkResource) { + $resourceUrl = '?a=resource/update&id=' . $resourceId; + $resourceTitle = $linkResource->get('pagetitle'); + } else { + $resourceId = ''; + $resourceUrl = '#'; + $resourceTitle = ''; + } + if ($this->getOption('displayText') == 'context') { + $displayText = $context->get('name') . ' (' . $contextKey . ')'; + } elseif ($this->getOption('displayText') == 'combination') { + $displayText = $context->get('name') . ' (' . $contextKey . ') - ' . $languages[$cultureKey]['Description'] . ' (' . (!empty($cultureKey) ? $cultureKey : $contextKey) . ')'; + } else { + $displayText = $languages[$cultureKey]['Description'] . ' (' . (!empty($cultureKey) ? $cultureKey : $contextKey) . ')'; + } + + $placeholders = [ + 'resourceId' => $resourceId, + 'resourceUrl' => $resourceUrl, + 'resourceTitle' => $resourceTitle, + 'displayText' => $displayText, + ]; + $menu[$contextKey] = $placeholders; + } + + return $menu; + } + + /** + * Get all languages in array + * + * @return array Languages' info + */ + public function getLanguages() + { + $cacheOptions = [ + xPDO::OPT_CACHE_KEY => 'babel', + xPDO::OPT_CACHE_HANDLER => $this->modx->getOption('cache_resource_handler', null, $this->modx->getOption(xPDO::OPT_CACHE_HANDLER)), + xPDO::OPT_CACHE_FORMAT => (integer)$this->modx->getOption('cache_resource_format', null, $this->modx->getOption(xPDO::OPT_CACHE_FORMAT, null, xPDOCacheManager::CACHE_PHP)), + ]; + $languages = $this->modx->cacheManager->get('languages', $cacheOptions); + if (!$languages) { + $ianaLstr = new LanguageSubtagRegistry(); + $ianaLstr->readSource($this->getOption('corePath') . 'src/LanguageSubtagRegistry/language-subtag-registry'); + $languages = $ianaLstr->languagesAssocArray('Subtag'); + $this->modx->cacheManager->set('languages', $languages, 0, $cacheOptions); + } + foreach ($languages as $k => $v) { + $languages[$k]['Description'] = $v['Description'][0]; + } + + return $languages; + } +} diff --git a/core/components/babel/src/Helper/Parse.php b/core/components/babel/src/Helper/Parse.php new file mode 100644 index 0000000..b7dc83d --- /dev/null +++ b/core/components/babel/src/Helper/Parse.php @@ -0,0 +1,212 @@ +modx =& $modx; + $this->babel =& $modx->babel; + } + + /** + * @param array $array + * @param string $separator + * @return array + */ + public static function flattenArray($array, $separator = '.'): array + { + $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); + $result = []; + foreach ($iterator as $value) { + $keys = []; + foreach (range(0, $iterator->getDepth()) as $depth) { + $keys[] = $iterator->getSubIterator($depth)->key(); + } + $result[join($separator, $keys)] = $value; + } + return $result; + } + + /** + * Get and parse a chunk (with template bindings) + * Modified parseTpl method from getResources package (https://github.com/opengeek/getResources) + * + * @param $tpl + * @param null $properties + * @return bool|string + */ + public function getChunk($tpl, $properties = null) + { + if ($pdo = $this->getPdoTools()) { + $output = $pdo->getChunk($tpl, $properties ?? []); + } else { + $output = false; + if (!empty($tpl)) { + $bound = [ + 'type' => '@CHUNK', + 'value' => $tpl + ]; + if (strpos($tpl, '@') === 0) { + $endPos = strpos($tpl, ' '); + if ($endPos > 2 && $endPos < 10) { + $tt = substr($tpl, 0, $endPos); + if (in_array($tt, $this->_validTypes)) { + $bound['type'] = $tt; + $bound['value'] = substr($tpl, $endPos + 1); + } + } + } + if (is_array($bound) && isset($bound['type']) && isset($bound['value'])) { + $output = $this->parseChunk($bound['type'], $bound['value'], $properties); + } + } + } + if (isset($properties['stripModxTags']) && $properties['stripModxTags']) { + $output = $this->stripModxTags($output); + } + return $output; + } + + /** + * Parse a chunk (with template bindings) + * Modified parseTplElement method from getResources package (https://github.com/opengeek/getResources) + * + * @param $type + * @param $source + * @param null $properties + * @return bool|string + */ + private function parseChunk($type, $source, $properties = null) + { + $output = false; + + if (!is_string($type) || !in_array($type, $this->_validTypes)) { + $type = $this->modx->getOption('tplType', $properties, '@CHUNK'); + } + + $content = false; + switch ($type) { + case '@FILE': + $path = $this->modx->getOption('tplPath', $properties, $this->modx->getOption('assets_path', $properties, MODX_ASSETS_PATH) . 'elements/chunks/'); + $key = $path . $source; + if (!isset($this->_tplCache['@FILE'])) { + $this->_tplCache['@FILE'] = []; + } + if (!array_key_exists($key, $this->_tplCache['@FILE'])) { + if (file_exists($key)) { + $content = file_get_contents($key); + } + $this->_tplCache['@FILE'][$key] = $content; + } else { + $content = $this->_tplCache['@FILE'][$key]; + } + if (!empty($content) && $content !== '0') { + $chunk = $this->modx->newObject('modChunk', ['name' => $key]); + $chunk->setCacheable(false); + $output = $chunk->process($properties, $content); + } + break; + case '@CODE': + case '@INLINE': + $uniqid = uniqid(); + $chunk = $this->modx->newObject('modChunk', ['name' => "$type-$uniqid"]); + $chunk->setCacheable(false); + $output = $chunk->process($properties, $source); + break; + case '@CHUNK': + default: + $chunk = null; + if (!isset($this->_tplCache['@CHUNK'])) { + $this->_tplCache['@CHUNK'] = []; + } + if (!array_key_exists($source, $this->_tplCache['@CHUNK'])) { + $chunk = $this->modx->getObject('modChunk', ['name' => $source]); + if ($chunk) { + $this->_tplCache['@CHUNK'][$source] = $chunk->toArray('', true); + } else { + $this->_tplCache['@CHUNK'][$source] = false; + } + } elseif (is_array($this->_tplCache['@CHUNK'][$source])) { + $chunk = $this->modx->newObject('modChunk'); + $chunk->fromArray($this->_tplCache['@CHUNK'][$source], '', true, true, true); + } + if (is_object($chunk)) { + $chunk->setCacheable(false); + $output = $chunk->process($properties); + } + break; + } + return $output; + } + + public function getPdoTools() + { + $pdoTools = null; + if (class_exists('pdoTools')) { + $pdoTools = $this->modx->getService('pdoTools'); + } elseif (class_exists('ModxPro\PdoTools\CoreTools')) { + $pdoTools = $this->modx->getService('ModxPro\PdoTools\CoreTools'); + } + + return $pdoTools; + } + + /** + * @param $string + * @return string + */ + public function stripModxTags($string) + { + return preg_replace('/\[\[([^\[\]]++|(?R))*?]]/sm', '', $string); + } +} diff --git a/core/components/babel/src/Plugins/Events/OnContextRemove.php b/core/components/babel/src/Plugins/Events/OnContextRemove.php new file mode 100644 index 0000000..6336d84 --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnContextRemove.php @@ -0,0 +1,24 @@ +scriptProperties['context']; + if ($context) { + $this->babel->removeLanguageLinksToContext($context->get('key')); + } + } +} diff --git a/core/components/babel/src/Plugins/Events/OnDocFormPrerender.php b/core/components/babel/src/Plugins/Events/OnDocFormPrerender.php new file mode 100644 index 0000000..8066f36 --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnDocFormPrerender.php @@ -0,0 +1,65 @@ +scriptProperties['resource']; + if (!$resource || !in_array($resource->get('context_key'), $this->babel->getOption('contexts'))) { + return false; + } + + return parent::init(); + } + + /** + * Add the Babel box to the resource form + * @return void + */ + public function process() + { + $assetsUrl = $this->babel->getOption('assetsUrl'); + $jsUrl = $this->babel->getOption('jsUrl') . 'mgr/'; + $jsSourceUrl = $assetsUrl . '../../../source/js/mgr/'; + + $resource = &$this->scriptProperties['resource']; + $linkedResources = $this->babel->getLinkedResources($resource->get('id')); + if (empty($linkedResources)) { + /* always be sure that the Babel TV is set */ + $this->babel->initBabelTv($resource); + } + + $this->babel->setOption('context_key', $resource->get('context_key')); + $this->babel->setOption('menu', $this->babel->getMenu($resource)); + if (empty($this->babel->getOption('menu'))) { + $this->modx->log(xPDO::LOG_LEVEL_ERROR, '[Babel] Could not load menu for context key: "' . $this->babel->getOption('context_key') . '". Try to check "babel.contextKeys" in System Settings. If this is intended, you can ignore this warning.'); + return; + } + + $this->modx->controller->addLexiconTopic('babel:default'); + if ($this->babel->getOption('debug') && ($this->babel->getOption('assetsUrl') != MODX_ASSETS_URL . 'components/babel/')) { + $this->modx->controller->addJavascript($jsSourceUrl . 'babel.js?v=v' . $this->babel->version); + } else { + $this->modx->controller->addJavascript($jsUrl . 'resourcebutton.min.js?v=v' . $this->babel->version); + } + $this->modx->controller->addHtml(''); + } +} diff --git a/core/components/babel/src/Plugins/Events/OnDocFormSave.php b/core/components/babel/src/Plugins/Events/OnDocFormSave.php new file mode 100644 index 0000000..b647472 --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnDocFormSave.php @@ -0,0 +1,42 @@ +scriptProperties['resource']; + if (!$resource || !in_array($resource->get('context_key'), $this->babel->getOption('contexts'))) { + return false; + } + + return parent::init(); + } + + /** + * Initialize or Synchronize the TVs + * @return void + */ + public function process() + { + $resource = &$this->scriptProperties['resource']; + if ($this->scriptProperties['mode'] == modSystemEvent::MODE_NEW) { + // No TV synchronization for new resources, just init Babel TV + $this->babel->initBabelTv($resource); + return; + } + $this->babel->synchronizeTvs($resource->get('id')); + } +} diff --git a/core/components/babel/src/Plugins/Events/OnEmptyTrash.php b/core/components/babel/src/Plugins/Events/OnEmptyTrash.php new file mode 100644 index 0000000..fccdd1e --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnEmptyTrash.php @@ -0,0 +1,27 @@ +scriptProperties['ids']; + if (is_array($deletedResourceIds)) { + // Remove translation links to non-existing resources + foreach ($deletedResourceIds as $deletedResourceId) { + $this->babel->removeLanguageLinksToResource($deletedResourceId); + } + } + } +} diff --git a/core/components/babel/src/Plugins/Events/OnResourceDuplicate.php b/core/components/babel/src/Plugins/Events/OnResourceDuplicate.php new file mode 100644 index 0000000..cc3f01a --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnResourceDuplicate.php @@ -0,0 +1,36 @@ +scriptProperties['newResource']; + if (!$resource || !in_array($resource->get('context_key'), $this->babel->getOption('contexts'))) { + return false; + } + + return parent::init(); + } + + /** + * Init Babel TV of duplicated resources + * @return void + */ + public function process() + { + $resource = &$this->scriptProperties['newResource']; + $this->babel->initBabelTvsRecursive($this->modx, $this->babel, $resource->get('id')); + } +} diff --git a/core/components/babel/src/Plugins/Events/OnResourceSort.php b/core/components/babel/src/Plugins/Events/OnResourceSort.php new file mode 100644 index 0000000..0765db0 --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnResourceSort.php @@ -0,0 +1,31 @@ +scriptProperties['nodesAffected']; + foreach ($nodesAffected as $node) { + $linkedResources = $this->babel->getLinkedResources($node->get('id')); + foreach ($linkedResources as $key => $id) { + if ($id === $node->get('id')) { + unset($linkedResources[$key]); + } + } + $linkedResources[$node->get('context_key')] = $node->get('id'); + $this->babel->updateBabelTv($linkedResources, $linkedResources); + } + } +} diff --git a/core/components/babel/src/Plugins/Events/OnSiteRefresh.php b/core/components/babel/src/Plugins/Events/OnSiteRefresh.php new file mode 100644 index 0000000..ea79482 --- /dev/null +++ b/core/components/babel/src/Plugins/Events/OnSiteRefresh.php @@ -0,0 +1,24 @@ +modx->getCacheManager(); + $cacheManager->refresh([ + 'babel' => [], + ]); + } +} diff --git a/core/components/babel/src/Plugins/Plugin.php b/core/components/babel/src/Plugins/Plugin.php new file mode 100644 index 0000000..5658ada --- /dev/null +++ b/core/components/babel/src/Plugins/Plugin.php @@ -0,0 +1,71 @@ +scriptProperties = &$scriptProperties; + $this->modx =& $modx; + $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/', [ + 'core_path' => $corePath + ]); + } + + /** + * Run the plugin event. + */ + public function run() + { + $init = $this->init(); + if ($init !== true) { + return; + } + + $this->process(); + } + + /** + * Initialize the plugin event. + * + * @return bool + */ + public function init() + { + return true; + } + + /** + * Process the plugin event code. + * + * @return mixed + */ + abstract public function process(); +} diff --git a/core/components/babel/src/Processors/ObjectCreateProcessor.php b/core/components/babel/src/Processors/ObjectCreateProcessor.php new file mode 100644 index 0000000..eb48513 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectCreateProcessor.php @@ -0,0 +1,106 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); + } + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } + + /** + * {@inheritDoc} + * @return string[] + */ + public function getLanguageTopics() + { + if (file_exists($this->babel->getOption('corePath') . 'lexicon/' . $this->modx->getOption('manager_language', [], 'en') . '/custom.inc.php')) { + $this->languageTopics[] = 'babel:custom'; + } + return $this->languageTopics; + } + + /** + * {@inheritDoc} + * @return bool + */ + public function beforeSave() + { + foreach ($this->required as $required) { + $value = $this->getProperty($required); + if (empty($value)) { + $this->addFieldError($required, $this->modx->lexicon('field_required')); + } + } + + $count = $this->modx->getCount($this->classKey); + $this->object->set('sortindex', $count); + + $this->clearCache(); + + return parent::beforeSave(); + } + + /** + * Clear the context and the lexicon topics cache. + */ + protected function clearCache() + { + $query = $this->modx->newQuery('modContext'); + $query->select($this->modx->escape('key')); + if ($query->prepare() && $query->stmt->execute()) { + $contextKeys = $query->stmt->fetchAll(PDO::FETCH_COLUMN); + } else { + $contextKeys = []; + } + + $this->modx->cacheManager->refresh( + [ + 'lexicon_topics' => [], + 'babel' => [], + 'resource' => ['contexts' => array_diff($contextKeys, ['mgr'])], + ] + ); + } +} diff --git a/core/components/babel/src/Processors/ObjectGetListProcessor.php b/core/components/babel/src/Processors/ObjectGetListProcessor.php new file mode 100644 index 0000000..853e751 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectGetListProcessor.php @@ -0,0 +1,125 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); + } + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } + + /** + * {@inheritDoc} + * @return string[] + */ + public function getLanguageTopics() + { + if (file_exists($this->babel->getOption('corePath') . 'lexicon/' . $this->modx->getOption('manager_language', [], 'en') . '/custom.inc.php')) { + $this->languageTopics[] = 'babel:custom'; + } + return $this->languageTopics; + } + + /** + * {@inheritDoc} + * @param xPDOQuery $c + * @return xPDOQuery + */ + public function prepareQueryBeforeCount(xPDOQuery $c) + { + $valuesQuery = $this->getProperty('valuesqry'); + $query = (!$valuesQuery) ? $this->getProperty('query') : ''; + if (!empty($query)) { + $conditions = []; + $or = ''; + foreach ($this->search as $search) { + $conditions[$or . $search . ':LIKE'] = '%' . $query . '%'; + $or = 'OR:'; + } + $c->where([$conditions]); + } + + return $c; + } + + /** + * {@inheritDoc} + * @param xPDOQuery $c + * @return xPDOQuery + */ + public function prepareQueryAfterCount(xPDOQuery $c) + { + $valuesQuery = $this->getProperty('valuesqry'); + $id = (!$valuesQuery) ? $this->getProperty('id') : $this->getProperty('query'); + if (!empty($id)) { + $c->where([ + $this->classKey . '.id:IN' => array_map('intval', explode('|', $id)) + ]); + } + + return $c; + } + + /** + * {@inheritDoc} + * @param array $list + * @return array + */ + public function beforeIteration(array $list) + { + if (!$this->getProperty('id') && $this->getBooleanProperty('combo', false)) { + $empty = [ + 'id' => 0, + $this->nameField => $this->modx->lexicon('ext_emptygroup') + ]; + $list[] = $empty; + } + + return $list; + } +} diff --git a/core/components/babel/src/Processors/ObjectProcessor.php b/core/components/babel/src/Processors/ObjectProcessor.php new file mode 100644 index 0000000..5f42fa5 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectProcessor.php @@ -0,0 +1,50 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', Babel::class, $corePath . 'model/babel/'); + } + + abstract public function process(); + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } +} diff --git a/core/components/babel/src/Processors/ObjectRemoveProcessor.php b/core/components/babel/src/Processors/ObjectRemoveProcessor.php new file mode 100644 index 0000000..383c979 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectRemoveProcessor.php @@ -0,0 +1,71 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); + } + + /** + * {@inheritDoc} + * @return bool + */ + public function afterRemove() + { + $this->clearCache(); + + return parent::afterRemove(); + } + + /** + * Clear the context and the lexicon topics cache. + */ + protected function clearCache() + { + $query = $this->modx->newQuery('modContext'); + $query->select($this->modx->escape('key')); + if ($query->prepare() && $query->stmt->execute()) { + $contextKeys = $query->stmt->fetchAll(PDO::FETCH_COLUMN); + } else { + $contextKeys = []; + } + + $this->modx->cacheManager->refresh( + [ + 'lexicon_topics' => [], + 'babel' => [], + 'resource' => ['contexts' => array_diff($contextKeys, ['mgr'])], + ] + ); + } +} diff --git a/core/components/babel/src/Processors/ObjectSortindexProcessor.php b/core/components/babel/src/Processors/ObjectSortindexProcessor.php new file mode 100755 index 0000000..4a10eb5 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectSortindexProcessor.php @@ -0,0 +1,136 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); + } + + /** + * {@inheritDoc} + * @return array|string + */ + public function process() + { + if (!$this->cleanSorting()) { + return $this->failure(); + } + + $targetId = $this->getProperty('targetId'); + $targetIndex = $this->modx->getObject($this->classKey, $targetId)->get($this->indexKey); + + // Prepare the moving ids + $movingIds = explode(',', $this->getProperty('movingIds', 0)); + $c = $this->modx->newQuery($this->classKey); + $c->where([ + 'id:IN' => $movingIds + ]); + $c->sortby($this->indexKey); + $c->sortby('id'); + /** @var xPDOObject[] $movingObjects */ + $movingObjects = $this->modx->getIterator($this->classKey, $c); + foreach ($movingObjects as $movingObject) { + $c = $this->modx->newQuery($this->classKey); + $movingIndex = $movingObject->get($this->indexKey); + if ($movingIndex < $targetIndex) { + $c->where([ + $this->indexKey . ':>' => $movingIndex, + $this->indexKey . ':<=' => $targetIndex, + ]); + } else { + $c->where([ + $this->indexKey . ':<' => $movingIndex, + $this->indexKey . ':>=' => $targetIndex, + ]); + } + $c->sortby($this->indexKey); + $c->sortby('id'); + /** @var xPDOObject[] $affectedObjects */ + $affectedObjects = $this->modx->getIterator($this->classKey, $c); + foreach ($affectedObjects as $affectedObject) { + $affectedIndex = $affectedObject->get($this->indexKey); + if ($movingIndex < $targetIndex) { + $newIndex = $affectedIndex - 1; + } else { + $newIndex = $affectedIndex + 1; + } + $affectedObject->set($this->indexKey, $newIndex); + $affectedObject->save(); + } + $movingObject->set($this->indexKey, $targetIndex); + $movingObject->save(); + } + + return $this->success(); + } + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } + + /** + * Clean the current sorting. + * + * @return bool + */ + private function cleanSorting() + { + $c = $this->modx->newQuery($this->classKey); + $c->sortby($this->indexKey); + $c->sortby('id'); + + /** @var xPDOObject[] $objects */ + $objects = $this->modx->getIterator($this->classKey, $c); + if (!$objects) { + return false; + } + + $i = 0; + foreach ($objects as $object) { + $object->set($this->indexKey, $i); + $object->save(); + $i++; + } + return true; + } +} + +return 'ConsentfriendPurposesSortindexProcessor'; diff --git a/core/components/babel/src/Processors/ObjectUpdateProcessor.php b/core/components/babel/src/Processors/ObjectUpdateProcessor.php new file mode 100644 index 0000000..da34ec4 --- /dev/null +++ b/core/components/babel/src/Processors/ObjectUpdateProcessor.php @@ -0,0 +1,103 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', 'Babel', $corePath . 'model/babel/'); + } + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } + + /** + * {@inheritDoc} + * @return string[] + */ + public function getLanguageTopics() + { + if (file_exists($this->babel->getOption('corePath') . 'lexicon/' . $this->modx->getOption('manager_language', [], 'en') . '/custom.inc.php')) { + $this->languageTopics[] = 'babel:custom'; + } + return $this->languageTopics; + } + + /** + * {@inheritDoc} + * @return bool + */ + public function beforeSave() + { + foreach ($this->required as $required) { + $value = $this->getProperty($required); + if (empty($value)) { + $this->addFieldError($required, $this->modx->lexicon('field_required')); + } + } + + $this->clearCache(); + + return parent::beforeSave(); + } + + /** + * Clear the context and the lexicon topics cache. + */ + protected function clearCache() + { + $query = $this->modx->newQuery('modContext'); + $query->select($this->modx->escape('key')); + if ($query->prepare() && $query->stmt->execute()) { + $contextKeys = $query->stmt->fetchAll(PDO::FETCH_COLUMN); + } else { + $contextKeys = []; + } + + $this->modx->cacheManager->refresh( + [ + 'lexicon_topics' => [], + 'babel' => [], + 'resource' => ['contexts' => array_diff($contextKeys, ['mgr'])], + ] + ); + } +} diff --git a/core/components/babel/src/Processors/Processor.php b/core/components/babel/src/Processors/Processor.php new file mode 100644 index 0000000..be3017c --- /dev/null +++ b/core/components/babel/src/Processors/Processor.php @@ -0,0 +1,50 @@ +modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', Babel::class, $corePath . 'model/babel/'); + } + + abstract public function process(); + + /** + * Get a boolean property. + * @param string $k + * @param mixed $default + * @return bool + */ + public function getBooleanProperty($k, $default = null) + { + return ($this->getProperty($k, $default) === 'true' || $this->getProperty($k, $default) === true || $this->getProperty($k, $default) === '1' || $this->getProperty($k, $default) === 1); + } +} diff --git a/core/components/babel/src/Snippets/BabelLinks.php b/core/components/babel/src/Snippets/BabelLinks.php new file mode 100644 index 0000000..4b42288 --- /dev/null +++ b/core/components/babel/src/Snippets/BabelLinks.php @@ -0,0 +1,171 @@ + (!empty($this->modx->resource) && is_object($this->modx->resource)) ? $this->modx->resource->get('id') : 0, + 'tpl' => 'tplBabellink', + 'wrapperTpl' => '', + 'activeCls' => 'active', + 'showUnpublished::bool' => false, + 'showCurrent::bool' => false, + 'includeUnlinked::bool' => false, + 'ignoreSiteStatus::bool' => false, + 'restrictToGroup::bool' => $this->babel->getOption('restrictToGroup'), + 'toArray::bool' => false, + 'toPlaceholder' => '', + 'outputSeparator' => "\n", + ]; + } + + /** + * Execute the hook and return the result. + * + * @return bool + * @throws /Exception + */ + public function execute() + { + $resourceId = $this->getProperty('resourceId'); + if (empty($resourceId)) { + return ''; + } + + if (!empty($this->modx->resource) && is_object($this->modx->resource) && $resourceId === $this->modx->resource->get('id')) { + $contextKeys = $this->babel->getGroupContextKeys($this->modx->resource->get('context_key'), $this->getProperty('restrictToGroup')); + $resource = $this->modx->resource; + } else { + $resource = $this->modx->getObject('modResource', $resourceId); + if (!$resource) { + return ''; + } + $contextKeys = $this->babel->getGroupContextKeys($resource->get('context_key'), $this->getProperty('restrictToGroup')); + } + + $linkedResources = $this->babel->getLinkedResources($resourceId); + $languages = $this->babel->getLanguages(); + $outputArray = []; + $this->modx->lexicon->load('babel:languages'); + foreach ($contextKeys as $contextKey) { + if (!$this->getProperty('showCurrent') && $contextKey === $resource->get('context_key')) { + continue; + } + if (!$this->getProperty('includeUnlinked') && !isset($linkedResources[$contextKey])) { + continue; + } + $context = $this->modx->getObject('modContext', ['key' => $contextKey]); + if (!$context) { + $this->modx->log(xPDO::LOG_LEVEL_ERROR, 'Could not load context: ' . $contextKey); + continue; + } + $context->prepare(); + if (!$context->getOption('site_status', null, true) && !$this->getProperty('ignoreSiteStatus')) { + continue; + } + $cultureKey = $context->getOption('cultureKey', $this->modx->getOption('cultureKey')); + $translationAvailable = false; + if (isset($linkedResources[$contextKey])) { + $c = $this->modx->newQuery('modResource'); + $c->where([ + 'id' => $linkedResources[$contextKey], + 'deleted:!=' => 1, + 'published:=' => 1, + ]); + if ($this->getProperty('showUnpublished')) { + $c->where([ + 'OR:published:=' => 0, + ]); + } + $count = $this->modx->getCount('modResource', $c); + if ($count) { + $translationAvailable = true; + } + } + $getRequest = $this->modx->request->getParameters(); + unset($getRequest['id']); + unset($getRequest[$this->modx->getOption('request_param_alias', null, 'q')]); + unset($getRequest['cultureKey']); + if ($translationAvailable) { + $url = $context->makeUrl($linkedResources[$contextKey], $getRequest, 'full'); + $active = ($resource->get('context_key') == $contextKey) ? $this->getProperty('activeCls') : ''; + $placeholders = [ + 'active' => $active, + 'contextKey' => $contextKey, + 'contextName' => $context->get('name'), + 'cultureKey' => $cultureKey, + 'id' => $linkedResources[$contextKey], + 'language' => $languages[$cultureKey]['Description'], + 'url' => $url, + ]; + + if ($this->getProperty('toArray')) { + $outputArray[] = $placeholders; + } else { + $chunk = $this->babel->parse->getChunk($this->getProperty('tpl'), $placeholders); + if (!empty($chunk)) { + $outputArray[] = $chunk; + } + } + } elseif ($this->getProperty('includeUnlinked')) { + $url = $context->makeUrl($context->getOption('site_start'), $getRequest, 'full'); + $active = ($resource->get('context_key') == $contextKey) ? $this->getProperty('activeCls') : ''; + $placeholders = [ + 'active' => $active, + 'contextKey' => $contextKey, + 'contextName' => $context->get('name'), + 'cultureKey' => $cultureKey, + 'id' => $context->getOption('site_start'), + 'language' => $languages[$cultureKey]['Description'], + 'url' => $url, + ]; + + if ($this->getProperty('toArray')) { + $outputArray[] = $placeholders; + } else { + $chunk = $this->babel->parse->getChunk($this->getProperty('tpl'), $placeholders); + if (!empty($chunk)) { + $outputArray[] = $chunk; + } + } + } + } + + if ($this->getProperty('toArray')) { + return '
' . print_r($outputArray, 1) . '
'; + } + + $output = implode($this->getProperty('outputSeparator'), $outputArray); + if (!empty($this->getProperty('wrapperTpl'))) { + $output = $this->babel->parse->getChunk($this->getProperty('wrapperTpl'), [ + 'babelLinks' => $output + ]); + } + + if (!empty($this->getProperty('toPlaceholder'))) { + $this->modx->setPlaceholder($this->getProperty('toPlaceholder'), $output); + return ''; + } + + return $output; + } +} diff --git a/core/components/babel/src/Snippets/BabelTranslation.php b/core/components/babel/src/Snippets/BabelTranslation.php new file mode 100644 index 0000000..c7fc917 --- /dev/null +++ b/core/components/babel/src/Snippets/BabelTranslation.php @@ -0,0 +1,68 @@ + (!empty($this->modx->resource) && is_object($this->modx->resource)) ? $this->modx->resource->get('id') : 0, + 'contextKey' => '', + 'cultureKey' => $this->modx->getOption('cultureKey'), + 'showUnpublished::bool' => false + ]; + } + + /** + * Execute the snippet and return the result. + * + * @return string + * @throws /Exception + */ + public function execute() + { + $resourceIds = $this->getProperty('resourceId'); + if (empty($resourceIds)) { + return ''; + } + + $resourceIds = array_map('trim', explode(',', $resourceIds)); + $contextKey = $this->getProperty('contextKey'); + if (empty($contextKey)) { + $cultureKey = $this->getProperty('cultureKey'); + $contextKey = $this->babel->getContextKey($cultureKey); + } + $showUnpublished = $this->getProperty('showUnpublished'); + + /* determine ids of translated resource */ + $output = []; + foreach($resourceIds as $resourceId) { + $linkedResource = $this->babel->getLinkedResources($resourceId); + if (isset($linkedResource[$contextKey])) { + /** @var modResource $resource */ + $resource = $this->modx->getObject('modResource', $linkedResource[$contextKey]); + if ($resource && ($showUnpublished || $resource->get('published') == 1)) { + $output[] = $resource->get('id'); + } + } + } + return implode(',', $output); + } +} diff --git a/core/components/babel/src/Snippets/Snippet.php b/core/components/babel/src/Snippets/Snippet.php new file mode 100644 index 0000000..2839a72 --- /dev/null +++ b/core/components/babel/src/Snippets/Snippet.php @@ -0,0 +1,163 @@ +modx =& $modx; + + $corePath = $this->modx->getOption('babel.core_path', null, $this->modx->getOption('core_path') . 'components/babel/'); + $this->babel = $this->modx->getService('babel', Babel::class, $corePath . 'model/babel/', [ + 'core_path' => $corePath + ]); + + $this->properties = $this->initProperties($properties); + } + + /** + * Get default snippet properties. + * + * @return array + */ + public function getDefaultProperties() + { + return []; + } + + /** + * @param array $properties + * @return array + */ + public function initProperties(array $properties = []) + { + $result = []; + foreach ($this->getDefaultProperties() as $key => $value) { + $parts = explode('::', $key); + $key = ($this->propertyPrefix && !in_array('noPrefix', $parts)) ? $this->propertyPrefix . ucfirst($parts[0]) : $parts[0]; + if (isset($parts[1]) && method_exists($this, 'get' . ucfirst($parts[1]))) { + if (isset($parts[2])) { + $result[$parts[0]] = $this->{'get' . ucfirst($parts[1])}($this->modx->getOption($key, $properties, $value, true), $parts[2]); + } else { + $result[$parts[0]] = $this->{'get' . ucfirst($parts[1])}($this->modx->getOption($key, $properties, $value, true)); + } + } else { + $result[$parts[0]] = $this->modx->getOption($key, $properties, $value, true); + } + if ($this->propertyPrefix) { + unset($properties[$key]); + } + unset($properties[$parts[0]]); + } + return array_merge($result, $properties); + } + + /** + * @param $value + * @return int + */ + protected function getInt($value) + { + return (int)$value; + } + + /** + * @param $value + * @return bool + */ + protected function getBool($value) + { + return ($value == 1 || $value == '1' || $value == true || $value == 'true'); + } + + /** + * @param $value + * @return array|null + */ + protected function getAssociativeJson($value) + { + return (is_string($value)) ? json_decode($value, true) : $value; + } + + /** + * Explode a separated value to an array. + * + * @param mixed $value + * @param string $separator + * @return array + */ + protected function getExplodeSeparated($value, $separator = ',') + { + return (is_string($value) && $value !== '') ? array_map('trim', explode($separator, $value)) : []; + } + + /** + * Get the snippet properties. + * + * @return array + */ + public function getProperties() + { + return $this->properties; + } + + /** + * Get a snippet property value or the default value. + * + * @param string $key + * @param null $default + * @return mixed + */ + public function getProperty(string $key, $default = null) + { + if (isset($this->properties[$key])) { + return $this->properties[$key]; + } + return $default; + } + + abstract public function execute(); +} diff --git a/core/components/babel/templates/default/index.tpl b/core/components/babel/templates/default/index.tpl deleted file mode 100644 index 1cbd957..0000000 --- a/core/components/babel/templates/default/index.tpl +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/assets/components/babel/css/cmp.css b/core/components/babel/templates/index.tpl similarity index 100% rename from assets/components/babel/css/cmp.css rename to core/components/babel/templates/index.tpl diff --git a/docs/contributors.md b/docs/contributors.md new file mode 100755 index 0000000..f7c6947 --- /dev/null +++ b/docs/contributors.md @@ -0,0 +1,8 @@ +The Babel project was started in 2010 by [Jakob +Class](https://github.com/mikrobi). It was improved further by [Rico +Goldsky](https://github.com/goldsky), [Joshua +Luckers](https://github.com/JoshuaLuckers) and [Thomas +Jakobi](https://github.com/Jako). + +Many thanks to all who contributed, whether by creating pull requests, +submitting bug reports, or donating. diff --git a/docs/index.md b/docs/index.md new file mode 100755 index 0000000..4105cf6 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,36 @@ +# Babel + +Babel is an Extra for MODx Revolution that helps you to manage your multilingual +websites using different contexts. Babel even supports managing several +different multilingual websites within one MODx instance by using so-called +context groups. + +Babel maintains links between translated resources. In the manager you can use +the Babel Box to easily switch between the different language versions of your +resources. Translations can be created automatically by Babel or defined +manually. + +Additionally, Babel can be used to synchronize certain template variables (TVs) +of translated resources which should be the same in every context (language). + +### Requirements + +* MODX Revolution 2.8+ +* PHP 7.2+ + +### Features + +* Babel Button on the resource page for creating, linking and updating + translated resources in different contexts +* Custom manager page for maintaining links between translated resources +* Snippet for displaying links between the translated resources +* Snippet for retrieving the ID of a translated resource in a given context + +### License + +The project is licensed under the [GPLv2 license](https://github.com/mikrobi/babel/LICENSE.md). + +### Translations [![Default Lexicon](https://hosted.weblate.org/widget/modx-extras/babel/standard/svg-badge.svg)](https://hosted.weblate.org/projects/modx-extras/babel/) + +Translations of the package can be made for the [Default Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/standard/), the [Permissions Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/permissions/), the [Properties Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/properties/) and the [System Settings Lexicon](https://hosted.weblate.org/projects/modx-extras/babel/system-settings/) + diff --git a/docs/installation.md b/docs/installation.md new file mode 100755 index 0000000..d9ffb23 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,23 @@ +## Install from MODX Extras + +Search for Babel in the Package Manager of your MODX +installation and install it in there. + +## Manual installation + +If you can't access the MODX Extras Repository in your MODX installation, you +can manually install Babel. + +* Download the transport package from [MODX Extras](https://modx.com/extras/package/babel) (or one of the pre built transport packages in [_packages](https://github.com/sergant210/Babel/tree/master/_packages)) +* Upload the zip file to your MODX installation's `core/packages` folder or upload it manually in the MODX Package Manager. +* In the MODX Manager, navigate to the Package Manager page, and select 'Search locally for packages' from the dropdown button. +* Babel should now show up in the list of available packages. Click the corresponding 'Install' button and follow the instructions to complete the installation. + +## Build it from source + +To build and install the package from source you could use [Git Package +Management](https://github.com/TheBoxer/Git-Package-Management). The GitHub +repository of Babel contains a +[config.json](https://github.com/sergant210/Babel/blob/master/_build/config.json) +to build that package locally. Use this option, if you want to debug +Babel and/or contribute bugfixes and enhancements. diff --git a/docs/usage/img/babel-cmp-contexts.png b/docs/usage/img/babel-cmp-contexts.png new file mode 100644 index 0000000..d470a7a Binary files /dev/null and b/docs/usage/img/babel-cmp-contexts.png differ diff --git a/docs/usage/img/babel-cmp-settings.png b/docs/usage/img/babel-cmp-settings.png new file mode 100644 index 0000000..56bcd67 Binary files /dev/null and b/docs/usage/img/babel-cmp-settings.png differ diff --git a/docs/usage/img/babel-linked-menu.png b/docs/usage/img/babel-linked-menu.png new file mode 100644 index 0000000..bf2590b Binary files /dev/null and b/docs/usage/img/babel-linked-menu.png differ diff --git a/docs/usage/img/babel-linking-window.png b/docs/usage/img/babel-linking-window.png new file mode 100644 index 0000000..e88b538 Binary files /dev/null and b/docs/usage/img/babel-linking-window.png differ diff --git a/docs/usage/img/babel-unlinked-menu.png b/docs/usage/img/babel-unlinked-menu.png new file mode 100644 index 0000000..216c53f Binary files /dev/null and b/docs/usage/img/babel-unlinked-menu.png differ diff --git a/docs/usage/img/context_access.png b/docs/usage/img/context_access.png new file mode 100644 index 0000000..1afdc2f Binary files /dev/null and b/docs/usage/img/context_access.png differ diff --git a/docs/usage/img/context_settings.png b/docs/usage/img/context_settings.png new file mode 100644 index 0000000..3e7384b Binary files /dev/null and b/docs/usage/img/context_settings.png differ diff --git a/docs/usage/img/create_contexts.png b/docs/usage/img/create_contexts.png new file mode 100644 index 0000000..df4b6c3 Binary files /dev/null and b/docs/usage/img/create_contexts.png differ diff --git a/docs/usage/index.md b/docs/usage/index.md new file mode 100755 index 0000000..69e6675 --- /dev/null +++ b/docs/usage/index.md @@ -0,0 +1,123 @@ +Babel contains a Babel Button, a custom manager page and two snippets. + +## Babel Button + +The Babel Button is located on the top of a resource form. With this button +you can create, link and update translated versions of the current resource in +different contexts. + +Hover the button and create, link, update and unlink the translated versions of +the current resource. + +![Linked Menu](img/babel-linked-menu.png) + +![Unlinked Menu](img/babel-unlinked-menu.png) + +If you create a link to an existing resource, the following window is displayed. +You must select the linked resource via the page tree on the left, by searching +for the page title or by entering the target ID directly. + +![Linking Window](img/babel-linking-window.png) + +## Custom Manager Page + +The custom manager page contains two tabs. + +### Contexts + +In this tab you can manage the translated versions of a resource. The first +columns contain information of the source resource (ID, context and pagetitle) +and an `All` column to remove all links to the source resource with a click on +the :fontawesome-solid-link-slash: icon. For each translatable context a grid +column is available with two icons. The following icons are available depending +on the link state: + +- :fontawesome-solid-circle-plus: to create a new resource to be linked, +- :fontawesome-solid-link: to link to this resource and its linked resources +- :fontawesome-regular-pen-to-square: to update the linked resource +- :fontawesome-solid-link-slash: to break the link + +![Contexts Tab](img/babel-cmp-contexts.png) + +### Settings + +In this tab you can manage the system settings of Babel. The Tab is only shown +for users that have the babel_settings or settings permission. + +![Settings Tab](img/babel-cmp-settings.png) + +## Snippets + +Currently, there are two snippets available for Babel: + +### BabelLinks + +BabelLinks is a snippet that displays links to other languages (contexts) in the +frontend. It uses the following snippet properties: + +| Property | Description | Default | +|------------------|-------------------------------------------------------------------------------------|----------------------------------------| +| activeCls | CSS class for the active language link. | active | +| ignoreSiteStatus | Flag whether to ignore the site_status (when the site is offline) | 0 (No) | +| includeUnlinked | Flag whether to show unlinked context. | 0 (No) | +| resourceId | Id of resource of which links to translations should be displayed. | Current resource ID | +| restrictToGroup | Restrict the contexts in the snippet output to the group of the current context. | System setting `babel.restrictToGroup` | +| showCurrent | Flag whether to show a link to a translation of the current language. | 0 (No) | +| showUnpublished | Flag whether to show unpublished translations. | 0 (No) | +| toArray | Flag whether to dump the output as an array instead. | 0 (No) | +| toPlaceholder | Flag whether to dump the output into the given placeholder's name. | - | +| tpl | Chunk to display a language link. | tplBabellink | +| wrapperTpl | Chunk to wrap all language links. The placeholder for all links is [[+babelLinks]]. | - | + +You can use the following placeholders in the tpl chunk: + +| Placeholder | Description | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| active | If link points to a resource of the current active language (context) this placeholder is set to the active CSS class name specified by the activeCls property. Otherwise this placeholder is empty. | +| contextKey | Context key of the translated resource. | +| contextName | Context name of the translated resource | +| cultureKey | Culture key of the translated resource (e.g en, de, fr oder es). You may use the babel lexicon to display the language's name: ```[[%babel.language_[[+cultureKey]]? &topic=`languages` &namespace=`babel`]]``` | +| id | ID of tranlated resource. If no translation is available this placeholder is empty ('') | +| language | Language description in the IANA language subtag registry | +| url | Url to linked translation (or site_url of specific language if there is no translated resource available). | + +### BabelTranslation + +The BabelTranslation snippets returns the ID of a translated resource in a +given context. It uses the following snippet properties: + +| Property | Description | Default | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------| +| contextKey | Key of context in which translated resource should be determined. | - | +| cultureKey | Key of culture in which translated resource should be determined. Used only in case contextKey was not specified. If both omitted the snippet the currently set cultureKey. | - | +| resourceId | ID of resource of which a translated resource should be determined. | Current resource ID | +| showUnpublished | Flag whether to show unpublished translations. | 0 (No) | + +## System Settings + +Babel uses the following system settings in the namespace `babel`: + +| Key | Name | Description | Default | +|-----------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------|--------------------| +| babel.babelTvName | Babel TV Name | Name of template variable (TV) in which Babel will store the links between multilingual resources. This TV will be maintained by Babel. | babelLanguageLinks | +| babel.contextKeys | Context Keys | Comma separated list of context keys which should be used to link multilingual resources. | - | +| babel.debug | Debug | Log debug information in the MODX error log. | No | +| babel.displayText | Button Text | Text shown in the Babel button for each context. You can use the following values: language, context, combination | language | +| babel.restrictToGroup | Restrict To Group | Restrict the contexts in the Babel button to the group of the current context. | Yes | +| babel.syncTvs | Synchronized TVs | Comma separated list of template variables (TVs) IDs to be synchronised by Babel. | - | + +The button text in the Babel button can use the following values: + +- language: the contexts are listed with the context language set in the cultureKey context setting. +- context: the contexts are listed with the context name. +- combination: the contexts are listed with the context name and the context language set in the cultureKey context setting. + +## Permissions + +Babel has the following permissions for manager users: + +| Permission | Description | +|----------------|---------------------------------------------------------------------------------| +| babel_settings | Allow a user to manage the Babel system settings the Babel custom manager page. | + +The permission check is not executed for sudo users. diff --git a/docs/usage/tutorial-seo.md b/docs/usage/tutorial-seo.md new file mode 100755 index 0000000..febebaf --- /dev/null +++ b/docs/usage/tutorial-seo.md @@ -0,0 +1,268 @@ +## SEO Friendly Multilingual Websites with MODx and Babel + +!!! caution "This is old!" + + This tutorial is a slightly modernized version of the [old blog + entry](https://web.archive.org/web/20180927220103/http://www.multilingual-modx.com/blog/2011/seo-friendly-multilingual-websites-with-modx-and-babel.html) + on multilingual-modx.com which is available only in the WaybackMachine. It uses + a routing plugin for easier maintaining the contexts. The links in the + text are updated to actual or to WaybackMachine versions. + +In my [previous article](tutorial.md) about setting up multilingual websites +with MODx and Babel I described a solution which is based on different +(sub)domains for each language. This domain based approach is implemented easily +but has some drawbacks in a SEO point of view: By using different domains for +each language you automatically split up your site into several single sites. +Each site will be handled separately by search engines. For example, they won't +share the same page rank and backlinks. Using one domain and subfolders for each +language may improve your site's overall ranking: All backlinks are connected to +your top level domain. In this article I'll describe a possible solution of how +to set up a multilingual website with MODx and Babel by using one domain and +subfolders for each language. + +This article doesn't focus on the SEO point of view. It's rather a technical +tutorial of how to set up a multilingual website by using subfolders. If you'd +like to read more about the "(sub)domains vs. subfolders" topic you may search +the web (there are a lot of articles about this topic) or read some of the +following posts of other blogs: + +- [Subfolders v/s Subdomains: Which one to choose for SEO?](https://web.archive.org/web/20150810025806/http://seohawk.com/subfolders-subdomains-seo) +- [Subdomains or Subfolders : Which are Better for SEO?](https://www.searchenginejournal.com/subdomains-vs-subfolders-seo/239795/) +- [Subdomains, Subfolders and Top-Level Domains](https://www.mattcutts.com/blog/subdomains-and-subdirectories/) +- [Subdomains and subdirectories](https://moz.com/blog/subdomains-subfolders-and-toplevel-domains) + +### Technical Background + +I'll describe the procedure of setting up the multilingual site by providing a +fictional example site _https://​www.​example.com_. The main website is reachable via +_https://​www.​example.com_ and is available in two languages: + +- German: _https://​www.​example.com/de/_ +- English: _http://​www.​example.com/en/_ + +For each language we are using one context: _web_ for German, _en_ for English. + +### Prerequisites + +Before starting with this tutorial you should be sure that **all** requirements +for a multilingual site are satisfied: + +- Friendly URLs are enabled: friendly_urls and use_alias_path are set to yes (1) +- The Apache rewrite engine is activated and the rewrite base is set correctly: + + ``` + RewriteEngine On + RewriteBase / + ``` + +- If you're running your site in a non-root directory like /subfolder/mysite/xy you have to define your rewrite base like this: + + ``` + RewriteBase /subfolder/mysite/xy/ + ``` + +- The base URL is set via the Tag in your HTML head of all your templates: + + ``` + + ... + + ... + + ``` + +### Step-by-Step Instructions + +You have to follow the five steps described in my previous article about setting +up multilingual websites and one additional step: + +1. Create your contexts for each language: no differences to domain based approach. +2. Configure language specific settings of all your contexts: `site_url`, `cultureKey` **and** `base_url`.
+ + | context | site_url | cultureKey | base_url | + |---------|-------------------------------|------------|----------| + | web | https://​www.​example.com/de/ | de | /de/ | + | en | https://​www.​example.com/en/ | en | /en/ | + + !!! caution "Differences to the non SEO version" + + Instead of using different domains in the `site_url` context setting you have to + use subfolders and additionally specifiy the `base_url` according to the context's + `cultureKey`. + + !!! hint + + You should also define settings like `site_start` `error_page` etc. for each of + your contexts. To maintain this entries a lot easier you can use the MODX Extra + [CrossContextsSettings](https://extras.modx.com/package/crosscontextssettings). + +3. Grant the _"Load Only"_ access policy for all your contexts to the _anonymous_ + group: no differences to domain based approach. +4. Install a routing extra from the MODX repository, i.e. SmartRouting, xRouting + or LangRouter via the MODX package management +5. Install the Babel Extra via package management: no differences to domain based approach. +6. Change existing rewrite rules for friendly URLs and add additional rules to your .htaccess file (see next section for detailed description): + + ``` + # redirect all requests to /en/favicon.ico and /de/favicon.ico + # to /favicon.ico + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(en|de)/favicon.ico$ favicon.ico [L,QSA] + + # redirect all requests to /en/assets* and /de/assets* to /assets* + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(en|de)/assets(.*)$ assets$2 [L,QSA] + ``` + +### Rewrite Rules + +If you don't add the rewrite rules above to your .htaccess file the pages are +still accessible via the language subfolders and linking your pages with relative +links should work. + +But there would be a problem regarding relative links: linking assets like CSS, +JavaScripts, images etc. won't work properly. Normally all these files are +located somewhere in the assets subfolder of your MODx root directory. When +including an asset via a relative URL like _assets/css/style.css_ the asset won't +be found: + +1. The browser will try to request something like + _https://​www.​example.com/en/assets/css/style.css_ because the site's URL + _https://​www.​example.com/en/_ (defined via the `site_url` context setting in step + 2) is used to handle relative URLs. +2. The rewrite rule from above will be applied and the request will be + internally forwarded to + _https://​www.​example.com/index.php?cultureKey=en&q=assets/css/style.css_ +3. MODx won't find any resource matching the alias _assets/css/style.css_ and will + return a 404 error code. + +To solve this problem you have to add another rewrite rule before +the rule from above which internally redirects all request to _/[ck]/assets/*_ to +_/assets/*_ where _[ck]_ is a valid culture key: + +``` +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(en|de)/assets(.*)$ assets$2 [L,QSA] +``` + +Fine! Now you can use relative links for your pages and assets. Including images +with TinyMCE should work, too. + +You may want to add some additional rewrite rules for other files which are +being referred via relative URLs. For example the _favicon.ico_ in your root +directory: + +``` +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(en|de)/favicon.ico$ favicon.ico [L,QSA] +``` + +!!! hint "Other languages" + + If you're using other languages than German and English you have to change the + _(en|de)_ part of the rewrite rule according to your needs. For example for a + website available in English, Spanish and French you can use the following favicon + rewrite rule: + + ``` + RewriteRule ^(en|es|fr)/favicon.ico$ favicon.ico [L,QSA] + ``` + +Additionally, the server can automatically determine the language when the domain +root _https://​www​.example.com/_ is requested and perform a redirect to the +suitable language version in the following way: + +- When the accepted language is not German _(de)_ and the root has been + requested (relative request URI is empty) redirect to the English version + _(en)_: see first condition and rewrite rule from below (line 2 and 3). +- Otherwise, redirect to German version _(de)_ when the root has been requested: + see second rewrite rule from below (line 4). + +``` +# detect language when requesting the root (/) +RewriteCond %{HTTP:Accept-Language} !^de [NC] +RewriteRule ^$ en/ [R=301,L] +RewriteRule ^$ de/ [R=301,L] +``` + +!!! hint + + That's very rudimentary. The condition only checks whether the value of + the _Accept-Language_ HTTP header variable begins with the language (culture) key. + But this variable contains much more than only a language key: It's a list of + preferred (or even non-preferred) keys like this: _Accept-Language: + de-de,de;q=0.8,en-us;q=0.5,en;q=0.3_. The _q_ variable specifies the importance of + the language from 0 to 1. Detecting the language with PHP in the gateway plugin + is much better. But this is not the topic of this article and will be discussed + in another post. + +Ok now all rules and conditions can be added to your _.htaccess_ file. It's **very +important** to place them in the right order before `# The Friendly URLs part` +because Apache goes through the rules from top to bottom: + +``` +# detect language when requesting the root (/) +RewriteCond %{HTTP:Accept-Language} !^de [NC] +RewriteRule ^$ en/ [R=301,L] +RewriteRule ^$ de/ [R=301,L] + +# redirect all requests to /en/favicon.ico and /de/favicon.ico +# to /favicon.ico +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(en|de)/favicon.ico$ favicon.ico [L,QSA] + +# redirect all requests to /en/assets* and /de/assets* to /assets* +RewriteCond %{REQUEST_FILENAME} !-d +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^(en|de)/assets(.*)$ assets$2 [L,QSA] +``` + +If you'd like to go deeper into defining rewrite rules you should read more +about the [Apache mod_rewrite module](https://httpd.apache.org/docs/2.2/mod/mod_rewrite.html). + +### Is this approach optimal? + +This solution works fine and editors can work as they did before without caring about relative links and subfolders. But I think this approach is rather a workaround than an optimal solution: + +- When linking assets relatively you link to non-existing "virtual" files. +- By applying the rewrite rules for the assets the same file is served via + several different URLs: _https://​www.​example.com/assets/css/style.css_, + _https://​www.​example.com/de/assets/css/style.css_ and + _https://​www.​example.com/en/assets/css/style.css_ return the same content. +- Files which are used in all language versions are not cached for the whole + site by your browser: The browser doesn't know that + _https://​www.​example.com/de/assets/css/style.css_ and + _https://​www.​example.com/en/assets/css/style.css_ are the same. +- When working with the GoogleSiteMap Extra you won't be able to serve a + sitemap.xml for your whole site without modifying the Extra manually. This is + because your documents are distributed over several contexts and GoogleSiteMap + is only capable of creating a sitemap for one context. XML sitemaps are very + helpful to tell a search engine bot where to find all your pages. So you + should use them, and they should list all pages of your site! + +!!! Caution + + The following section is outdated and will not take place in this form. + +### The optimal approach: Babel 2.3! + +In my opinion the "cleanest" way to manage a multilingual website would be using +one single context for the whole site and placing your documents into resource +containers for each language. At the moment Babel doesn't support this approach. +But I have already developed a concept of how to change and extend Babel to be +able to use the Extra for both approaches: domain based and subfolder based. + +Therefore, I'll introduce an additional level of abstraction into the Babel's +architecture which will make it possible to run Babel in domain-based or +subfolder-based mode. The look and feel will remain the same and the new version +should be compatible with older ones. + +I'll need to change a lot of code, and currently I'm working on some other +(paid) projects, too. + +I hope you like my plans and I appreciate your feedback! diff --git a/docs/usage/tutorial.md b/docs/usage/tutorial.md new file mode 100755 index 0000000..b9c9135 --- /dev/null +++ b/docs/usage/tutorial.md @@ -0,0 +1,104 @@ +## Multilingual Websites with MODx and Babel + +!!! caution "This is old!" + + This tutorial is a slightly modernized version of the [old blog + entry](https://web.archive.org/web/20181010174256/http://www.multilingual-modx.com/blog/2011/multilingual-websites-with-modx-and-babel.html) + on multilingual-modx.com which is available only in the WaybackMachine. It uses + a routing plugin for easier maintaining the contexts. The links in the + text are updated to actual or to WaybackMachine versions. + +In the [official documentation](https://mikrobi.github.io/babel/) of the Babel +Extra I’ve only provided a short summary of how to set up your MODx contexts for +a multilingual website and referred to an outdated tutorial. Many Babel users +contacted me or posted an issue on [GitHub](https://github.com/Jako/Babel) +because they had some troubles with Babel. Most of these troubles were not +related to Babel itself but have been caused by setting up the contexts +incorrectly. With this small tutorial I want to support you in configuring your +multilingual websites with MODx and Babel. + +!!! important + + I've described a more SEO-friendly approach in a [new + article](tutorial-seo.md) which you may want to read, too. + +First of all I want to thank [digital butter](https://www.butter.com.hk/) for +their great +[tutorial](https://web.archive.org/web/20150402201647/http://www.butter.com.hk/blog/posts/2010/08/internationalization-in-modx-revolution.html) +which explains how to set up a multilingual website with MODx. I referred to +their tutorial in the official documentation. However, since there have been +made some changes to the access control system of MODx you have to apply some +more steps to set up your multilingual website correctly. + +In this article I’ll simply list all the steps necessary to set up your +multilingual site in a very basic way. I won’t provide as many details as the +guys from digital butter did. There are already some helpful resources available +on the web where you can obtain additional information: + +- [Tutorial of digital butter](https://web.archive.org/web/20150402201647/http://www.butter.com.hk/blog/posts/2010/08/internationalization-in-modx-revolution.html) +- [Thread in the old MODX forum](https://forums.modx.com/index.php?action=thread&thread=52869&i=1) + +### Step-by-Step Instructions + +Ok. If you have worked through the documents listed above and installed a new +clean MODx environment you should be ready to set up your multilingual website. + +I’ll go through all the necessary steps by configuring an example website which +will be available in three languages: _English_, _German_ and _French_. The English +site will be available via _www.​example.com_ the German site via _www.​example.de_ +and the French one via _www.​example.fr_. + +1. Create your contexts for each language:
The default _web_ context will + be used for the English site, a _de_ context for the German and a _fr_ context for + the French site: + + ![Create a context for each language](img/create_contexts.png) + +2. Configure language specific settings of all your contexts: `site_url` and `cultureKey`.
+ - **web context:** `site_url`: https://​www.​example.com, `cultureKey`: en + - **de context:** `site_url`: https://​www.​example.de, `cultureKey`: de + - **fr context:** `site_url`: https://​www.​example.fr, `cultureKey`: fr + + ![Create language specific settings for each context](img/context_settings.png) + +3. Grant the _"Load Only"_ access policy for all your contexts to the _anonymous_ + group to let your users load the contexts. + + ![Grant access to contexts](img/context_access.png) + +4. Install a routing extra from the MODX repository, i.e. SmartRouting, xRouting + or LangRouter via the MODX package management + +5. Install the Babel Extra via package management. + +Now you should be able to create documents and link translations via Babel in +your MODx manager. For information about how to use the MODx lexicon feauture +you may take a look at the [tutorial at digital +butter](https://web.archive.org/web/20150402201647/http://www.butter.com.hk/blog/posts/2010/08/internationalization-in-modx-revolution.html) +or [official documentation](https://mikrobi.github.io/babel/). + +### Common Mistakes + +In order to avoid mistakes during setting up your contexts here are some common +mistakes which have been made by users who requested my help: + +- **Babel does not display the correct language of a context**
+ You may have forgotten to configure the cultureKey setting in the specific context. Babel uses this setting to determine the language of a context. + +- **Babel does not display all links to translated documents in the front-end**
+ You may have forgotten to grant the "Load Only" access policy for your visitors to the specific contexts. Or you may have forgotten to flush the permissions. + +- **The site is always displayed in the same language** + Check your routing plugin and make sure it works properly. + +### Further Help + +!!! important + + I've described a more SEO-friendly approach in a new article which you may want to read, too. + +If you’re still having problem regarding your multilingual site and Babel have a +look at the [closed issues](https://github.com/mikrobi/babel/issues/closed) on +GitHub. If you can’t find a solution there, feel free to [post a new +issue](https://github.com/mikrobi/babel/issues). We try to help you and +incorporate your feedback to improve Babel. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..a58d9d6 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,113 @@ +const gulp = require('gulp'), + autoprefixer = require('autoprefixer'), + composer = require('gulp-uglify/composer'), + concat = require('gulp-concat'), + cssnano = require('cssnano'), + footer = require('gulp-footer'), + format = require('date-format'), + header = require('gulp-header'), + postcss = require('gulp-postcss'), + rename = require('gulp-rename'), + replace = require('gulp-replace'), + sass = require('gulp-sass')(require('sass')), + uglifyjs = require('uglify-js'), + uglify = composer(uglifyjs, console), + pkg = require('./_build/config.json'); + +const banner = '/*!\n' + + ' * <%= pkg.name %> - <%= pkg.description %>\n' + + ' * Version: <%= pkg.version %>\n' + + ' * Build date: ' + format("yyyy-MM-dd", new Date()) + '\n' + + ' */'; +const year = new Date().getFullYear(); + +const mgrScripts = [ + 'source/js/mgr/babel.js', +]; + +const scriptsMgr = function () { + return gulp.src([ + 'source/js/mgr/babel.js', + 'source/js/mgr/helper/combo.js', + 'source/js/ux/LockingGridView/LockingGridView.js', + 'source/js/mgr/widgets/resourcematrix.grid.js', + 'source/js/mgr/widgets/home.panel.js', + 'source/js/mgr/widgets/settings.panel.js', + 'source/js/mgr/sections/index.js' + ]) + .pipe(concat('babel.min.js')) + .pipe(uglify()) + .pipe(header(banner + '\n', {pkg: pkg})) + .pipe(gulp.dest('assets/components/babel/js/mgr/')) +}; +const scriptsResourcebutton = function () { + return gulp.src([ + 'source/js/mgr/babel.js' + ]) + .pipe(concat('resourcebutton.min.js')) + .pipe(uglify()) + .pipe(header(banner + '\n', {pkg: pkg})) + .pipe(gulp.dest('assets/components/babel/js/mgr/')) +}; +gulp.task('scripts', gulp.series(scriptsMgr, scriptsResourcebutton)); + +const sassMgr = function () { + return gulp.src([ + 'source/sass/mgr/babel.scss', + ]) + .pipe(sass().on('error', sass.logError)) + .pipe(postcss([ + autoprefixer() + ])) + .pipe(gulp.dest('source/css/mgr/')) + .pipe(concat('babel.css')) + .pipe(postcss([ + cssnano({ + preset: ['default', { + discardComments: { + removeAll: true + } + }] + }) + ])) + .pipe(rename({ + suffix: '.min' + })) + .pipe(footer('\n' + banner, {pkg: pkg})) + .pipe(gulp.dest('assets/components/babel/css/mgr/')) +}; +gulp.task('sass', gulp.series(sassMgr)); + +const bumpCopyright = function () { + return gulp.src([ + 'core/components/babel/model/babel/babel.class.php', + 'core/components/babel/src/Babel.php', + ], {base: './'}) + .pipe(replace(/Copyright 2010(-\d{4})? by/g, 'Copyright ' + (year > 2010 ? '2010-' : '') + year + ' by')) + .pipe(gulp.dest('.')); +}; +const bumpVersion = function () { + return gulp.src([ + 'core/components/babel/src/Babel.php', + ], {base: './'}) + .pipe(replace(/version = '\d+\.\d+\.\d+[-a-z0-9]*'/ig, 'version = \'' + pkg.version + '\'')) + .pipe(gulp.dest('.')); +}; +const bumpAbout = function () { + return gulp.src([ + 'source/js/mgr/babel.js', + ], {base: './'}) + .pipe(replace(/© 2010(-\d{4})?/g, '© ' + (year > 2010 ? '2010-' : '') + year)) + .pipe(gulp.dest('.')); +}; +gulp.task('bump', gulp.series(bumpCopyright, bumpVersion, bumpAbout)); + +gulp.task('watch', function () { + // Watch .js files + gulp.watch(['./source/js/**/*.js'], gulp.series('scripts')); + // Watch .scss files + gulp.watch(['./source/sass/**/*.scss'], gulp.series('sass')); +}); + +// Default Task +gulp.task('default', gulp.series('bump', 'scripts', 'sass')); diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..f42c97f --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,59 @@ +site_name: Babel +docs_dir: docs +site_dir: _build/site +edit_uri: tree/master/docs + +repo_name: 'Jako/Babel' +repo_url: https://github.com/Jako/Babel + +copyright: '© 2010-2024 Jakob Class' + +nav: +- Description: 'index.md' +- Installation: 'installation.md' +- Usage: + - 'usage/index.md' + - Multilingual Websites with MODX and Babel: 'usage/tutorial.md' + - SEO Friendly Multilingual Websites with MODX and Babel: 'usage/tutorial-seo.md' +- Contributors: 'contributors.md' + +extra: + analytics: + provider: matomo + url: matomo.treehillstudio.com + site: 40 + social: + - icon: fontawesome/brands/modx + link: https://modx.com/extras/package/babel + +theme: + name: material + custom_dir: ../../mkdocs-material-jako/material + + # 404 page + static_templates: + - 404.html + + language: de + font: false + features: + - navigation.indexes + - navigation.instant + - navigation.top + +markdown_extensions: + - footnotes + - tables + - admonition + - meta + - toc + - pymdownx.details + - pymdownx.superfences + - attr_list + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + +plugins: + - glightbox + - search diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8323efa --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5611 @@ +{ + "name": "babel", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "babel", + "devDependencies": { + "autoprefixer": "^10.4.16", + "cssnano": "^6.0.3", + "date-format": "^4.0.14", + "gulp": "^4.0.2", + "gulp-concat": "^2.6.1", + "gulp-footer": "^2.1.0", + "gulp-header": "^2.0.9", + "gulp-postcss": "^9.0.1", + "gulp-rename": "^2.0.0", + "gulp-replace": "^1.1.4", + "gulp-sass": "^5.1.0", + "gulp-uglify": "^3.0.2", + "postcss": "^8.4.33", + "sass": "^1.69.7", + "uglify-js": "^3.17.4" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/expect": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz", + "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz", + "integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/vinyl": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.11.tgz", + "integrity": "sha512-vPXzCLmRp74e9LsP8oltnWKTH+jBwt86WgRUb4Pc9Lf3pkMVGyvIo2gm9bODeGfCay2DBB/hAWDuvf07JcK4rw==", + "dev": true, + "dependencies": { + "@types/expect": "^1.20.4", + "@types/node": "*" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "dev": true, + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "dev": true, + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001576", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz", + "integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", + "dev": true + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", + "dev": true, + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dev": true, + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/css-declaration-sorter": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz", + "integrity": "sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.3.tgz", + "integrity": "sha512-MRq4CIj8pnyZpcI2qs6wswoYoDD1t0aL28n+41c1Ukcpm56m1h6mCexIHBGjfZfnTqtGSSCP4/fB1ovxgjBOiw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^6.0.3", + "lilconfig": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.3.tgz", + "integrity": "sha512-4y3H370aZCkT9Ev8P4SO4bZbt+AExeKhh8wTbms/X7OLDo5E7AYUUy6YPxa/uF5Grf+AJwNcCnxKhZynJ6luBA==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^7.1.1", + "cssnano-utils": "^4.0.1", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.0.2", + "postcss-convert-values": "^6.0.2", + "postcss-discard-comments": "^6.0.1", + "postcss-discard-duplicates": "^6.0.1", + "postcss-discard-empty": "^6.0.1", + "postcss-discard-overridden": "^6.0.1", + "postcss-merge-longhand": "^6.0.2", + "postcss-merge-rules": "^6.0.3", + "postcss-minify-font-values": "^6.0.1", + "postcss-minify-gradients": "^6.0.1", + "postcss-minify-params": "^6.0.2", + "postcss-minify-selectors": "^6.0.2", + "postcss-normalize-charset": "^6.0.1", + "postcss-normalize-display-values": "^6.0.1", + "postcss-normalize-positions": "^6.0.1", + "postcss-normalize-repeat-style": "^6.0.1", + "postcss-normalize-string": "^6.0.1", + "postcss-normalize-timing-functions": "^6.0.1", + "postcss-normalize-unicode": "^6.0.2", + "postcss-normalize-url": "^6.0.1", + "postcss-normalize-whitespace": "^6.0.1", + "postcss-ordered-values": "^6.0.1", + "postcss-reduce-initial": "^6.0.2", + "postcss-reduce-transforms": "^6.0.1", + "postcss-svgo": "^6.0.2", + "postcss-unique-selectors": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.1.tgz", + "integrity": "sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.628", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.628.tgz", + "integrity": "sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", + "dev": true, + "dependencies": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-footer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/gulp-footer/-/gulp-footer-2.1.0.tgz", + "integrity": "sha512-CK3nRBP3PG59XN2L1rDLkBHA7goYsW+tJuVQccLP9jq3mpBT2kuRq0ImgNjrUkDbF948aCVQH4J7uIEqiZ2MHA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21", + "map-stream": "^0.0.7" + } + }, + "node_modules/gulp-header": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz", + "integrity": "sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==", + "dev": true, + "dependencies": { + "concat-with-sourcemaps": "^1.1.0", + "lodash.template": "^4.5.0", + "map-stream": "0.0.7", + "through2": "^2.0.0" + } + }, + "node_modules/gulp-postcss": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-9.0.1.tgz", + "integrity": "sha512-9QUHam5JyXwGUxaaMvoFQVT44tohpEFpM8xBdPfdwTYGM0AItS1iTQz0MpsF8Jroh7GF5Jt2GVPaYgvy8qD2Fw==", + "dev": true, + "dependencies": { + "fancy-log": "^1.3.3", + "plugin-error": "^1.0.1", + "postcss-load-config": "^3.0.0", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/gulp-rename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", + "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/gulp-replace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.1.4.tgz", + "integrity": "sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/vinyl": "^2.0.4", + "istextorbinary": "^3.0.0", + "replacestream": "^4.0.3", + "yargs-parser": ">=5.0.0-security.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gulp-sass": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-5.1.0.tgz", + "integrity": "sha512-7VT0uaF+VZCmkNBglfe1b34bxn/AfcssquLKVDYnCDJ3xNBaW7cUuI3p3BQmoKcoKFrs9jdzUxyb+u+NGfL4OQ==", + "dev": true, + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "picocolors": "^1.0.0", + "plugin-error": "^1.0.1", + "replace-ext": "^2.0.0", + "strip-ansi": "^6.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gulp-uglify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", + "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "isobject": "^3.0.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", + "through2": "^2.0.0", + "uglify-js": "^3.0.5", + "vinyl-sourcemaps-apply": "^0.2.0" + } + }, + "node_modules/gulp-uglify/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-uglify/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-uglify/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istextorbinary": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", + "integrity": "sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==", + "dev": true, + "dependencies": { + "binaryextensions": "^2.2.0", + "textextensions": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", + "dev": true + }, + "node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-error-cause": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", + "integrity": "sha512-4TO2Y3HkBnis4c0dxhAgD/jprySYLACf7nwN6V0HAHDx59g12WlRpUmFy1bRHamjGUEEBrEvCq6SUpsEE2lhUg==", + "dev": true, + "dependencies": { + "make-error": "^1.2.0" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "dev": true, + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/plugin-error/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.2.tgz", + "integrity": "sha512-TXKOxs9LWcdYo5cgmcSHPkyrLAh86hX1ijmyy6J8SbOhyv6ua053M3ZAM/0j44UsnQNIWdl8gb5L7xX2htKeLw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.2.tgz", + "integrity": "sha512-aeBmaTnGQ+NUSVQT8aY0sKyAD/BaLJenEKZ03YK0JnDE1w1Rr8XShoxdal2V2H26xTJKr3v5haByOhJuyT4UYw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.1.tgz", + "integrity": "sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.1.tgz", + "integrity": "sha512-1hvUs76HLYR8zkScbwyJ8oJEugfPV+WchpnA+26fpJ7Smzs51CzGBHC32RS03psuX/2l0l0UKh2StzNxOrKCYg==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.1.tgz", + "integrity": "sha512-yitcmKwmVWtNsrrRqGJ7/C0YRy53i0mjexBDQ9zYxDwTWVBgbU4+C9jIZLmQlTDT9zhml+u0OMFJh8+31krmOg==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.1.tgz", + "integrity": "sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.2.tgz", + "integrity": "sha512-+yfVB7gEM8SrCo9w2lCApKIEzrTKl5yS1F4yGhV3kSim6JzbfLGJyhR1B6X+6vOT0U33Mgx7iv4X9MVWuaSAfw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.3.tgz", + "integrity": "sha512-yfkDqSHGohy8sGYIJwBmIGDv4K4/WrJPX355XrxQb/CSsT4Kc/RxDi6akqn5s9bap85AWgv21ArcUWwWdGNSHA==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.1", + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.1.tgz", + "integrity": "sha512-tIwmF1zUPoN6xOtA/2FgVk1ZKrLcCvE0dpZLtzyyte0j9zUeB8RTbCqrHZGjJlxOvNWKMYtunLrrl7HPOiR46w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.1.tgz", + "integrity": "sha512-M1RJWVjd6IOLPl1hYiOd5HQHgpp6cvJVLrieQYS9y07Yo8itAr6jaekzJphaJFR0tcg4kRewCk3kna9uHBxn/w==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.2.tgz", + "integrity": "sha512-zwQtbrPEBDj+ApELZ6QylLf2/c5zmASoOuA4DzolyVGdV38iR2I5QRMsZcHkcdkZzxpN8RS4cN7LPskOkTwTZw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.2.tgz", + "integrity": "sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.1.tgz", + "integrity": "sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.1.tgz", + "integrity": "sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.1.tgz", + "integrity": "sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.1.tgz", + "integrity": "sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.1.tgz", + "integrity": "sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.1.tgz", + "integrity": "sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.2.tgz", + "integrity": "sha512-Ff2VdAYCTGyMUwpevTZPZ4w0+mPjbZzLLyoLh/RMpqUqeQKZ+xMm31hkxBavDcGKcxm6ACzGk0nBfZ8LZkStKA==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.1.tgz", + "integrity": "sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.1.tgz", + "integrity": "sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.1.tgz", + "integrity": "sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==", + "dev": true, + "dependencies": { + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.2.tgz", + "integrity": "sha512-YGKalhNlCLcjcLvjU5nF8FyeCTkCO5UtvJEt0hrPZVCTtRLSOH4z00T1UntQPj4dUmIYZgMj8qK77JbSX95hSw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.1.tgz", + "integrity": "sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.2.tgz", + "integrity": "sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.2.tgz", + "integrity": "sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "dev": true, + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.3", + "object-assign": "^4.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/sass": { + "version": "1.69.7", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz", + "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/sass/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sass/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/sass/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sass/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz", + "integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylehacks": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.2.tgz", + "integrity": "sha512-00zvJGnCu64EpMjX8b5iCZ3us2Ptyw8+toEkb92VdmkEaRaSGBNKAoK6aWZckhXxmQP8zWiTaFaiMGIU8Ve8sg==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2", + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/svgo": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", + "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/textextensions": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-3.3.0.tgz", + "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", + "dev": true, + "dependencies": { + "source-map": "^0.5.1" + } + }, + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b4b11d5 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "babel", + "description": "The easy way for your multilingual site!", + "author": "Jakob Class ", + "contributors": [ + "Rico Goldsky ", + "Joshua Luckers " + ], + "private": true, + "devDependencies": { + "autoprefixer": "^10.4.16", + "cssnano": "^6.0.3", + "date-format": "^4.0.14", + "gulp": "^4.0.2", + "gulp-concat": "^2.6.1", + "gulp-footer": "^2.1.0", + "gulp-header": "^2.0.9", + "gulp-postcss": "^9.0.1", + "gulp-rename": "^2.0.0", + "gulp-replace": "^1.1.4", + "gulp-sass": "^5.1.0", + "gulp-uglify": "^3.0.2", + "postcss": "^8.4.33", + "sass": "^1.69.7", + "uglify-js": "^3.17.4" + }, + "browserslist": [ + "last 2 version", + "> 1%", + "maintained node versions", + "not dead" + ] +} diff --git a/screenshots/babel-linked-menu.png b/screenshots/babel-linked-menu.png deleted file mode 100644 index df3ce20..0000000 Binary files a/screenshots/babel-linked-menu.png and /dev/null differ diff --git a/screenshots/babel-linking-window.png b/screenshots/babel-linking-window.png deleted file mode 100644 index db79d68..0000000 Binary files a/screenshots/babel-linking-window.png and /dev/null differ diff --git a/screenshots/babel-unlinked-menu.png b/screenshots/babel-unlinked-menu.png deleted file mode 100644 index 94c0abf..0000000 Binary files a/screenshots/babel-unlinked-menu.png and /dev/null differ diff --git a/source/css/mgr/babel.css b/source/css/mgr/babel.css new file mode 100644 index 0000000..90721a9 --- /dev/null +++ b/source/css/mgr/babel.css @@ -0,0 +1,112 @@ +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +.x-grid3-locked, .x-grid3-unlocked { + overflow: hidden; + position: absolute; +} + +.x-grid3-locked { + border-right: 1px solid #99BBE8; +} + +.x-grid3-locked .x-grid3-scroller { + overflow: hidden; +} + +.x-grid3-locked .x-grid3-row { + border-right: 0; +} + +.x-grid3-scroll-spacer { + height: 19px; +} + +.x-grid3-unlocked .x-grid3-header-offset { + padding-left: 0; +} + +.x-grid3-unlocked .x-grid3-row { + border-left: 0; +} + +.babel-panel .action-buttons { + text-align: center; +} +.babel-panel .action-buttons li { + display: inline-block; + font-size: 1.1em; + line-height: 0.7; + margin-right: 5px; +} +.babel-panel .action-buttons li:last-child { + margin-right: 0; +} +.babel-panel .x-combo-list-item { + min-height: 20px; +} +.babel-panel .icon-babel-description-img { + width: 16px; + height: 16px; + margin: 0 6px 0 12px; +} +.babel-panel .icon-babel-description-img:first-child { + margin-left: 0; +} + +.home-panel.debug { + background: linear-gradient(to top right, transparent, transparent, transparent, #fff); +} + +.ribbon { + height: 180px; + overflow: hidden; + pointer-events: none; + position: absolute; + width: 180px; + z-index: 10; +} +.ribbon:before, .ribbon:after { + border: 5px solid #a20000; + content: ""; + display: block; + position: absolute; + z-index: -1; +} +.ribbon.top-right { + right: -10px; + top: -10px; +} +.ribbon.top-right:before, .ribbon.top-right:after { + border-right-color: transparent; + border-top-color: transparent; +} +.ribbon.top-right:before { + left: 0; + top: 0; +} +.ribbon.top-right:after { + bottom: 0; + right: 0; +} +.ribbon.top-right span { + left: -46px; + top: 46px; + transform: rotate(45deg); +} +.ribbon span { + background-color: #be0000; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); + color: #fff; + display: block; + font: 700 18px/1 "Lato", sans-serif; + padding: 15px 0; + position: absolute; + text-align: center; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + text-transform: uppercase; + width: 300px; +} \ No newline at end of file diff --git a/source/js/mgr/babel.js b/source/js/mgr/babel.js new file mode 100644 index 0000000..908bca8 --- /dev/null +++ b/source/js/mgr/babel.js @@ -0,0 +1,357 @@ +var babel = function (config) { + config = config || {}; + babel.superclass.constructor.call(this, config); +}; +Ext.extend(babel, Ext.Component, { + page: {}, window: {}, grid: {}, tree: {}, panel: {}, combo: {}, config: {}, util: {}, + getMenu: function (menus) { + var _this = this; + var actionButtons = Ext.getCmp('modx-action-buttons'); + if (actionButtons) { + var menu = [], i = 0; + for (var ctx in menus) { + if (ctx === this.config.context_key) { + continue; + } + if (typeof (menus[ctx]['resourceUrl']) !== 'undefined' && + menus[ctx]['resourceUrl'] !== '' && + menus[ctx]['resourceUrl'] !== '#') { + menu.push({ + text: '' + menus[ctx]['displayText'], + menu: { + items: [{ + text: '' + _('babel.open') + ' ' + menus[ctx]['resourceTitle'] + ' (' + menus[ctx]['resourceId'] + ')', + resourceUrl: menus[ctx]['resourceUrl'], + resourceId: menus[ctx]['resourceId'], + handler: function () { + MODx.loadPage('resource/update', 'id=' + this.resourceId); + } + }, '-', { + text: '' + _('babel.unlink') + ' ' + menus[ctx]['resourceTitle'] + ' (' + menus[ctx]['resourceId'] + ')', + contextKey: ctx, + target: menus[ctx]['resourceId'], + handler: function () { + _this.unlinkTranslation(this.contextKey, this.target); + } + }] + } + }); + i++; + } else { + menu.push({ + text: '' + menus[ctx]['displayText'], + handler: Ext.emptyFn, + menu: { + items: [{ + text: '' + _('babel.create_translation'), + contextKey: ctx, + handler: function () { + _this.createTranslation(this.contextKey); + } + }, '-', { + text: '' + _('babel.link_translation'), + contextKey: ctx, + handler: function () { + _this.linkTranslation(this.contextKey); + } + }] + } + }); + } + } + if (i > 0) { + menu.push('-'); + menu.push({ + text: '' + _('babel.unlink_all_translations'), + handler: function () { + _this.unlinkTranslation(); + } + }); + } + menu.push('-'); + menu.push({ + text: '' + _('babel.about'), + handler: function () { + _this.aboutWindow(); + }, + }); + // destroy existing button menu + var buttonMenu = Ext.getCmp('babel-language-select'); + if (buttonMenu) { + buttonMenu.destroy(); // @TODO Get the previous button position and use this for the new button + } + buttonMenu = new Ext.Button({ + id: 'babel-language-select', + text: 'Select Language', + menu: menu, + listeners: { + render: { + fn: function (btn) { + btn.setText(menus[_this.config.context_key]['displayText']); + }, + scope: this + }, + mouseover: function (btn) { + btn.showMenu(); + } + } + }); + actionButtons.insertButton(0, [buttonMenu]); + actionButtons.doLayout(); + } + }, + linkTranslation: function (ctx) { + var id = MODx.request.id; + var window = MODx.load({ + xtype: 'modx-window', + title: _('babel.link_translation'), + url: this.config.connectorUrl, + baseParams: { + action: 'mgr/resource/link', + context: ctx, + id: id + }, + listeners: { + success: { + fn: function (r) { + MODx.msg.status({ + title: _('success'), + message: r.message || _('save_successful') + }); + this.getMenu(r.a.result.object.menu); + this.hideMask(); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + beforeSubmit: { + fn: this.loadMask, + scope: this + } + }, + fields: [{ + xtype: 'textfield', + fieldLabel: _('context'), + anchor: '100%', + disabled: true, + emptyText: ctx + }, { + xtype: 'modx-field-parent-change', + fieldLabel: _('babel.select_tree_node'), + id: '', + name: 'target-combo', + anchor: '100%', + end: function (parent) { + var tree = Ext.getCmp('modx-resource-tree'); + if (!tree) { + return; + } + parent.display = parent.display || parent.value; + if (parent.context !== ctx) { + return; + } + tree.removeListener('click', this.handleChangeParent, this); + tree.on('click', tree._handleClick, tree); + tree.disableHref = false; + window.fp.getForm().findField('target').setValue(parent.value); + window.fp.getForm().findField('page_id').setValue(null); + this.setValue(parent.display); + this.oldValue = false; + }, + handleChangeParent: function (node, e) { + var tree = Ext.getCmp('modx-resource-tree'); + if (!tree) { + return false; + } + tree.disableHref = true; + var id = node.id.split('_'); + id = id[1]; + if (id === this.config.currentid) { + MODx.msg.alert('', _('resource_err_own_parent')); + return false; + } + this.fireEvent('end', { + value: node.attributes.type !== 'modContext' ? id : node.attributes.pk, + display: Ext.util.Format.stripTags(node.text), + context: node.attributes.ctx + }); + e.preventDefault(); + e.stopEvent(); + return true; + } + }, { + xtype: 'modx-combo', + fieldLabel: _('babel.target_pagetitle'), + name: 'page_id', + anchor: '100%', + url: this.config.connectorUrl, + baseParams: { + action: 'mgr/resource/getlist', + context: ctx, + combo: true + }, + displayField: 'pagetitle', + valueField: 'id', + fields: ['id', 'pagetitle'], + editable: true, + typeAhead: true, + forceSelection: true, + listeners: { + select: { + fn: function (combo, record) { + var val = combo.getValue(); + if (val === '' || val === 0 || val === ' ') { + combo.setValue(null); + } else { + window.fp.getForm().findField('target').setValue(record.get('id')); + } + window.fp.getForm().findField('target-combo').reset(); + }, + scope: this + }, + blur: { + fn: function (combo) { + var val = combo.getValue(); + if (val === '' || val === 0 || val === ' ') { + combo.setValue(null); + } + }, + scope: this + } + } + }, { + fieldLabel: _('babel.target_id'), + xtype: 'numberfield', + name: 'target', + anchor: '100%', + enableKeyEvents: true, + listeners: { + keyup: { + fn: function () { + window.fp.getForm().findField('target-combo').reset(); + window.fp.getForm().findField('page_id').reset(); + }, + scope: this + } + } + }, { + xtype: 'xcheckbox', + boxLabel: _('babel.copy_tv_values'), + name: 'copy-tv-values' + }, { + xtype: 'xcheckbox', + boxLabel: _('babel.sync_linked_tranlations'), + name: 'sync-linked-tranlations', + checked: true + }] + }); + window.show(); + }, + unlinkTranslation: function (ctx, target) { + this.loadMask(); + ctx = ctx || ''; + target = parseInt(target) || 0; + var id = MODx.request.id; + var text = (target === 0) ? + _('babel.unlink_all_translations_confirm') : + _('babel.unlink_translation_confirm', { + context: ctx, + id: id + }); + return MODx.msg.confirm({ + title: _('confirm'), + text: text, + url: this.config.connectorUrl, + params: { + action: 'mgr/resource/unlink', + id: id, + context: ctx, + target: target + }, + listeners: { + success: { + fn: function (r) { + MODx.msg.status({ + title: _('success'), + message: r.message || _('save_successful') + }); + this.getMenu(r.object.menu); + this.hideMask(); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + cancel: { + fn: this.hideMask, + scope: this + } + } + }); + }, + createTranslation: function (ctx) { + this.loadMask(); + var id = MODx.request.id; + return MODx.msg.confirm({ + title: _('confirm'), + text: _('babel.create_translation_confirm', {context: ctx, id: id}), + url: this.config.connectorUrl, + params: { + action: 'mgr/resource/duplicate', + context_key: ctx, + id: id + }, + listeners: { + success: { + fn: function (r) { + this.hideMask(); + MODx.loadPage('resource/update', 'id=' + r.object.id); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + cancel: { + fn: this.hideMask, + scope: this + } + } + }); + }, + loadMask: function () { + if (!this.overlayMask) { + var domHandler = Ext.getBody().dom; + this.overlayMask = new Ext.LoadMask(domHandler, { + msg: _('babel.please_wait') + }); + } + this.overlayMask.show(); + }, + hideMask: function () { + if (this.overlayMask) { + this.overlayMask.hide(); + } + }, + aboutWindow: function () { + const msg = '© 2010-2024 by Jakob Class

' + + 'Authors: Jakob Class, Rico Goldsky, Joshua Luckers, Thomas Jakobi

' + + 'Repository: github.com/Jako/Babel'; + Ext.Msg.show({ + title: _('babel') + ' ' + Babel.config.version, + msg: msg, + buttons: Ext.Msg.OK, + cls: 'babel_window', + width: 358 + }); + } +}); +Ext.reg('babel', babel); + +var Babel = new babel(); diff --git a/source/js/mgr/helper/combo.js b/source/js/mgr/helper/combo.js new file mode 100644 index 0000000..82e9cb4 --- /dev/null +++ b/source/js/mgr/helper/combo.js @@ -0,0 +1,22 @@ +Babel.combo.Context = function (config) { + config = config || {}; + Ext.applyIf(config, { + url: Babel.config.connectorUrl, + baseParams: { + action: 'mgr/context/getlist', + combo: true, + exclude: 'mgr' + }, + tpl: new Ext.XTemplate('
{name:htmlEncode} ({key:htmlEncode})
') + }); + Babel.combo.Context.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.combo.Context, MODx.combo.Context, { + setValue: function (value) { + if (value === '') { + value = null; + } + Babel.combo.Context.superclass.setValue.call(this, value); + } +}); +Ext.reg('babel-combo-context', Babel.combo.Context); diff --git a/source/js/mgr/sections/index.js b/source/js/mgr/sections/index.js new file mode 100644 index 0000000..8667318 --- /dev/null +++ b/source/js/mgr/sections/index.js @@ -0,0 +1,21 @@ +MODx.config.help_url = 'https://mikrobi.github.io/babel/usage/'; + +Babel.page.Home = function (config) { + config = config || {}; + Ext.applyIf(config, { + buttons: [{ + text: _('babel.about'), + handler: Babel.aboutWindow + },{ + text: _('help_ex'), + handler: MODx.loadHelpPane + }], + formpanel: 'babel-panel-home', + components: [{ + xtype: 'babel-panel-home' + }] + }); + Babel.page.Home.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.page.Home, MODx.Component); +Ext.reg('babel-page-home', Babel.page.Home); diff --git a/source/js/mgr/widgets/home.panel.js b/source/js/mgr/widgets/home.panel.js new file mode 100644 index 0000000..a7717af --- /dev/null +++ b/source/js/mgr/widgets/home.panel.js @@ -0,0 +1,127 @@ +Babel.panel.Home = function (config) { + config = config || {}; + Ext.applyIf(config, { + cls: 'container home-panel' + ((Babel.config.debug) ? ' debug' : '') + ' modx' + Babel.config.modxversion, + defaults: { + collapsible: false, + autoHeight: true + }, + items: [{ + html: '

' + _('babel') + '

' + ((Babel.config.debug) ? '
' + _('babel.debug_mode') + '
' : ''), + border: false, + cls: 'modx-page-header' + }, { + defaults: { + autoHeight: true + }, + border: true, + cls: 'babel-panel', + items: [{ + xtype: 'babel-panel-overview' + }] + }] + }); + Babel.panel.Home.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.panel.Home, MODx.Panel); +Ext.reg('babel-panel-home', Babel.panel.Home); + +Babel.panel.HomeTab = function (config) { + config = config || {}; + Ext.applyIf(config, { + id: 'babel-panel-' + config.tabtype, + title: config.title, + items: [{ + html: '

' + config.description + '

', + border: false, + cls: 'panel-desc' + }, { + layout: 'form', + cls: 'x-form-label-left main-wrapper', + defaults: { + autoHeight: true + }, + border: true, + items: [{ + id: 'babel-panel-' + config.tabtype + '-' + config.contenttype, + xtype: 'babel-' + config.contenttype + '-' + config.tabtype, + preventRender: true, + contexts: Babel.config.contexts, + listeners: { + afterrender: function () { + this.store.on('load', function () { + var tbarHeight = this.getTopToolbar().getHeight(); + var lockedHdHeight = this.getView().lockedHd.getHeight(); + var lockedBodyHeight = this.getView().lockedBody.getHeight(); + var bbarHeight = this.getBottomToolbar().getHeight(); + this.setHeight(tbarHeight + lockedHdHeight + lockedBodyHeight + bbarHeight + 14); + }, this); + } + } + }] + }], + }); + Babel.panel.HomeTab.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.panel.HomeTab, MODx.Panel); +Ext.reg('babel-panel-hometab', Babel.panel.HomeTab); + +Babel.panel.Overview = function (config) { + config = config || {}; + this.ident = 'babel-overview-' + Ext.id(); + this.panelOverviewTabs = [{ + xtype: 'babel-panel-hometab', + title: _('babel.contexts'), + description: '
' + _('babel.contexts_desc') + '
' + _('babel.contexts_desc_link') + + '' + _('babel.contexts_desc_unlink') + + '' + _('babel.contexts_desc_update') + + '' + _('babel.contexts_desc_create') + '
', + tabtype: 'resourcematrix', + contenttype: 'grid' + }]; + if (Babel.config.permissions.babel_settings || Babel.config.permissions.settings) { + this.panelOverviewTabs.push({ + xtype: 'babel-panel-settings' + }); + } + Ext.applyIf(config, { + id: this.ident, + items: [{ + xtype: 'modx-tabs', + border: true, + stateful: true, + stateId: 'babel-panel-overview', + stateEvents: ['tabchange'], + getState: function () { + return { + activeTab: this.items.indexOf(this.getActiveTab()) + }; + }, + autoScroll: true, + deferredRender: true, + forceLayout: false, + defaults: { + layout: 'form', + autoHeight: true, + hideMode: 'offsets' + }, + items: this.panelOverviewTabs, + listeners: { + tabchange: function (o, t) { + if (t.xtype === 'babel-panel-settings') { + if (Ext.getCmp('babel-grid-system-settings')) { + Ext.getCmp('babel-grid-system-settings').getStore().reload(); + } + } else if (t.xtype === 'babel-panel-hometab') { + if (Ext.getCmp('babel-panel-' + t.tabtype + '-' + t.contenttype)) { + Ext.getCmp('babel-panel-' + t.tabtype + '-' + t.contenttype).getStore().reload(); + } + } + } + } + }] + }); + Babel.panel.Overview.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.panel.Overview, MODx.Panel); +Ext.reg('babel-panel-overview', Babel.panel.Overview); diff --git a/source/js/mgr/widgets/resourcematrix.grid.js b/source/js/mgr/widgets/resourcematrix.grid.js new file mode 100644 index 0000000..1d0ab8f --- /dev/null +++ b/source/js/mgr/widgets/resourcematrix.grid.js @@ -0,0 +1,468 @@ +Babel.grid.ResourceMatrix = function (config) { + config = config || {}; + this.buttonColumnTpl = new Ext.XTemplate('' + + '' + + '
    ' + + '' + + '
  • ' + + '
    ' + + '
' + + '
' + + '
', { + compiled: true + }); + this.ident = 'babel-resourcematrix-' + Ext.id(); + var _this = this; + var columns = []; + var fields = ['id', 'context_key', 'pagetitle', 'parent']; + var contexts = []; + if (config.contexts) { + columns = [{ + header: _('id'), + width: 70, + sortable: true, + dataIndex: 'id', + locked: true, + id: 'res_id' + }, { + header: _('context'), + width: 80, + sortable: true, + dataIndex: 'context_key', + locked: true, + id: 'context_key' + }, { + header: _('pagetitle'), + width: 200, + sortable: true, + dataIndex: 'pagetitle', + locked: true, + id: 'pagetitle' + }, { + header: _('babel.all'), + renderer: this.buttonColumnAllRenderer.bind(this), + menuDisabled: true, + fixed: true, + locked: true, + width: 50 + }]; + Ext.each(config.contexts, function (item) { + fields.push('linkedres_id_' + item); + fields.push('linkedres_pagetitle_' + item); + contexts.push(item); + columns.push({ + header: item, + width: 70, + sortable: false, + dataIndex: 'linkedres_id_' + item, + id: 'linkedres_id_' + item, + menuDisabled: true, + renderer: _this.buttonColumnContextRenderer.bind(_this), + }); + }); + } + var cm = new Ext.ux.grid.LockingColumnModel({ + columns: columns + }); + var view = new Ext.ux.grid.LockingGridView({ + syncHeights: true + }); + + Ext.apply(config, { + url: Babel.config.connectorUrl, + baseParams: { + action: 'mgr/resource/getmatrixlist', + contexts: contexts.toString() + }, + colModel: cm, + fields: fields, + paging: true, + remoteSort: true, + anchor: '100%', + view: new Ext.ux.grid.LockingGridView(), + autoHeight: false, + showActionsColumn: false, + tbar: [{ + xtype: 'babel-combo-context', + id: this.ident + '-filter-context', + emptyText: _('babel.select_context'), + listeners: { + select: { + fn: this.filterByContext, + scope: this + } + } + }, '->', { + xtype: 'textfield', + id: this.ident + '-filter-query', + cls: 'x-form-filter', + emptyText: _('babel.search'), + width: 300, + listeners: { + change: { + fn: this.filterByQuery, + scope: this + }, + render: { + fn: function (cmp) { + new Ext.KeyMap(cmp.getEl(), { + key: Ext.EventObject.ENTER, + fn: this.blur, + scope: cmp + }); + }, + scope: this + } + } + }, { + xtype: 'button', + id: this.ident + '-filter-clear', + cls: 'x-form-filter-clear', + text: _('babel.reset'), + listeners: { + click: { + fn: this.clearFilter, + scope: this + } + } + }] + }); + Babel.grid.ResourceMatrix.superclass.constructor.call(this, config); +}; +Ext.extend(Babel.grid.ResourceMatrix, MODx.grid.Grid, { + linkTranslation: function (ctx, id) { + var window = MODx.load({ + xtype: 'modx-window', + title: _('babel.link_translation'), + url: Babel.config.connectorUrl, + baseParams: { + action: 'mgr/resource/link', + context: ctx, + id: id + }, + listeners: { + success: { + fn: function (r) { + MODx.msg.status({ + title: _('success'), + message: r.message || _('save_successful') + }); + this.hideMask(); + this.refresh(); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + beforeSubmit: { + fn: this.loadMask, + scope: this + } + }, + fields: [{ + xtype: 'textfield', + fieldLabel: _('context'), + anchor: '100%', + disabled: true, + emptyText: ctx + }, { + xtype: 'modx-field-parent-change', + fieldLabel: _('babel.select_tree_node'), + id: '', + name: 'target-combo', + anchor: '100%', + end: function (parent) { + var tree = Ext.getCmp('modx-resource-tree'); + if (!tree) { + return; + } + parent.display = parent.display || parent.value; + if (parent.context !== ctx) { + return; + } + tree.removeListener('click', this.handleChangeParent, this); + tree.on('click', tree._handleClick, tree); + tree.disableHref = false; + window.fp.getForm().findField('target').setValue(parent.value); + window.fp.getForm().findField('page_id').setValue(null); + this.setValue(parent.display); + this.oldValue = false; + }, + handleChangeParent: function (node, e) { + var tree = Ext.getCmp('modx-resource-tree'); + if (!tree) { + return false; + } + tree.disableHref = true; + var id = node.id.split('_'); + id = id[1]; + if (id === this.config.currentid) { + MODx.msg.alert('', _('resource_err_own_parent')); + return false; + } + this.fireEvent('end', { + value: node.attributes.type !== 'modContext' ? id : node.attributes.pk, + display: Ext.util.Format.stripTags(node.text), + context: node.attributes.ctx + }); + e.preventDefault(); + e.stopEvent(); + return true; + } + }, { + xtype: 'modx-combo', + fieldLabel: _('babel.target_pagetitle'), + name: 'page_id', + anchor: '100%', + url: Babel.config.connectorUrl, + baseParams: { + action: 'mgr/resource/getlist', + context: ctx, + combo: true + }, + displayField: 'pagetitle', + valueField: 'id', + fields: ['id', 'pagetitle'], + editable: true, + typeAhead: true, + forceSelection: true, + listeners: { + select: { + fn: function (combo, record) { + var val = combo.getValue(); + if (val === '' || val === 0 || val === ' ') { + combo.setValue(null); + } else { + window.fp.getForm().findField('target').setValue(record.get('id')); + } + window.fp.getForm().findField('target-combo').reset(); + }, + scope: this + }, + blur: { + fn: function (combo) { + var val = combo.getValue(); + if (val === '' || val === 0 || val === ' ') { + combo.setValue(null); + } + }, + scope: this + } + } + }, { + fieldLabel: _('babel.target_id'), + xtype: 'numberfield', + name: 'target', + anchor: '100%', + enableKeyEvents: true, + listeners: { + keyup: { + fn: function () { + window.fp.getForm().findField('target-combo').reset(); + window.fp.getForm().findField('page_id').reset(); + }, + scope: this + } + } + }, { + xtype: 'xcheckbox', + boxLabel: _('babel.copy_tv_values'), + name: 'copy-tv-values' + }, { + xtype: 'xcheckbox', + boxLabel: _('babel.sync_linked_tranlations'), + name: 'sync-linked-tranlations', + checked: true + }] + }); + window.reset(); + window.show(); + }, + unlinkTranslation: function (ctx, id, target) { + this.loadMask(); + ctx = ctx || ''; + target = parseInt(target) || 0; + var text = (target === 0) ? + _('babel.unlink_all_translations_confirm') : + _('babel.unlink_translation_confirm', { + context: ctx, + id: id + }); + return MODx.msg.confirm({ + title: _('confirm'), + text: text, + url: Babel.config.connectorUrl, + params: { + action: 'mgr/resource/unlink', + id: id, + context: ctx, + target: target + }, + listeners: { + success: { + fn: function (r) { + MODx.msg.status({ + title: _('success'), + message: r.message || _('save_successful') + }); + this.hideMask(); + this.refresh(); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + cancel: { + fn: this.hideMask, + scope: this + } + } + }); + }, + createTranslation: function (ctx, id) { + this.loadMask(); + return MODx.msg.confirm({ + title: _('confirm'), + text: _('babel.create_translation_confirm', {context: ctx, id: id}), + url: Babel.config.connectorUrl, + params: { + action: 'mgr/resource/duplicate', + context_key: ctx, + id: id + }, + listeners: { + success: { + fn: function (r) { + this.hideMask(); + MODx.loadPage('resource/update', 'id=' + r.object.id); + }, + scope: this + }, + failure: { + fn: this.hideMask, + scope: this + }, + cancel: { + fn: this.hideMask, + scope: this + } + } + }); + }, + clearFilter: function () { + var store = this.getStore(); + store.baseParams.context = ''; + store.baseParams.query = ''; + Ext.getCmp(this.ident + '-filter-context').reset(); + Ext.getCmp(this.ident + '-filter-query').reset(); + this.getBottomToolbar().changePage(1); + this.refresh(); + }, + filterByContext: function (cb, rec) { + this.getStore().baseParams.context = rec.data.key; + this.getBottomToolbar().changePage(1); + this.refresh(); + }, + filterByQuery: function (tf, newValue) { + this.getStore().baseParams.query = newValue; + this.getBottomToolbar().changePage(1); + this.refresh(); + return true; + }, + loadMask: function () { + if (!this.overlayMask) { + var domHandler = Ext.getBody().dom; + this.overlayMask = new Ext.LoadMask(domHandler, { + msg: _('babel.please_wait') + }); + } + this.overlayMask.show(); + }, + hideMask: function () { + if (this.overlayMask) { + this.overlayMask.hide(); + } + }, + buttonColumnAllRenderer: function () { + return this.buttonColumnTpl.apply({ + action_buttons: [{ + className: 'unlink-all', + icon: 'chain-broken', + text: _('babel.unlink') + }] + }); + }, + buttonColumnContextRenderer: function (value, metaData, record) { + var actionButtons = []; + if (metaData.id !== 'linkedres_id_' + record.get('context_key')) { + var ctx = metaData.id.substr('linkedres_id_'.length); + if (record.get(metaData.id) === '') { + actionButtons.push({ + className: 'create', + icon: 'plus-circle', + text: _('babel.create_translation'), + ctx: ctx, + target: 0 + }, { + className: 'link', + icon: 'link', + text: _('babel.link_translation'), + ctx: ctx, + target: 0 + }); + } else { + var pagetitle = record.get('linkedres_pagetitle_' + ctx); + var target = record.get('linkedres_id_' + ctx); + actionButtons.push({ + className: 'update', + icon: 'pencil-square-o', + text: _('edit') + ': ' + pagetitle + ' (' + target + ')', + ctx: ctx, + target: target + }, { + className: 'unlink', + icon: 'chain-broken', + text: _('babel.unlink') + ': ' + pagetitle + ' (' + target + ')', + ctx: ctx, + target: target + }); + } + } + return this.buttonColumnTpl.apply({ + action_buttons: actionButtons + }); + }, + onClick: function (e) { + var t = e.getTarget(); + var elm = t.className.split(' ')[0]; + if (elm === 'icon') { + var act = t.className.split(' ')[1]; + var record = this.getSelectionModel().getSelected(); + switch (act) { + case 'unlink-all': + this.unlinkTranslation('', record.get('id'), 0) + break; + case 'create': + this.createTranslation(t.dataset.ctx, record.get('id')); + break; + case 'link': + this.linkTranslation(t.dataset.ctx, record.get('id')); + break; + case 'update': + MODx.loadPage('resource/update', 'id=' + t.dataset.target); + console.log(record); + break; + case 'unlink': + this.unlinkTranslation(t.dataset.ctx, record.get('id'), t.dataset.target); + break; + default: + break; + } + } + } +}); +Ext.reg('babel-grid-resourcematrix', Babel.grid.ResourceMatrix); diff --git a/source/js/mgr/widgets/settings.panel.js b/source/js/mgr/widgets/settings.panel.js new file mode 100644 index 0000000..348b9d8 --- /dev/null +++ b/source/js/mgr/widgets/settings.panel.js @@ -0,0 +1,128 @@ +if (MODx.grid.SettingsGrid) { + Babel.panel.Settings = function (config) { + config = config || {}; + MODx.request.ns = 'babel'; + Ext.applyIf(config, { + id: 'babel-panel-settings', + title: _('babel.settings'), + items: [{ + html: '

' + _('babel.settings_desc') + '

', + border: false, + cls: 'panel-desc' + }, { + xtype: 'babel-grid-system-settings', + id: 'babel-grid-system-settings', + cls: 'main-wrapper', + preventSaveRefresh: true + }] + }); + Babel.panel.Settings.superclass.constructor.call(this, config); + }; + Ext.extend(Babel.panel.Settings, MODx.Panel); + Ext.reg('babel-panel-settings', Babel.panel.Settings); + + Babel.grid.SystemSettings = function (config) { + config = config || {}; + Ext.applyIf(config, { + id: 'babel-grid-systemsettings', + url: Babel.config.connectorUrl, + baseParams: { + action: 'mgr/settings/getlist', + area: MODx.request.area || '' + }, + save_action: 'mgr/settings/updatefromgrid', + tbar: [], + queryParam: (Babel.config.modxversion >= 3) ? 'query' : 'key' + }); + Babel.grid.SystemSettings.superclass.constructor.call(this, config); + }; + Ext.extend(Babel.grid.SystemSettings, MODx.grid.SettingsGrid, { + _showMenu: function (g, ri, e) { + e.stopEvent(); + e.preventDefault(); + this.menu.record = this.getStore().getAt(ri).data; + if (!this.getSelectionModel().isSelected(ri)) { + this.getSelectionModel().selectRow(ri); + } + this.menu.removeAll(); + var m = []; + if (this.menu.record.menu) { + m = this.menu.record.menu; + } else { + m.push({ + text: _('setting_update') || _('edit'), + handler: this.updateSetting + }); + } + if (m.length > 0) { + this.addContextMenuItem(m); + this.menu.showAt(e.xy); + } + }, + updateSetting: function (btn, e) { + var r = this.menu.record; + r.fk = Ext.isDefined(this.config.fk) ? this.config.fk : 0; + var uss = MODx.load({ + xtype: 'modx-window-setting-update', + url: Babel.config.connectorUrl, + action: 'mgr/settings/update', + record: r, + grid: this, + listeners: { + success: { + fn: this.refresh, + scope: this + } + } + }); + uss.reset(); + uss.setValues(r); + uss.show(); + }, + clearFilter: function () { + var area = MODx.request.area || ''; + this.getStore().baseParams = this.initialConfig.baseParams; + var filterArea = Ext.getCmp('modx-filter-area'); + filterArea = filterArea || this.topToolbar.getComponent('filter-area'); + if (filterArea) { + filterArea.store.load(); + filterArea.reset(); + } + var filterQuery = Ext.getCmp('modx-filter-' + this.config.queryParam) + filterQuery = filterQuery || this.topToolbar.getComponent('filter-query'); + if (filterQuery) { + filterQuery.reset(); + } + this.getStore().baseParams.area = area; + this.getStore().baseParams[this.config.queryParam] = ''; + this.getBottomToolbar().changePage(1); + }, + filterByKey: function (tf, newValue) { + this.getStore().baseParams[this.config.queryParam] = newValue; + this.getBottomToolbar().changePage(1); + return true; + }, + filterByNamespace: function () { + this.getStore().baseParams.area = ''; + this.getBottomToolbar().changePage(1); + var filterArea = Ext.getCmp('modx-filter-area'); + filterArea = filterArea || this.topToolbar.getComponent('filter-area'); + if (filterArea) { + var s = filterArea.store; + s.removeAll(); + s.load(); + filterArea.setValue(''); + } + }, + listeners: { + afterrender: function (cmp) { + var filterNamespace = Ext.getCmp('modx-filter-namespace'); + filterNamespace = filterNamespace || cmp.topToolbar.getComponent('filter-ns'); + if (filterNamespace) { + filterNamespace.hide(); + } + } + } + }); + Ext.reg('babel-grid-system-settings', Babel.grid.SystemSettings); +} diff --git a/assets/components/babel/js/ux/LockingGridView/LockingGridView.css b/source/js/ux/LockingGridView/LockingGridView.css similarity index 100% rename from assets/components/babel/js/ux/LockingGridView/LockingGridView.css rename to source/js/ux/LockingGridView/LockingGridView.css diff --git a/assets/components/babel/js/ux/LockingGridView/LockingGridView.js b/source/js/ux/LockingGridView/LockingGridView.js similarity index 97% rename from assets/components/babel/js/ux/LockingGridView/LockingGridView.js rename to source/js/ux/LockingGridView/LockingGridView.js index 09f9c3e..30032e5 100644 --- a/assets/components/babel/js/ux/LockingGridView/LockingGridView.js +++ b/source/js/ux/LockingGridView/LockingGridView.js @@ -1,9 +1,3 @@ -/*! - * Ext JS Library 3.4.0 - * Copyright(c) 2006-2011 Sencha Inc. - * licensing@sencha.com - * http://www.sencha.com/license - */ /*! * Ext JS Library 3.4.0 * Copyright(c) 2006-2010 Ext JS, Inc. @@ -62,16 +56,16 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { mainWrap = el.child('div.x-grid3-viewport'), mainHd = mainWrap.child('div.x-grid3-header'), scroller = mainWrap.child('div.x-grid3-scroller'); - + if (this.grid.hideHeaders) { lockedHd.setDisplayed(false); mainHd.setDisplayed(false); } - + if(this.forceFit){ scroller.setStyle('overflow-x', 'hidden'); } - + Ext.apply(this, { el : el, mainWrap: mainWrap, @@ -88,7 +82,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { lockedBody: lockedScroller.child('div.x-grid3-body'), lockedInnerHd: lockedHd.child('div.x-grid3-header-inner', true) }); - + this.focusEl.swallowEvent('click', true); }, @@ -157,7 +151,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { headers = this.mainHd.select('td').removeClass(sortClasses), lockedLen = this.cm.getLockedCount(), cls = sortClasses[dir == 'DESC' ? 1 : 0]; - + if(col < lockedLen){ lockedHeaders.item(col).addClass(cls); }else{ @@ -339,7 +333,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls); Ext.fly(lrows[lrows.length - 1]).addClass(this.lastRowCls); }, - + syncRowHeights: function(row1, row2){ if(this.syncHeights){ var el1 = Ext.get(row1), @@ -369,7 +363,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { this.grid.fireEvent('viewready', this.grid); }, - renderUI : function(){ + renderUI : function(){ var templates = this.templates, header = this.renderHeaders(), body = templates.body.apply({rows:' '}); @@ -384,7 +378,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { lstyle: 'width:'+this.getLockedWidth()+';' }); }, - + afterRenderUI: function(){ var g = this.grid; this.initElements(); @@ -461,7 +455,7 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { ddGroup : g.ddGroup || 'GridDD' }); } - this.updateHeaderSortState(); + this.updateHeaderSortState(); }, layout : function(){ @@ -635,50 +629,50 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { var markup = this.renderRows() || [' ', ' ']; return [this.templates.body.apply({rows: markup[0]}), this.templates.body.apply({rows: markup[1]})]; }, - + refreshRow: function(record){ - var store = this.ds, - colCount = this.cm.getColumnCount(), - columns = this.getColumnData(), - last = colCount - 1, - cls = ['x-grid3-row'], + var store = this.ds, + colCount = this.cm.getColumnCount(), + columns = this.getColumnData(), + last = colCount - 1, + cls = ['x-grid3-row'], rowParams = { tstyle: String.format("width: {0};", this.getTotalWidth()) - }, + }, lockedRowParams = { tstyle: String.format("width: {0};", this.getLockedWidth()) - }, - colBuffer = [], - lockedColBuffer = [], - cellTpl = this.templates.cell, - rowIndex, - row, - lockedRow, - column, - meta, - css, + }, + colBuffer = [], + lockedColBuffer = [], + cellTpl = this.templates.cell, + rowIndex, + row, + lockedRow, + column, + meta, + css, i; - + if (Ext.isNumber(record)) { rowIndex = record; record = store.getAt(rowIndex); } else { rowIndex = store.indexOf(record); } - + if (!record || rowIndex < 0) { return; } - + for (i = 0; i < colCount; i++) { column = columns[i]; - + if (i == 0) { css = 'x-grid3-cell-first'; } else { css = (i == last) ? 'x-grid3-cell-last ' : ''; } - + meta = { id: column.id, style: column.style, @@ -686,49 +680,49 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { attr: "", cellAttr: "" }; - + meta.value = column.renderer.call(column.scope, record.data[column.name], meta, record, rowIndex, i, store); - + if (Ext.isEmpty(meta.value)) { meta.value = ' '; } - + if (this.markDirty && record.dirty && typeof record.modified[column.name] != 'undefined') { meta.css += ' x-grid3-dirty-cell'; } - + if (column.locked) { lockedColBuffer[i] = cellTpl.apply(meta); } else { colBuffer[i] = cellTpl.apply(meta); } } - + row = this.getRow(rowIndex); row.className = ''; lockedRow = this.getLockedRow(rowIndex); lockedRow.className = ''; - + if (this.grid.stripeRows && ((rowIndex + 1) % 2 === 0)) { cls.push('x-grid3-row-alt'); } - + if (this.getRowClass) { rowParams.cols = colCount; cls.push(this.getRowClass(record, rowIndex, rowParams, store)); } - + // Unlocked rows this.fly(row).addClass(cls).setStyle(rowParams.tstyle); rowParams.cells = colBuffer.join(""); row.innerHTML = this.templates.rowInner.apply(rowParams); - + // Locked rows this.fly(lockedRow).addClass(cls).setStyle(lockedRowParams.tstyle); lockedRowParams.cells = lockedColBuffer.join(""); lockedRow.innerHTML = this.templates.rowInner.apply(lockedRowParams); lockedRow.rowIndex = rowIndex; - this.syncRowHeights(row, lockedRow); + this.syncRowHeights(row, lockedRow); this.fireEvent('rowupdated', this, rowIndex, record); }, @@ -814,13 +808,13 @@ Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, { syncHeaderHeight: function(){ var hrow = Ext.fly(this.innerHd).child('tr', true), lhrow = Ext.fly(this.lockedInnerHd).child('tr', true); - + hrow.style.height = 'auto'; lhrow.style.height = 'auto'; var hd = hrow.offsetHeight, lhd = lhrow.offsetHeight, height = Math.max(lhd, hd) + 'px'; - + hrow.style.height = height; lhrow.style.height = height; diff --git a/source/sass/mgr/babel.scss b/source/sass/mgr/babel.scss new file mode 100644 index 0000000..ea591e9 --- /dev/null +++ b/source/sass/mgr/babel.scss @@ -0,0 +1,99 @@ +$red: #be0000; + +@import '../../js/ux/LockingGridView/LockingGridView'; + +.babel-panel { + .action-buttons { + text-align: center; + + li { + display: inline-block; + font-size: 1.1em; + line-height: .7; + margin-right: 5px; + + &:last-child { + margin-right: 0; + } + } + } + + .x-combo-list-item { + min-height: 20px; + } + + .icon-babel-description-img { + width: 16px; + height: 16px; + margin: 0 6px 0 12px; + + &:first-child { + margin-left: 0; + } + } +} + +.home-panel { + &.debug { + background: linear-gradient(to top right, transparent, transparent, transparent, #fff); + } +} + +.ribbon { + height: 180px; + overflow: hidden; + pointer-events: none; + position: absolute; + width: 180px; + z-index: 10; + + &:before, + &:after { + border: 5px solid mix(#000, $red, 15%); + content: ''; + display: block; + position: absolute; + z-index: -1; + } + + &.top-right { + right: -10px; + top: -10px; + + &:before, + &:after { + border-right-color: transparent; + border-top-color: transparent; + } + + &:before { + left: 0; + top: 0; + } + + &:after { + bottom: 0; + right: 0; + } + + span { + left: -46px; + top: 46px; + transform: rotate(45deg); + } + } + + span { + background-color: $red; + box-shadow: 0 5px 10px rgba(0, 0, 0, .1); + color: #fff; + display: block; + font: 700 18px/1 'Lato', sans-serif; + padding: 15px 0; + position: absolute; + text-align: center; + text-shadow: 0 1px 1px rgba(0, 0, 0, .2); + text-transform: uppercase; + width: 300px; + } +}