pax_global_header00006660000000000000000000000064147310601100014503gustar00rootroot0000000000000052 comment=eead4a224d62504485e2d3f02a7468787dd5ae89 kiwix-desktop-2.4.1/000077500000000000000000000000001473106011000143115ustar00rootroot00000000000000kiwix-desktop-2.4.1/.github/000077500000000000000000000000001473106011000156515ustar00rootroot00000000000000kiwix-desktop-2.4.1/.github/FUNDING.yml000066400000000000000000000012451473106011000174700ustar00rootroot00000000000000# These are supported funding model platforms github: kiwix # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: # https://kiwix.org/support-us/ kiwix-desktop-2.4.1/.github/stale.yml000066400000000000000000000007511473106011000175070ustar00rootroot00000000000000daysUntilClose: false staleLabel: stale issues: daysUntilStale: 60 markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be now be reviewed manually. Thank you for your contributions. pulls: daysUntilStale: 7 markComment: > This pull request has been automatically marked as stale because it has not had recent activity. It will be now be reviewed manually. Thank you for your contributions. kiwix-desktop-2.4.1/.github/workflows/000077500000000000000000000000001473106011000177065ustar00rootroot00000000000000kiwix-desktop-2.4.1/.github/workflows/ci.yml000066400000000000000000000043601473106011000210270ustar00rootroot00000000000000name: CI on: pull_request: push: branches: - main jobs: Windows: strategy: fail-fast: false matrix: config: - native_mixed runs-on: windows-2022 steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup python 3.8 uses: actions/setup-python@v5 with: python-version: '3.8' - name: Install packages run: | choco.exe install pkgconfiglite - name: Install QT uses: jurplel/install-qt-action@v4 with: version: 5.15.2 modules: "qtwebengine" setup-python: false - name: Setup MSVC compiler uses: bus1/cabuild/action/msdevshell@v1 with: architecture: x64 - name: Install dependencies uses: kiwix/kiwix-build/actions/dl_deps_archive@main with: target_platform: win-x86_64-mixed - name: Compile shell: cmd run: | set PKG_CONFIG_PATH=%cd%\BUILD_win-amd64\INSTALL\lib\pkgconfig qmake PREFIX=%cd%\BUILD_win-amd64\INSTALL nmake release-all Linux: strategy: fail-fast: false matrix: target: - jammy-qt5 - noble-qt6.4 - oracular-qt6.6 include: - target: jammy-qt5 image_variant: jammy lib_postfix: '/x86_64-linux-gnu' - target: noble-qt6.4 image_variant: noble lib_postfix: '/x86_64-linux-gnu' - target: oracular-qt6.6 image_variant: oracular lib_postfix: '/x86_64-linux-gnu' env: HOME: /home/runner runs-on: ubuntu-22.04 container: image: ghcr.io/kiwix/kiwix-build_ci_${{matrix.image_variant}}:2024-12-18 steps: - name: Install dependencies uses: kiwix/kiwix-build/actions/dl_deps_archive@main with: target_platform: linux-x86_64-dyn - name: Retrieve source code uses: actions/checkout@v4 - name: Compile source code shell: bash env: PKG_CONFIG_PATH: "/home/runner/BUILD_linux-x86_64/INSTALL/lib/pkgconfig:/home/runner/BUILD_linux-x86_64/INSTALL/lib${{matrix.lib_postfix}}/pkgconfig" run: | qmake PREFIX=$HOME/BUILD_linux-x86_64/INSTALL make kiwix-desktop-2.4.1/.github/workflows/package.yml000066400000000000000000000071101473106011000220230ustar00rootroot00000000000000name: Packages on: pull_request: push: branches: - main release: types: [published] jobs: build-deb: runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: distro: # - debian-unstable # - debian-trixie # - debian-bookworm # - debian-bullseye - ubuntu-noble - ubuntu-jammy - ubuntu-focal steps: - uses: actions/checkout@v4 # Determine which PPA we should upload to - name: PPA id: ppa run: | if [[ $REF == refs/tags* ]] then echo "::set-output name=ppa::kiwixteam/release" else echo "::set-output name=ppa::kiwixteam/dev" fi env: REF: ${{ github.ref }} - uses: legoktm/gh-action-auto-dch@main with: fullname: Kiwix builder email: release+launchpad@kiwix.org distro: ${{ matrix.distro }} # - uses: legoktm/gh-action-build-deb@debian-unstable # if: matrix.distro == 'debian-unstable' # name: Build package for debian-unstable # id: build-debian-unstable # with: # args: --no-sign # # - uses: legoktm/gh-action-build-deb@b47978ba8498dc8b8153cc3b5f99a5fc1afa5de1 # pin@debian-trixie # if: matrix.distro == 'debian-trixie' # name: Build package for debian-trixie # id: build-debian-trixie # with: # args: --no-sign # # - uses: legoktm/gh-action-build-deb@1f4e86a6bb34aaad388167eaf5eb85d553935336 # pin@debian-bookworm # if: matrix.distro == 'debian-bookworm' # name: Build package for debian-bookworm # id: build-debian-bookworm # with: # args: --no-sign # # - uses: legoktm/gh-action-build-deb@084b4263209252ec80a75d2c78a586192c17f18d # pin@debian-bullseye # if: matrix.distro == 'debian-bullseye' # name: Build package for debian-bullseye # id: build-debian-bullseye # with: # args: --no-sign - uses: legoktm/gh-action-build-deb@9114a536498b65c40b932209b9833aa942bf108d # pin@ubuntu-noble if: matrix.distro == 'ubuntu-noble' name: Build package for ubuntu-noble id: build-ubuntu-noble with: args: --no-sign ppa: ${{ steps.ppa.outputs.ppa }} - uses: legoktm/gh-action-build-deb@ubuntu-jammy if: matrix.distro == 'ubuntu-jammy' name: Build package for ubuntu-jammy id: build-ubuntu-jammy with: args: --no-sign ppa: ${{ steps.ppa.outputs.ppa }} - uses: legoktm/gh-action-build-deb@ubuntu-focal if: matrix.distro == 'ubuntu-focal' name: Build package for ubuntu-focal id: build-ubuntu-focal with: args: --no-sign ppa: ${{ steps.ppa.outputs.ppa }} - uses: actions/upload-artifact@v4 with: name: Packages for ${{ matrix.distro }} path: output - uses: legoktm/gh-action-dput@main name: Upload dev package if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' && startswith(matrix.distro, 'ubuntu-') with: gpg_key: ${{ secrets.LAUNCHPAD_GPG }} repository: ppa:kiwixteam/dev packages: output/*_source.changes - uses: legoktm/gh-action-dput@main name: Upload release package if: github.event_name == 'release' && startswith(matrix.distro, 'ubuntu-') with: gpg_key: ${{ secrets.LAUNCHPAD_GPG }} repository: ppa:kiwixteam/release packages: output/*_source.changes kiwix-desktop-2.4.1/.gitignore000066400000000000000000000007401473106011000163020ustar00rootroot00000000000000# Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app /kiwix-desktop # QtCreator Environment Settings (not suitable for sharing) kiwix-desktop.pro.user # Qt autogenerated files /qrc_*.cpp /ui_*.h /moc_*.h /moc_*.cpp /Makefile /.qmake.stash # IDE files /.vscode kiwix-desktop-2.4.1/COPYING000066400000000000000000001043741473106011000153550ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kiwix-desktop-2.4.1/ChangeLog000066400000000000000000000341431473106011000160700ustar00rootroot00000000000000kiwix-destkop 2.4.1 =================== Compilation: * FIX: PPA upload (@veloman-yunkan #1288) * NEW: Qt6 in CI (@adamlamar #1287 #1289) kiwix-destkop 2.4.0 =================== General: * FIX: Fullscreen with Wayland on Linux (@adamlamar #1046) * FIX: Fullscreen (auto-)scrolling (@sgourdas #1064) * FIX: Main window title at start (@juuz0 #962) * FIX: Proper fullscreen shortcut when run on WSL (@sgourdas #1080 #068) * FIX: Settings directories display (@sgourdas #1139 #1125) * FIX: More informative file-not-found page (@ShaopengLin #1132) * FIX: UI padding/margin improvements (@ShaopengLin #1146) * FIX: Stop crashing if ZIM file is somehow invalid (@veloman-yunkan #1086 #1174) * FIX: Support of RTL (@ShaopengLin #1187) * FIX: Improve support of high-density screens (@ShaopengLin #1198 #1208 #1209) * FIX: Launching from a network drive on Windows (@sgourdas #1215 #1180 #1178 #1170, @veloman-yunkan #1266) * FIX: App icons (@rgaudin @siemsie #1245) * FIX: Scrollabel Settings tab (@heropj #1269) * FIX: Bookmarks sidebar look & feel (@heropj #1256) * CHANGE: Non-standart boomark icon changed to standart "star" and adding tooltip (@sgourdas #1066) * CHANGE: Bookmarks sidebar shortcut to Ctrl+B (@vinurk #1090) * CHANGE: Simplify & improve handling of portable version (@sgourdas #1179) * NEW: Support of Qt6 (@adamlamar #1046) * NEW: Handle Win+Arrow shortcuts on Windows (@juuz0 #878) * NEW: Handle Ctrl+F4 and Ctrl+w tabs related shortcuts @juuz0 #968) * NEW: "Random Article" button (@juuz0 #928 #955) * NEW: Remember the current directory path to pen file over restart (@sgourdas #1058) * NEW: Block any resource required within a ZIM page (@veloman-yunkan #1116) * NEW: Remember window position over restart (@ShaopengLin #1126) * NEW: Implement the "Home" button (@sgourdas #1138) * NEW: import/export bookmarks (@ShaopengLin #1163) * NEW: Support of IPv6 in server and improve IP propositions (@sgourdas #1220 #1121) * NEW: Table of content sidebar (@ShaopengLin #1237) * NEW: Text to Speech tool (ShaopengLin #1143) * NEW: Open PDF files in ZIM via PDF reader (@juuz0 @veloman-yunkan #1123) Tabs: * FIX: Buggy tab closing fixed (@veloman-yunkan #1057) * FIX: Keep sidebars open by switching tabs (@sgourdas #1079) * NEW: Remember (current) tabs over restart (@ShaopengLin #1048 #1073) Search(es): * FIX: Keep vertical position after exiting find-in-page (@vinurk #1075) * FIX: Proper search bar focus shortcuts: F6, Ctrl_I, Alt + d, ... (@ShaopengLin #1061) * FIX: Fulltext search result handling (@sgourdas #1065) * FIX: Improve handling of bookmark button in searchbar (@ShaopengLin #1060) * NEW: Endless suggestion list (@ShaopengLin #1224) * NEW: Pressing ENTER in the searchbar opens first suggestion (@ShaopengLin #1232) * NEW: New search book chooser (@ShaopengLin #1218) Library: * FIX: Book downloader stability (@veloman-yunkan #1024 #1035 #1036 #1038 #118) * FIX: Properly check first if ZIM file can be saved to target filesystem (@veloman-yunkan #1188) * FIX: More informative message if lack of space to download (@veloman-yunkan #1092) * FIX: Detection of clicks on download control buttons (@veloman-yunkan #1101) * FIX: Smarter/robuster directory monitoring... for ZIM files (@veloman-yunkan #1164) * CHANGE: Moving library freetext search box to the sidebar (@juuz0 #554) * CHANGE: Dyanmicaly populated library language & category filter (@juuz0 #960) * CHANGE: Library revamping using Qt (@juuz0 #946 #965 #970, @ShaopengLin #1145) * NEW: Library double-click opening a book (@juuz0 #946) * NEW: Translated category label (@ShaopengLin #1175) * NEW: New Library "Open folder" button (@juuz0 #970) * NEW: Allow to nove book file to filesystem trash (@juuz0 #479) * NEW: Switch automatically to online library if no local book (@juuz0 #989) * NEW: Remember library filter values over restart (@juuz0 #974) * NEW: Added ContextMenu Button for Previewing Online Books (@ShaopengLin #1110) Compilation: * FIX: Better handle libzim and libkiwix dependencies (@kelson42 #1044) * FIX: PPA publishing workflow (@kelson42 #953) * FIX: Improve header includes order (@sgourdas #1077) * FIX Many fixes around Appimage version (@veloman-yunkan #1016) * CHANGE: Use latest libkiwix (@juuz0 #936, @kelson42 #1012, @mgautierfr ##1130, @aryanA101a #1112) * NEW: Enable compilation on WSL (@sgourdas #1071) Documentation: * CHANGE: [Proper documentation about where data are saved(https://github.com/kiwix/kiwix-desktop/wiki/Data-and-Configuration-Files) (@sgourdas #111]4) kiwix-destkop 2.3.1 =================== * Fix the AppImage packaging. Now published AppImages work correctly on recent distrubution (@mgautierfr #905) * Improve zim file picker (@kelson42 #886) * Do not show ServiceWorker zim file from the remote catalog (@kelson42 #887) kiwix-desktop 2.3.0 =================== * Fix downloading of file bigger than 4G (@juzz0 #855) * Hide top widget and topbar in fullscreen (@juzz0 #859) * Add shortcuts for navigating tabs (Ctrl-tab, Ctrl-shift-tab) (@juzz0 #867) * Do not use deprecated method `QWebEngineDownloadItem::setPath` (@juzz0 #853) * Fix compilation with last version of libkiwix (@mgautierfr #858) * Fix README.md (@psypherium #860) * Update translations. kiwix-desktop 2.2.2 =================== * Remove usage of deprecated libkiwix function (@juzz0 @mgautiefr #831) * Adapt kiwix-desktop to last libkiwix api (@mgautierfr #842, @veloman-yunkan #844) * Do not search (and crash) on a zim file without fulltext index (@mgautierfr #830) * Update translations. * [Flathub] Update link to screenshot kiwix-desktop 2.2.1 =================== * [HOTFIX] Fix a bug making kiwix-desktop removing ALL file in the library directory when a download fails (@juuz0 #816) * Improve update of the library view when downloading a book (@juuz0 #811) * Update translations. kiwix-desktop 2.2.0 =================== * Force the request to be explicit about the fact we don't want a book count limit. Fix case when server returns 0 books. (@juuz0 #769) * Correctly initialize mainWindows/contentManager. Fix crash on Windows. (@mgautierfr #783) * New Feature: Monitor a local directory for new/removed zim files (@juuz0 #743) * Fix library filtering on "other" category (@mgautier #791 #798) * Correctly set the zoom level on new pages (@juuz0 #774) * Fix setting UI when zoom level may be hidden by QSpinBox arroys (@juuz0 #799) * Remove filtering by fulltext index presence (@kelson42 #795) * Refactor internal code for better signal management (@asashnov #751) * Fix svg icon installation path (@xvitaly #773) * Fix typos and translations Known bugs: * AppImage build by our CI is buggy on recent Fedora, nothing is displayed in the WebView. This works correctly on AppImage build on Fedora or rpm packaged version. * Kiwix-desktop fails to download huge zim files because of too big metadata describing the download. kiwix-desktop 2.1.0 =================== * Add a IPChooser in the server dialog windows and display a best IP address on which the user can connect to (@juuz0 #735) * Open multiple zim files from the command line (@juuz0 #720) * Setting's zoom level change the zoom in all open tabs (@juuz0 #719) * Properly display back and forward buttons on RTL environment (@juuz0 #721) * Open new tabs just after the current tab (@juuz0 #716) * Always open new url in background (@juuz0 #717) * Make the server follow modification made in the library (@veloman-yunkan #714) * Improved setting tab (@juuz0 #696) * Display the shortcut of the action in its tootips (@juuz0 #682) * Limit zoom changes to the current tab only (@juuz0 #689) * Make the server use human-friendly name for zim files (@MananJethwany #676) * Fix tooltips' position (@kelson42 #672) * Improved server dialog (@HanYoung-uwu #638) * Add shortcuts to navigate in web history : - `BackButton`/`ForwardButton` (mouse buttons) (@Goutte #646) - `Alt+Left`/`Alt+Right` (@kelson42 #621) * Add `--version` and `--help` options (@HanYoung-uwu #631) * Fix file dialog style on Windows (@HanYoung-uwu #634) * Fix search result pagination (@maneeshpm #628) * Add shortcut `Alt + ` to switch between tabs (@rishabh-soni #567) * Fix fade-out tab when title is too long (@asashnov #573) * Use secure connection (https) when possible (@kelson42 #589) * Apply language filter to local library (@HanYoung-uwu #581) * Make `Search` and `Main Menu` buttons visible to screen reader (@asashnov #583) * Fix print support (@Ambrevar #557) * Adpat to new libkiwix 10.0.0 API * New SVG logo (@kelson42 #539) * Various fixes (@legoktm @HanYoung-uwu @Saket-07 @rishabh-soni @asashnov @manneshpm @MananJethwany) kiwix-desktop 2.0.5 =================== * Fix typos (@Abijeet) * Better font in the contentManager (@vishal-1408) * [CI] Add building and publication of deb package (@legoktm) * Check the available size in the configured downloaded directory instea of the default one (@mgautierfr) * Use kiwix-lib internal server instead of launching a kiwix-serve sub-process. (This remove dependency of kiwix-desktop on kiwix-tools) (@mgautierfr) * Update translation file. kiwix-desktop 2.0.4 =================== * Add "open link in web browser" action in context menu. * Improve setting UX (no apply button. Download directory dialog). * Change fonts to the free "Selawik". * Do not call `date` and `git describe` during build step to allow reproducible build. * Better about.html text. * Update translations. kiwix-desktop 2.0.3 =================== * Update logo * Use new threadsafe api of kiwix-lib to do suggestions search. kiwix-desktop 2.0.2 =================== * Add shortcut to set focus on the searchbar * Udpate logo * Create only one instance of the application. * Add content type filter * Fluid suggestion list UX * Fix text and add several translations kiwix-desktop 2.0.1 =================== * Automatically migrate data from the old data dir to the new one. * Improve UX of the fulltext search/suggestions. * Fix menu in fullscreen on Windows. kiwix-desktop 2.0 ================= * Readinglist doesn't close automatically * Move the search bar (in article) at the bottom of the view. * Fix zoom using mouse wheel. * Make new tab empty (instead of reusing the previous url). * Restore title tab when search bar loses focus. * Allow user to set the download directory in the setting. * Add search (in zim file) feature. * Correctly handle redirection article in zimfile. * Add a translation system using translatewiki. * Use the new tag system of library.kiwix.org. * Lot of UI tweaking and bug fixes. kiwix-desktop rc4 ================= * New "Settings" page * Better aria2c error message * Fix Reading list with bookmarks from missing books * Support video fullscreen mode * Support the default zoom level setting * Support zoom level per content * Remove page view source feature * Stop crashing if a download fails kiwix-desktop rc3 ================= * Correctly display a book in the local library at the end of download. * Do not display the context menu on the toolbar. * Remove the status bar. * Disable useless actions when displaying the library page. * Allow user to download files (epub) from a zim files. * Do not display obsolet bookmarks after removing a book from a library. * Correctly display zim's icons in the local library page. * Add "donate" action in the menu. * Display a tooltip with the url when a link is "mouse over". * Fix some debug information print on the console. kiwix-desktop rc2 ================= * Close tab on middle (scroll wheel) click. * Do not display hidden zim tag (starting with `_`) in the content manager. * Close all tabs displaying a book when we remove the book from the library. * Fix icons around the top bar. * Do not display the zim id in the searchbar. * Add a icons to the windows executable. * Remove the "Save page ..." action. * Correctly run kiwix-serve with the correct library.xml. kiwix-desktop rc1 ================= * Fix random crash when opening article (race condition). * Alert user if there is not enough place to download a zim file. * Better searchbar completion and validation. * Use the library.xml along the kiwix-desktop binary if present. (For kiwix-desktop+content on a usb key) * Better content manager design (css, icons, ...) * Add few shortcuts (alt+home, ctrl+mousewheel) * Refresh only information about downloading books instead of all books. * Remove RPATH from the binaries. * Add a new tag button. * Remove categories without content. * Integrate kiwix-serve (can run kiwix-serve from kiwix-desktop)7 * Add book sorting. kiwix-desktop beta5 =================== * Bug fixes (numerous) * Avoid to update the remote library when displaying the local library. * Add filtering by category for the local content. * Make zim files displayed with kiwix icon in the file explorer. * Make the windows' title displaying the current article's title. * Add an option to delete a book from the local library. * Display a "load" icon when we are loading/updating the remote library. * Add pause, resume and stop button for the downloads. * Fix crash when trying to open a non existant file (from a link). * Fix search bar reset. * Search result doesn't open a new tab. * Random article doesn't open a new tab. kiwix-desktop beta4 =================== * Fixup appdata information (for flatpak). * Add a filtering by language for the remote content. * Add a filtering by category for the remote content. kiwix-desktop beta3 =================== * Update README. * Update to last version of kiwix-lib. * Correctly install extra-files for flatpak. * Update `about.html` files. kiwix-desktop beta2 =================== * Do not crash in contentManager view and backend are out of sync. * Reduce number of requests when we search in the contentManager * Correctly handle the sideBar * Make the searchBar update to tab change. * Url encode the request to the server. * Get the favicon from the book instead of the reader. * Correctly style the first tab. * Ensure reading list is displayed in only one column. * Rename .desktop file to org.kiwix.desktop.desktop * Add a appdata file * Elide the title tab of the article. * Update style * Disable navigation buttons when needed * Remove text highlight when we quit search kiwix-desktop-2.4.1/LICENSE000066400000000000000000001045131473106011000153220ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kiwix-desktop-2.4.1/README.md000066400000000000000000000107771473106011000156040ustar00rootroot00000000000000 Download on Flathub Kiwix Desktop ============= The Kiwix Desktop is a viewer/manager of ZIM files for GNU/Linux and Microsoft Windows OSes. [![Release](https://img.shields.io/github/v/tag/kiwix/kiwix-desktop?label=release&sort=semver)](https://download.kiwix.org/release/kiwix-desktop/) [![Repositories](https://img.shields.io/repology/repositories/kiwix-desktop?label=repositories)](https://github.com/kiwix/kiwix-desktop/wiki/Repology) [![Build Status](https://github.com/kiwix/kiwix-desktop/workflows/CI/badge.svg?query=branch%3Amain)](https://github.com/kiwix/kiwix-desktop/actions?query=branch%3Amain) [![CodeFactor](https://www.codefactor.io/repository/github/kiwix/kiwix-desktop/badge)](https://www.codefactor.io/repository/github/kiwix/kiwix-desktop) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) Disclaimer ---------- This document assumes you have a little knowledge about software compilation. If you experience difficulties with the dependencies or with the Kiwix library compilation itself, we recommend to have a look at [kiwix-build](https://github.com/kiwix/kiwix-build). Dependencies ------------ The Kiwix Desktop application relies on many third party software libraries. The following libraries need to be available: * [libkiwix](https://github.com/kiwix/libkiwix/) * [Qt](https://www.qt.io/) * [aria2](https://aria2.github.io/) These dependencies may or may not be packaged by your operating system. They may also be packaged but only in an older version. The compilation script will tell you if one of them is missing or too old. In the worst case, you will have to download and compile a bleeding edge version by hand. Libkiwix has to be compiled dynamically, the best way to have it is to use [kiwix-build](https://github.com/kiwix/kiwix-build). Install needed packages (on Ubuntu 18.04+): ```bash sudo apt-get install libqt5gui5 qtbase5-dev qtwebengine5-dev \ libqt5svg5-dev qt5-image-formats-plugins aria2 \ qttools5-dev-tools qtchooser qt5-qmake \ qtbase5-dev-tools ``` Compilation ----------- Once all dependencies are installed, you can compile Kiwix Desktop: ```bash qmake . make ``` `qmake` will use pkg-config to locate libraries. Depending on where you've installed libkiwix (and other libraries) you may have to update the env variable `PKG_CONFIG_PATH`. It can be set as follows, for example, for x86-64 native systems: ```bash export PKG_CONFIG_PATH="<...>/BUILD_native_dyn/INSTALL/lib/x86_64-linux-gnu/pkgconfig" ``` You may want to simply open the kiwix-desktop project in QtCreator and then compile the project from there (don't forget to update `PKG_CONFIG_PATH` if necessary). Compilation with Qt6 -------------------- There is initial support for Qt6. Additional packages are needed: ```bash sudo apt install qt6-base-dev qt6-base-dev-tools qt6-webengine-dev libqt6webenginecore6-bin libqt6svg6 ``` And `qmake` needs to be configured to use Qt6. First confirm `qmake` is using the right version: ```bash qtchooser -install qt6 $(which qmake6) # run once export QT_SELECT=qt6 # set in environments where Qt6 builds are desired qmake --version ``` produces this output: ```bash $ qmake --version QMake version 3.1 Using Qt version 6.2.4 in /usr/lib/aarch64-linux-gnu ``` then build as normal: ```bash qmake . make ``` Installation ------------ To install Kiwix Desktop on the system: ```bash sudo make install ``` Run --- To run Kiwix Desktop ```bash kiwix-desktop ``` You might have to refresh the `ld` database before: ```bash sudo ldconfig ``` If you face problems such as `library not found...`, add the following environment variable: ```bash LD_LIBRARY_PATH="<...>/BUILD_native_dyn/INSTALL/lib/x86_64-linux-gnu" ``` ## Communication Available communication channels: * [Web Public Chat channel](https://chat.kiwix.org) * [Email](mailto:contact+android@kiwix.org) * [Mailing list](mailto:kiwix-developer@lists.sourceforge.net) * [Slack](https://kiwixoffline.slack.com): #android channel [Get an invite](https://join.slack.com/t/kiwixoffline/shared_invite/zt-19s7tsi68-xlgHdmDr5c6MJ7uFmJuBkg) * IRC: #kiwix on irc.freenode.net For more information, please refer to [https://wiki.kiwix.org/wiki/Communication](https://wiki.kiwix.org/wiki/Communication). License ------- [GPLv3](https://www.gnu.org/licenses/gpl-3.0) or later, see [LICENSE](LICENSE) for more details. kiwix-desktop-2.4.1/debian/000077500000000000000000000000001473106011000155335ustar00rootroot00000000000000kiwix-desktop-2.4.1/debian/changelog000066400000000000000000000002031473106011000174000ustar00rootroot00000000000000kiwix (0.0.0) unstable; urgency=medium * Initial release -- Kunal Mehta Wed, 22 Jul 2020 15:40:03 -0700 kiwix-desktop-2.4.1/debian/control000066400000000000000000000017771473106011000171520ustar00rootroot00000000000000Source: kiwix Section: misc Priority: optional Maintainer: Kiwix team Build-Depends: debhelper-compat (= 13), pkg-config, qtbase5-dev, qtwebengine5-dev, libqt5texttospeech5-dev, libkiwix-dev (>= 14.0), libkiwix-dev (<< 15.0), libzim-dev (>= 9.0), libzim-dev (<< 10.0), Standards-Version: 4.5.0 Homepage: https://www.kiwix.org/ Rules-Requires-Root: no Package: kiwix Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: offline Wikipedia reader Kiwix is an offline reader and manager for online content like Wikipedia, Project Gutenberg, or TED Talks. Kiwix allows you to read and search through offline content as they were online. Similar to a browser, Kiwix works with the highly compressed ZIM file format. . Features: * Pure ZIM file reader * Case and diacritics insensitive full text search engine * Bookmarks & Notes * ZIM base HTTP server * PDF/HTML export * Localized * Search suggestions * ZIM file Index capacity * Tabs navigation kiwix-desktop-2.4.1/debian/copyright000066400000000000000000000000441473106011000174640ustar00rootroot00000000000000See COPYING in the repository root. kiwix-desktop-2.4.1/debian/kiwix-desktop.1000066400000000000000000000003361473106011000204210ustar00rootroot00000000000000.TH KIWIX-DESKTOP "1" "July 2020" "Kiwix" "User Commands" .SH NAME kiwix-desktop \- viewer and manager for ZIM files .SH SYNOPSIS \fBkiwix\-desktop\fR [ZIMFILE]\fR .SH DESCRIPTION .TP ZIMFILE A ZIM file you wish to open. kiwix-desktop-2.4.1/debian/manpages000066400000000000000000000000271473106011000172500ustar00rootroot00000000000000debian/kiwix-desktop.1 kiwix-desktop-2.4.1/debian/rules000077500000000000000000000001431473106011000166110ustar00rootroot00000000000000#!/usr/bin/make -f export QT_SELECT=qt5 export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: dh $@ kiwix-desktop-2.4.1/debian/source/000077500000000000000000000000001473106011000170335ustar00rootroot00000000000000kiwix-desktop-2.4.1/debian/source/format000077500000000000000000000000151473106011000202450ustar00rootroot000000000000003.0 (native) kiwix-desktop-2.4.1/kiwix-desktop.pro000066400000000000000000000200561473106011000176400ustar00rootroot00000000000000#------------------------------------------------- # # Project created by QtCreator 2018-04-11T15:26:46 # #------------------------------------------------- QT += core gui network QT += webenginewidgets webchannel QT += printsupport qtHaveModule(texttospeech): QT += texttospeech # Avoid stripping incompatible files, due to false identification as executables, on WSL DETECT_WSL = $$system(test -f /proc/sys/fs/binfmt_misc/WSLInterop && echo true || echo false) equals(DETECT_WSL , "true"): CONFIG += nostrip CONFIG += link_pkgconfig greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = kiwix-desktop TEMPLATE = app QMAKE_CXXFLAGS += -std=c++17 QMAKE_LFLAGS += -std=c++17 !win32 { QMAKE_CXXFLAGS += -Werror equals(QT_MAJOR_VERSION, 6):equals(QT_MINOR_VERSION, 6) { # Fail the build on errors, except for 'template-id-cdtor' due to a problem with Qt headers. # This can be removed when the Ubuntu package is fixed. # See # https://github.com/RfidResearchGroup/proxmark3/issues/2382 # https://bugreports.qt.io/browse/QTBUG-126989 QMAKE_CXXFLAGS += -Wno-error=template-id-cdtor } } !win32:!static { QMAKE_LFLAGS += -Wl,-rpath-link,\'$$PREFIX/lib/x86_64-linux-gnu\' } # Also change resources/org.kiwix.desktop.appdata.xml DEFINES += VERSION="2.4.1" # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ src/choiceitem.cpp \ src/contentmanagerdelegate.cpp \ src/contentmanagerheader.cpp \ src/contentmanagermodel.cpp \ src/contenttypefilter.cpp \ src/descriptionnode.cpp \ src/downloadmanagement.cpp \ src/findinpagebar.cpp \ src/flowlayout.cpp \ src/kiwixchoicebox.cpp \ src/kiwixmessagebox.cpp \ src/kiwixlineedit.cpp \ src/kiwixlistwidget.cpp \ src/kiwixloader.cpp \ src/rownode.cpp \ src/suggestionlistworker.cpp \ src/suggestionlistmodel.cpp \ src/suggestionlistdelegate.cpp \ src/thumbnaildownloader.cpp \ src/translation.cpp \ src/main.cpp \ src/mainwindow.cpp \ src/kiwixapp.cpp \ src/kprofile.cpp \ src/blobbuffer.cpp \ src/library.cpp \ src/settingsmanager.cpp \ src/settingsview.cpp \ src/topwidget.cpp \ src/urlschemehandler.cpp \ src/webview.cpp \ src/searchbar.cpp \ src/mainmenu.cpp \ src/webpage.cpp \ src/about.cpp \ src/contentmanager.cpp \ src/contentmanagerview.cpp \ src/tabbar.cpp \ src/contentmanagerside.cpp \ src/readinglistbar.cpp \ src/tableofcontentbar.cpp \ src/klistwidgetitem.cpp \ src/opdsrequestmanager.cpp \ src/localkiwixserver.cpp \ src/fullscreenwindow.cpp \ src/fullscreennotification.cpp \ src/zimview.cpp \ src/multizimbutton.cpp \ qtHaveModule(texttospeech): SOURCES += src/texttospeechbar.cpp \ HEADERS += \ src/choiceitem.h \ src/contentmanagerdelegate.h \ src/contentmanagerheader.h \ src/contentmanagermodel.h \ src/contentmanagerview.h \ src/contenttypefilter.h \ src/descriptionnode.h \ src/downloadmanagement.h \ src/findinpagebar.h \ src/flowlayout.h \ src/kiwixchoicebox.h \ src/kiwixmessagebox.h \ src/kiwixlineedit.h \ src/kiwixlistwidget.h \ src/kiwixloader.h \ src/node.h \ src/rownode.h \ src/suggestionlistworker.h \ src/suggestionlistmodel.h \ src/suggestionlistdelegate.h \ src/thumbnaildownloader.h \ src/translation.h \ src/mainwindow.h \ src/kiwixapp.h \ src/kprofile.h \ src/blobbuffer.h \ src/library.h \ src/settingsmanager.h \ src/settingsview.h \ src/topwidget.h \ src/kconstants.h \ src/urlschemehandler.h \ src/webview.h \ src/searchbar.h \ src/mainmenu.h \ src/webpage.h \ src/about.h \ src/contentmanager.h \ src/tabbar.h \ src/contentmanagerside.h \ src/readinglistbar.h \ src/tableofcontentbar.h \ src/klistwidgetitem.h \ src/opdsrequestmanager.h \ src/localkiwixserver.h \ src/fullscreenwindow.h \ src/fullscreennotification.h \ src/menuproxystyle.h \ src/zimview.h \ src/portutils.h \ src/css_constants.h \ src/multizimbutton.h \ src/kiwixwebchannelobject.h \ qtHaveModule(texttospeech): HEADERS += src/texttospeechbar.h \ FORMS += \ src/choiceitem.ui \ src/contentmanagerview.ui \ src/findinpagebar.ui \ ui/kiwixchoicebox.ui \ ui/kiwixmessagebox.ui \ ui/mainwindow.ui \ ui/about.ui \ src/contentmanagerside.ui \ src/readinglistbar.ui \ ui/localkiwixserver.ui \ ui/settings.ui \ src/tableofcontentbar.ui \ qtHaveModule(texttospeech): FORMS += src/texttospeechbar.ui \ include(subprojects/QtSingleApplication/src/qtsingleapplication.pri) CODECFORSRC = UTF-8 isEmpty(PREFIX) { PREFIX = /usr/local } target.path = $$PREFIX/bin INSTALLS += target static { PKGCONFIG_OPTION = "--static" } unix { desktop_file.path = $$PREFIX/share/applications/ desktop_file.files = resources/org.kiwix.desktop.desktop INSTALLS += desktop_file metainfo_file.path = $$PREFIX/share/metainfo/ metainfo_file.files = resources/org.kiwix.desktop.appdata.xml INSTALLS += metainfo_file app_icon24.path = $$PREFIX/share/icons/hicolor/24x24/apps app_icon24.files = resources/icons/kiwix/24/kiwix-desktop.png app_icon32.path = $$PREFIX/share/icons/hicolor/32x32/apps app_icon32.files = resources/icons/kiwix/32/kiwix-desktop.png app_icon48.path = $$PREFIX/share/icons/hicolor/48x48/apps app_icon48.files = resources/icons/kiwix/48/kiwix-desktop.png app_icon128.path = $$PREFIX/share/icons/hicolor/128x128/apps app_icon128.files = resources/icons/kiwix/128/kiwix-desktop.png app_icon256.path = $$PREFIX/share/icons/hicolor/256x256/apps app_icon256.files = resources/icons/kiwix/256/kiwix-desktop.png app_icon512.path = $$PREFIX/share/icons/hicolor/512x512/apps app_icon512.files = resources/icons/kiwix/512/kiwix-desktop.png app_svg.path = $$PREFIX/share/icons/hicolor/scalable/apps app_svg.files = resources/icons/kiwix/scalable/kiwix-desktop.svg INSTALLS += app_icon24 app_icon32 app_icon48 app_icon128 app_icon256 app_icon512 app_svg mime_icon48.path = $$PREFIX/share/icons/hicolor/48x48/mimetypes mime_icon48.files = resources/icons/48/kiwix/org.kiwix.desktop.x-zim.png mime_icon128.path = $$PREFIX/share/icons/hicolor/128x128/mimetypes mime_icon128.files = resources/icons/128/kiwix/org.kiwix.desktop.x-zim.png mime_icon256.path = $$PREFIX/share/icons/hicolor/256x256/mimetypes mime_icon256.files = resources/icons/256/kiwix/org.kiwix.desktop.x-zim.png mime_icon512.path = $$PREFIX/share/icons/hicolor/512x512/mimetypes mime_icon512.files = resources/icons/512/kiwix/org.kiwix.desktop.x-zim.png INSTALLS += mime_icon48 mime_icon128 mime_icon256 mime_icon512 mime_file.path = $$PREFIX/share/mime/packages/ mime_file.files = resources/org.kiwix.desktop-mime.xml INSTALLS += mime_file } DEPS_DEFINITION = \"libkiwix >= 14.0.0 libkiwix < 15.0.0 libzim >= 9.0.0 libzim < 10.0.0\" PKGCONFIG_CFLAGS = $$system(pkg-config --cflags $$PKGCONFIG_OPTION $$DEPS_DEFINITION) QMAKE_CXXFLAGS += $$PKGCONFIG_CFLAGS QMAKE_CFLAGS += $$PKGCONFIG_CFLAGS !win32 { LIBS += $$system(pkg-config --libs $$PKGCONFIG_OPTION $$DEPS_DEFINITION) } win32 { LIBS += $$system(python scripts/pkg-config-wrapper.py --libs $$PKGCONFIG_OPTION $$DEPS_DEFINITION) } RESOURCES += \ resources/kiwix.qrc \ resources/translations.qrc \ resources/contentmanager.qrc \ resources/settingsmanager.qrc \ resources/style.qrc \ resources/js.qrc RC_ICONS = resources/icons/kiwix/app_icon.ico kiwix-desktop-2.4.1/resources/000077500000000000000000000000001473106011000163235ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/contentmanager.qrc000066400000000000000000000001461473106011000220400ustar00rootroot00000000000000 css/_contentManager.css kiwix-desktop-2.4.1/resources/css/000077500000000000000000000000001473106011000171135ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/css/_contentManager.css000066400000000000000000000027631473106011000227410ustar00rootroot00000000000000#contentmanagerside { background-color: red; } QTreeView::branch:open:has-children { image: url(:/icons/caret-down-solid.svg); padding: 6px; } QTreeView::branch:closed:has-children { image: url(:/icons/caret-right-solid.svg); padding: 7px; } QTreeView::branch:has-children { border-bottom: 1px solid #cccccc; } QTreeView::branch:has-children:hover { background-color: #eaecf0; } QTreeView::item:has-children { border-bottom: 1px solid #cccccc; } QTreeView { font-family: 'Selawik'; padding: 4px; /* XXX: duplicated in css_constants.h */ border: none; selection-color: black; qproperty-iconSize: 30px; } QTreeView::item:hover { background-color: #eaecf0; } QHeaderView::section { color: #666666; background-color: #fff; border-width: 0px 0px 2px; border-color: black; border-style: plain; font-size: 16px; font-family: 'Selawik'; padding: 4px; margin-left: 10px; } QHeaderView::down-arrow { image: url(:/icons/caret-down-solid.svg); height: 12px; width: 12px; padding-bottom: 6px; subcontrol-position: left; } QHeaderView::up-arrow { image: url(:/icons/caret-up-solid.svg); height: 12px; width: 12px; padding-bottom: 6px; subcontrol-position: left; } QMenu { background-color: white; margin: 2px; font-family: 'Selawik'; } QMenu::item { padding: 2px 25px 2px 20px; border-bottom: 1px solid #cccccc; } QMenu::item:selected { background-color: #cccccc; } kiwix-desktop-2.4.1/resources/css/_settingsManager.css000066400000000000000000000024741473106011000231260ustar00rootroot00000000000000QWidget#widget { max-width: 600; } QLabel, QPushButton, QSpinBox { font-size: 16px; line-height: 24px; } QLabel, QPushButton { padding: 12px 8px; } QFrame[frameShape="4"] { /*frameShape 4 is HLine */ border: 1px solid #eaecf0; min-height: 0; max-height: 1pt; } QLabel#settingsLabel { font-size: 32px; line-height: 44px; font-weight: bold; } QSpinBox, QLabel#downloadDirPath, #monitorDirPath { font: bold 12pt; } QPushButton { background-color: white; color: #3366cc; padding: 4px; font: bold; border-radius: 4px; } QPushButton:hover { background-color: #3366cc; color: white; } #downloadDirPathCopy, #monitorDirPathCopy { background-color: none; border: 1px solid transparent; } #downloadDirPathCopy:hover, #monitorDirPathCopy:hover { background-color: #D9E9FF; border: 1px solid #3366CC; border-radius: 3px; } #monitorDirLabel { padding-right: 0; } #monitorHelp { padding: 1; margin: 0; background: #666666; color: white; border-radius: 2px; max-height: 18px; min-width: 14px; font: bold; } QCheckBox::indicator { width: 16px; height: 16px; border: 2px solid black; border-radius: 5px; padding: 4px; } QCheckBox::indicator:checked { image: url(:/icons/check-solid.svg); } kiwix-desktop-2.4.1/resources/css/choiceBox.css000066400000000000000000000020551473106011000215320ustar00rootroot00000000000000QListWidget::item { padding: 0; padding-top: 6px; padding-bottom: 6px; padding-left: 2px; } QListWidget { padding: 0; border: 1px solid #ccc; } QListWidget::item::selected { color: #444444; background-color: transparent; } QLineEdit { padding: 4px; border: 0; } #choiceLabel { font-size: 16px; } #currentChoices { margin: 0; padding: 0; border: 1px solid #ccc; border-radius: 1px; } #closeButton { margin: 0; background: transparent; color: #eaecf0; font-size: 12px; } ChoiceItem > QFrame { border: 1px solid #ccc; border-radius: 2px; padding: 0; background-color: #666; padding-left: 2px; padding-right: 2px; margin:0; } #itemLabel { margin: 0; height: 6px; background-color: #666; color: #eaecf0; font-size: 13px; } #clearButton { background-color: white; color: #3366cc; padding: 4px; font: bold; font-size: 14px; border-radius: 4px; } #clearButton:hover { background-color: #3366cc; color: white; } kiwix-desktop-2.4.1/resources/css/contentmanagerside.css000066400000000000000000000006571473106011000235070ustar00rootroot00000000000000#searcher { font-family: 'Selawik'; padding: 4px; border: none; border-bottom: 1px solid #cccccc; color: #666666; font-size: 16px; height: 32px; line-height: 24px; } QScrollArea { border: 0; } #allFileButton, #localFileButton, #contentTypeButton { padding-left: 2px; } #allFileButton::indicator, #localFileButton::indicator, #contentTypeButton::indicator { height: 0; width: 0; } kiwix-desktop-2.4.1/resources/css/localServer.css000066400000000000000000000010121473106011000221000ustar00rootroot00000000000000QWidget { background-color: white; } QDialog { border: 2px solid #cccccc; } QPushButton { opacity: 1; border: none; padding: 3px; color: RoyalBlue; outline: 0; } QPushButton:hover { color: rgba(65, 105, 225, 0.9); } QLineEdit { border: 1 solid #cccccc; padding: 2px; } QLabel { margin-left: 8px; margin-top: 4px; } #IpChooser { border-color: #cccccc; } #stackedWidget { margin-top: 8px; margin-bottom: 4px; } #KiwixServerButton { margin-right:8px; } kiwix-desktop-2.4.1/resources/css/messageBox.css000066400000000000000000000010321473106011000217160ustar00rootroot00000000000000* { font-family: 'Selawik'; background-color: white; font-size: 16px; } QDialog { border: 2px solid #cccccc; } #confirmTitle { font-size: 18px; line-height: 44px; font-weight: bold; } QPushButton { opacity: 1; padding: 6px; outline: 0; border-radius: 2px; width: 24px; border: 1px solid #3366cc; color: #3366cc; } QPushButton:hover { background-color: #3366cc; color: white; } #closeButton { border: 0; } #closeButton:hover { background-color: transparent; } kiwix-desktop-2.4.1/resources/css/popup.css000066400000000000000000000013441473106011000207720ustar00rootroot00000000000000QTreeView { background-color: white; border: none; outline: none; } QTreeView::item { border: 1px solid transparent; } QTreeView::item:selected { border: 1px solid #3366CC; background-color: #D9E9FF; color: black; } QHeaderView { background-color: white; } QHeaderView::section { border: none; color: #3b3b3b; background-color: white; margin-top: 5px; /* XXX: duplicated in css_constants.h */ padding: 5px 10px; /* XXX: duplicated in css_constants.h */ font-size: 16px; line-height: 24px; /* XXX: duplicated in css_constants.h */ font-weight: 400; } QScrollBar { width: 5px; border: none; outline: none; } QScrollBar::handle { background-color: grey; }kiwix-desktop-2.4.1/resources/css/style.css000066400000000000000000000241741473106011000207750ustar00rootroot00000000000000QWidget { background-color: #EAECF0; color: #000000; } /* ------------------------------------ The topBar */ TopWidget { min-height: 48px; max-height: 48px; margin: 0; padding: 5px; border: none; border-bottom: 1px solid #ccc; } TopWidget::separator { background: none; border: none; width: 40px; } QToolButton { background: none; height: 40px; width: 40px; border: none; } SearchBar { background-color: white; margin: 2px; /* XXX: duplicated in css_constants.h */ border: 1px solid #ccc; /* XXX: duplicated in css_constants.h */ border-radius: 3px; max-height: 40px; } SearchBar > QLabel#searchIcon { padding: 0; border: none; background-color: none; margin: 0px 6px; max-height: 38px; max-width: 38px; } SearchBar > SearchBarLineEdit { background-color: white; margin: 0; padding: 0; color: #666; border: none; font-size: 16px; max-height: 38px; } SearchBar > QToolButton { padding: 0; border: 0 solid #fff; background-color: none; max-height: 38px; max-width: 38px; } SearchBar > QToolButton:pressed, SearchBar > QToolButton:hover { border: 1px solid #3366CC; background-color: #D9E9FF; border-radius: 3px; } MultiZimButton QListWidget { border: 0px; outline: 0px; padding: 5px 0px; /* XXX: duplicated in css_constants.h */ background-color: white; } MultiZimButton QListWidget::item { padding: 0px 5px; /* XXX: duplicated in css_constants.h */ border: 1px solid transparent; /* XXX: duplicated in css_constants.h */ background-color: white; } MultiZimButton QListWidget::item:hover, MultiZimButton QListWidget::item:selected:active { border: 1px solid #3366CC; background-color: #D9E9FF; } MultiZimButton QScrollBar { width: 5px; /* XXX: duplicated in css_constants.h */ border: none; outline: none; } MultiZimButton QScrollBar::handle { background-color: grey; } ZimItemWidget * { background-color: transparent; } ZimItemWidget QLabel { font-size: 16px; line-height: 24px; /* XXX: duplicated in css_constants.h */ } ZimItemWidget QRadioButton::indicator { image: none; } ZimItemWidget QRadioButton::indicator:checked { image: url(:/icons/tick.svg); } TopWidget QToolButton:pressed, TopWidget QToolButton::hover { border: 1px solid #3366CC; background-color: #D9E9FF; border-radius: 3px; } TopWidget QToolButton::menu-button { width: 100%; background: rgba(0, 0, 0, 0); } TopWidget QToolButton::menu-arrow { image: none; } TopWidget QToolButton::menu-indicator { width: 0; /* it can be hidden at all by setting 0px */ height: 0; subcontrol-origin: padding; } TopWidget QToolButton#backButton { margin-left: 6px; /* XXX: duplicated in css_constants.h */ } TopWidget QToolButton#fullScreenButton { margin-right: 6px; } /* ---------------------------------------- Menu */ QMenu { border: none; min-width: 320px; } QMenu::item { min-width: 320px; min-height: 40px; max-height: 40px; border: 1px solid transparent; padding: 2px 12px 2px 40px; /* top right bottom left */ } QMenu::icon { min-width: 40px; min-height: 40px; } QMenu::item:selected { background-color: #D9E9FF; border: 1px solid #3366CC; } MainMenu::indicator { color: #666666; width: 13px; height: 13px; } WebViewForwardMenu::item, WebViewBackMenu::item { padding: 2px 12px; } WebViewForwardMenu::icon, WebViewBackMenu::icon { min-width: 2px; min-height: 2px; } /* ----------------------------------------- TabWidget */ QTabBar { font-size: 16px; icon-size: 24px; border-bottom: 1px solid #ccc; } QTabBar::tear { width: 0px; height: 0px; border: none; } QTabWidget::pane { top: -2px; border: none; border-top: 1px solid #ccc; } QTabBar::tab { border: 1px solid #ccc; /* XXX: duplicated in css_constants.h */ border-radius: 0; padding: 4px; /* XXX: duplicated in css_constants.h */ padding-top: 6px; } QTabBar::tab:selected { background-color: white; border-bottom: 1px solid white; } QTabBar::tab:first { padding-top: 6px; padding-left: 5px; } #closeTabButton, #newTabButton { font-size: 30px; width: 30px; min-width: 30px; max-width: 30px; height: 30px; min-height:30px; max-height:30px; border-radius: 3px; } #nextTabButton, #prevTabButton, #newTabSideButton { border: 1px solid #ccc; } #closeTabButton:hover, #newTabButton:hover, #nextTabButton:hover, #prevTabButton:hover, #newTabSideButton:hover { border: 1px solid #3366CC; background-color: #D9E9FF; border-radius: 3px; } QTabBar::scroller { width: 0px; height: 0px; /* Last tab size is off by 1 if border not set. */ border: 1px solid transparent; } /* ----------------------------------------- TabWidget */ #aboutText { padding: 20px; background-color: white; } /* ---------------------------------------- Find Search page */ #FindInPageBar { border-top: 1px solid #ccc; } #findEdit { background-color: white; padding: 2px; max-height: 36px; color: #666; font-size: 16px; border: 1px solid #ccc; border-radius: 0; } #fNextButton, #fPreviousButton, #hideButton { outline: none; max-height: 36px; max-width: 36px; border: 1px solid #ccc; border-radius: 0; } #fNextButton:pressed, #fPreviousButton:pressed, #hideButton:pressed { background-color: #D9E9FF; border: 1px solid #3366CC; } /* ---------------------------------------- Find Search page */ #contentmanagerside QWidget { background-color: white; outline: none; } #contentmanagerside QRadioButton, #contentmanagerside QCheckBox { padding: 10px; } #contentmanagerside QRadioButton:checked { border: none; } #contentmanagerside QRadioButton::indicator { image: none; } #contentmanagerside QCheckBox::indicator { image: none; } #contentmanagerside QListWidget { border: none; padding-left: 30px; show-decoration-selected: 0; } #contentTypeSelector QCheckBox { padding: 0; } #categorySelector QScrollBar, #languageSelector QScrollBar { width: 5px; border: none; outline: none; } #categorySelector QScrollBar::handle, #languageSelector QScrollBar::handle { background-color: grey; } #categorySelector::item:selected, #languageSelector::item:selected { background-color: white; color: black; outline: none; } #contentTypeAllButton, ContentTypeFilter { spacing: 10; } #tableofcontentbar { background-color: white; } #tableofcontentbar QTreeWidget, #tableofcontentbar QLabel, #tableofcontentbar QFrame { background-color: white; } #tableofcontentbar QTreeWidget { outline: none; } #tableofcontentbar QTreeWidget::item { height: 26px; padding: 0px 10px; outline: none; border-top: 1px solid transparent; border-bottom: 1px solid transparent; } #tableofcontentbar QTreeWidget::item:selected, #tableofcontentbar QTreeWidget::item:hover { outline: none; border-top: 1px solid #3366CC; border-bottom: 1px solid #3366CC; background-color: #D9E9FF; color: black; } #tableofcontentbar QTreeWidget::branch:selected, #tableofcontentbar QTreeWidget::branch:hover { outline: none; border-top: 1px solid #3366CC; border-bottom: 1px solid #3366CC; background-color: #D9E9FF; } #tableofcontentbar QTreeWidget::branch { image: none; } #tableofcontentbar #titleLabel { padding: 0px; margin: 10px; } #tableofcontentbar #hideLabel { margin: 13px 10px 10px; /* 3px to match bottom with titleLabel */ } #tableofcontentbar QScrollBar { width: 5px; border: none; outline: none; } #tableofcontentbar QScrollBar::handle { background-color: grey; } /*this selector worked after changing class ReadingListBar to a QFrame instead of QWidget in readinglistbar.h file*/ #readinglistbar { background-color: white; } #readinglistbar QPushButton::menu-indicator { width: 0; height: 0; } #readinglistbar QTreeWidget, #readinglistbar QLabel, #readinglistbar QFrame, #readinglistbar QListWidget, #readinglistbar QPushButton { background-color: white; } #readinglistbar QPushButton{ margin: 13px 10px 10px; } #readinglistbar QListWidget { outline: none; } #readinglistbar QListWidget::item, #readinglistbar QListWidget::item:selected{ height: 26px; padding: 0px 10px; outline: none; border-top: 1px solid transparent; border-bottom: 1px solid transparent; color: black; } #readinglistbar QListWidget::item:hover { outline: none; border-top: 1px solid #3366CC; border-bottom: 1px solid #3366CC; background-color: #D9E9FF; color: black; } #readinglistbar #titleLabel { padding: 0px; margin: 10px; } #readinglistbar QScrollBar { width: 5px; border: none; outline: none; } #readinglistbar QScrollBar::handle { background-color: grey; } #readinglistbar QLabel#titleLabel { font-family: "Selawik"; font-size: 24px; /*equivalent to font-size 18*/ font-weight: 500; /*equivalent to font-weight medium*/ } /* ---------------------------------------- Text to Speech Page */ TextToSpeechBar { border-top: 1px solid #ccc; } TextToSpeechBar #closeButton { outline: none; max-height: 36px; max-width: 36px; border: 1px solid #ccc; border-radius: 0; } TextToSpeechBar #stopButton { outline: none; max-height: 36px; padding: 0px 10px; background-color: white; border: 1px solid #ccc; border-radius: 0; } TextToSpeechBar #stopButton:hover { background-color: #D9E9FF; border: 1px solid #3366CC; } TextToSpeechBar #stopButton:disabled { color: grey; background-color: darkgrey; } TextToSpeechBar QComboBox::drop-down { height: 22px; width: 15px; padding: 0px 2px; margin: 0px; image: url(":/icons/drop-down.svg"); background-color: white; } TextToSpeechBar QComboBox { background-color: white; border: 1px solid #ccc; } TextToSpeechBar QAbstractItemView QScrollBar { width: 5px; border: none; outline: none; } TextToSpeechBar QAbstractItemView QScrollBar::handle { background-color: grey; } kiwix-desktop-2.4.1/resources/fonts/000077500000000000000000000000001473106011000174545ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/fonts/Selawik/000077500000000000000000000000001473106011000210535ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/fonts/Selawik/LICENSE.txt000066400000000000000000000106351473106011000227030ustar00rootroot00000000000000Copyright 2015, Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. All Rights Reserved. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries. This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. kiwix-desktop-2.4.1/resources/fonts/Selawik/selawk.ttf000066400000000000000000001263001473106011000230620ustar00rootroot00000000000000pDSIGT>&GDEF{xJGPOSiM{LGSUBstOS/2HMx`cmap"LXgasp {l glyfףF$dheadީ6hhea04$hmtxdmlocar `maxppX name9Vjtpost2{L yi_<DSR| bQ n b``dMO332H MS @ !"Q   *1))))))))))]]]]]]]         }_}_}_}_!!!!!!!!nE!/\\\\\\\\\r\{{\@P@P@P@P@P1)1)1)1)1)yyyyylllll5555[[[[[[[[[[[_____cy`ecc/`/`/`/`/`/`/`/`/`4cccc@dd41_________l`cK6eVeVeVeVeVZ+++++5555PUPPlPP PPoPbP\PVr@xibVWo@['FFo|w#'R2j\jBjj5jjR33 \ H\*'U]UY'PrdPdPfPTPPPEyyyyyyy P PyygwTV/Lly00:ndkA]qBsn%f3\PhW%f@R2{H>R#Y "/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' ?C^uywx}|>< %:798;RW G2&-~,$ HI(n#?0)*+-ABD\]_V^[SX]UZ\TV@ /9~#'+37HM[gk~7 (6    " & 0 : !" 0: &*.69JP^jn7 &5    & 0 9 !"m4wTp$,>@^bdnvz|"/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' %!&4:W8,9[<2R-7U  -)*+?DABHC.G_\]^lKyuw}x|~(zv {"$#&./,(246578;=<>FEINPORTSYXWac`bgmnqsrUZVTSX]\^ZI@DPKAHGMJBECLONifho>?(V>l>d LFRj8XxD".BZ *Td|  , ^  N h 0  B j H~R$Bj:`,H f L>*6B".nz P&P,8DP\ht ,8RBNZfr~@v Xdp"Hx    & 2 > | !!!2!Z!f!r!~!!!!!!""F"""##*##$$@$$$%&%J%Z%p%%%%%%&:&P&&&&&&&' ','>'J'h't'''''''(((4(T(h(r(z(z(()H)))*$*N*z*****++v, ,",B,P,d,-N-n-.(...// /L/Z/v/////0 0"000F0T0p00000011*1H1Z11111122>2R!#3#&&'#^q&(8f9H C" #73!#3#&&'#^q&(\f9H C &'332673#!#3#&&'# E:8H V^q&(4oe),-(eof9H C&#%3#'!#3#&&'#H^q&(53EnN 1|uR  #367#M騨D# 8/7T*}z# !##367653'{騨D# 8<2u/7T*}8tQXGF3!!@ 3#3!!@ƚ"3QF# 3!!6653@'<2iUtQXG"3! %!573%H"``̚r337673#47##&'##*$Ҥ  R&r+g&fs$6'H5A?zA33&&53#&&'## ' !  K%;fyB>A3#33&&53#&&'## ' !  ƣK%;fyB>A 373#33&&53#&&'## ' !   K%;fyB>#A33&&53#&&'##6653 ' !  '<2K%;fyB>iUtQXGA%'>7&'##33&&53Aw> &  Kjs!M>L%;A0&'&&#"#46323253#33&&53#&&'##hD3*9DraU$<,(8Jv,P60 ' !  ']l`Fl<K%;fyB>\$54$32#66'4&#"34̤44ѝqqܝrrޞOR\#3#$54$32#66'4&#"3z̤44ѝqqܝrrޞOR\&3#'#$54$32#66'4&#"3΅y̤44ѝqqܝrrޞyyɿOR\ )9&&54632# &54632#$54$32#66'4&#"3$8!E22H!6 OFD12GD3o̤44ѝqqܝrrޞ !7 3DE2 8 E33DE22FܿOR\#3#$54$32#66'4&#"3ɝ̤44ѝqqܝrrޞɿOR\'3#%3#$54$32#66'4&#"3ִܒ̤44ѝqqܝrrޞǿOR\#!!$54$32#66'4&#"3vk̤44ѝqqܝrrޞƿOR\",#"&''7&54$327&#"654&'3H`хVNPS4{SN(\zrq985RLAaREA?SgL~\(8&'&&#"#46323253#$54$32#66'4&#"3nD3*9DraU$<,(8Jv,P6̤44ѝqqܝrrޞ']l`Fl<OR\(%!"#"$54$323!!!!327&#"n5n]֟J/g.d$rRm֗{_~ NR # S* !2###2654&#t헻Wbq*###33654&#3t헻uưbq\'&&'#"$54$32326'4&#"z[TU\̤42rޞqqܝr%%OR¿[!###!2654&#3orưdY}/|~v#73###!2654&#3,orư4dY}/|~v%373###!2654&#3쯤Jorư놆dY}/|~v# !####!2&654&#3653'or>ư<2udY}/w~vtQXGFP*&'732654&&'.54632'&&#"#yAqPOufxfӫA>lLIla~prڙ 3::-mOi@)1TvC ]e?Z=+7`~z`P.3#&'732654&&'.54632'&&#"#CyAqPOufxfӫA>lLIla~prڙ3::-mOi@)1TvC ]e?Z=+7`~z`P 1373#&'732654&&'.54632'&&#"#˯XyAqPOufxfӫA>lLIla~prڙ 3::-mOi@)1TvC ]e?Z=+7`~z`PP<2!"'53254#"5&'732654&&'.54632'&&#"2Ila~p[|jz$, k{AqPOufxfӫA>lLZ=+7`~mg :[QxFH3;:-mOi@)1TvC ]eP#*2&'732654&&'.54632'&&#"#6653yAqPOufxfӫA>lLIla~prڙa'<2 3::-mOi@)1TvC ]e?Z=+7`~z`tUtQXG) !5!!#cb) 3###53!5!n̨ct)  373#!5!!#įcb 㘘)P !2!"'53254#"5#!5!!Fjz$, (cb@[QxFH)# !5!!#6653cb?'<2iUtQXG3! 3!th*mFq3#3! 3!Ith*mFq3#'#3! 3!2thyy*mFq (&&54632# &54632#3! 3!8!E22H!6 OFD12GD3(th !7 3DE2 8 E33DE22F*mFq3#3! 3!ɝth*mFq3#%3#3! 3!ܒth*mFq!!3! 3!v$th*mFqp327#"5467&3! <&8b1]T6th1ABTu ;x%*mFqR*&&546632#6654&#"33! 3!\57_;9]57`;-77)'55'th2W58Z42X67Z3f5'(55('5*mFq 3367# 7H6Ltf_3366733673#&&'##3  =0'kRT$Qa^JGfxn  f6dA KB+B%[ "t@e["tA?["tD[~"tG["tI[1"tK[p-<7#"547&'#"&&54663254&#"'663236655&&#"3#>Ǝ,bFc[^s}pn*Dz/VXvA2zBk5`?  orWM2T0>a^JGfxn  LZ6dA KB+B%["tM'["tPW[\3=L$67#"&'#"&&5466324754&#"'663266323%654&&#67&'&&#"37K3GY:iWc[^spn*Dz/Y>{XHѐ 2oV 2Fj5`?(oqa^JG Exn  KN}sOOϤ DwK3[N'#QF+B%U!#"'#3636654&&#"3.blՙD/w:KAYdVgEyݕkP_S);n1_&&54666&#"3267#rtR7(zCiV3TPz坜~7 $_ "@5_ "BR_P+!"'53254#"5.54666&#"3267k$+ym dtR7(zCiV3hPHn<> ܓ~7 : R_"Hcg#&'#"&&5466323$65&&#"39+mzߓVl>BeP@f'gc\^{hm]j,6,YrVg`-&&5466327&''%&&''7%#>5!"3qvڐ{W[k3J!m?c!7GuڑfJbMKb~롡Ngb7U-T^.bwb|x_c"Q>c+&'#"&&546632!5!53365&&#"3V9+mzߓ,=>BeP@fCgc\^{h 様,6,YrVg`!$67#"$466323%654&&#K3GYsڙXHѐ 2oV(v}sOOϤ DwK` "@t` "B`"D`~"G`"H`"I`1"K`p%/7#"547#"$4663232673%654&&#)(NڎjRsڙXHCK3l0 2oVs#nsv}sOOTZ` DwK47###5754632&'&#;勞~"^*$% 1[3cP= c''>55#"&&5466327&&#"3265f`mzߓ(>BeP@f2 W~D{x^,6-YrVgc"Acj"F0c"H(#4&#"#363WjxV;sdr4{=6(q#4&#"##5353!!63WjxV;+sdr4{=6(qj &54632#3#@@0/@@/U@0/@@/0@2J3#21 "@T"Dz0~"Go"HQ"Ix"o1"K@p"#HLsdj &54632#>53BB..AA.i8B..AA..BV~F dJ >538V~F  #367#(q >"EJ3#3"@V"Q4]"E"7d #5737+vKDyy fvS##&&#"#&&#"#363263aPdrQ5drL5yqf,dr4|92=A4|93!`zLF#4&'#363WiyV:ytdr4{=7)a{ "@ "B"E#'>54&'#363W8iyV:ytdr V~{=7)a{"P_N&&546632#>7.#"3瘕z{^QR^dSSe~痙ꀀ隘~WhjYZkhV_N "@_N"D_N~"G_N"I_N"J_N1"K_\"+#"&''7&&5466327&#"$'3266724{^@gNg7:_?qO;SudT1(Tv^Q3Bd~1.lIlBe42wKYEYjvV;Wh_N"P` $.>$67#"&'#"&&54663266323%654&&#667.#"3K3GY>AЄ瘃A<ЍXHѐ 2oVGQR^dSSe(_a]e~痙d\ae}sOOϤ DwK6WhjYZkhV*U #"'#36636654&#"3)glՙBz'Cc:KMMhDsݛ|HNP50n1*U"#"'#336636654&#"3)glՙBBa:KMMhDsݛELP50n1c(##"&&546632765&&#"3_msݜME7M@fZr{|>9],/3Vg 32&#"#3-1f| `^ "@K "B6"EV !'7674&&'.5!2&#!6r5OE[rQRs9sb0G@_yXMH/<$9r^53&2=}gV  "@V  "B,VP 32!"'53254#"5&'7674&&'.5!2&# ]k$,ym 6r5OE[rQRs9sb0G@_yXQPHn<> CH/<$9r^53&2=}gV "Ez=#&&'76'4&&'.54667>54&#"#46632s-C;McFW^bD/F(+?"9{i *"4B%6q^F]6 -G4O_E}RZ|gN^f~>, ++327#"&&5#533!u'P9(3AC]B <,S5PR+^++!!327#"&&5#535#533!u 'P9(3AC]B <,S5PR ^+5"Q`+P+*327#"'2!"'53254#"&&5#533!u'P9(3AC62]k$+ym *, <,S5`PHn<>)tB+^++"E69&'#"&&5332653:UVJmqV'h\)R8ni]փk}d|9 "@9"D9~"G9"I9"J91"Kp9(7#"&5467&'#"&&53326533#MUgBH)UVJmqVXO%)  RD@wARM)R8ni]փk}d|Hd'/+9"Mb 336673#hclh-!33667336673#&&'##   Шͪ H< G H E =-? ?m "@@"Df~"G"Im 333###nHz|>773377IUuR x93~}`EpW/FNL3 "@K"Dp~"G"Ix5j 7!5!!!5.<3/5j "@+5j "BH5j"HU!&54632#72654&#"3jrٙjqٙ[CB}Y^FD\@Zõ'%3#'$sdEl 74667>54!"'7632!!lky_jHB{Y&(_o]lI=SA\X%ٌxK>[['73265!' 4&#"'76632#"&'9MC{8jF ExDX}?\)rj P cT    !53##^732654&#"!!7632#"&&'1W£))11-iHc&٨on} o*# 632&#"663654&&#"3Xy}|f`VI)tv}8}bm |ro"k}ܤ4HTYE- )b!5!#';]\-=&&54667&&546632#6654&&#"36654&&#"3jMyD^m^}bxm]CxMmӒkA9lF/TI\BTGa>V&!"'732667#"&&5466375.#"3ZfbPL UlqqҋG6yh{G{MGuנiiϒyu a~jH ,!'%3#4667>54#"'676632!!k$b7;SE9D.)T2>a5|AWC81]<@.L~@jP8.?L*x  sIyT7,3x !'%3#!53##}k$b73tjhh<@.L~f݂3L-8;!&'732654&#'2654&#"'6632#!53##k~+.y68D|f\p.&3s*+ADh9NAN^IX}tjhh<@p 5,8CL>)02[54#"'676632!!b;SE9D.)T2>a5|AWC81]@jP8.?L*x  sIyT7,3_)&'732654&#'2654&#"'6632#,~+.y68D|f\p.&3s*+ADh9NAN^IX_ 5,8CL>)02[>3=33>>33= 6654&&#"3sCCsDDuEEtE CsDEtEFuCDsC[d &54632#&54632#LL89LL98LL89LL9I67II76II67II76I'P6653'C2WI}y|cj"# 3#&54632#ˬ==33>>3=33>>33=Q Fw!!###!7!!7!333!!#3q@TTTxS ?T{UWW }?kuqk,knjkoP &54632#==33>>3=33>>33=|*4667>54&'"'6632#&54632#E4J;-4"zp]%DI1E9/7$'==33>>3 lO,"2L6\g#eK,$8W?=33>>33=w( 3#3#L++43#+'\ &54632#6653HH33GG3C2WI$G33EE33G}y|c#C @2 c[2\+4'565%3E;2, t $60-KY*~BC m@8!#3!pww5C m@%| 7#`zotb PPR|Cw@I!5!ȁI!5!ȁI!!"II\? 3#3#\+/Y+/XPXH? 7333J/+լ/+՗PXPX\a?3#\+/X*/?C@h#AU#47#47~C2WIC2WI}y| cF}y| c]665376653]C2WIC2WI }y|cF}y|cU~#47~C2WI}y| cY2'P/!#5.5466753&'667[sdcsH/(dr;`Q3|{w~t ےۆ.L&d{#+77&547'76327'#"'$6654&&#"3dLL\nm\NN\hgvEGvCGuCEuEۆp}k`MM`q|yt`LLEuEDvEEuEEuEd/T%,3#5#&'733.546753'&&'$654&'gjk{AqPyfƫjA>gHfa[l\b\cy3;:-1Sw@ 2c.[Qp{WYn,&f$,%#"'#53&547#53632&&#"!!!!3267$ER)wghy,x1%%$<}CA$18 1- , *,1/*"T'732#537>32&#"3#!?$!([g| WXA3 .Z:$|WGЊx^Px"%!5655#5754632&&'&#"%!xٯ4'# 0gp) Ɉ{ } Fo}‹E!!!!#5!5!5!5!336673Hd-  錹 3> [663232673#"&'&&#"#F|T7lMHQ'pN=-e:+d=,.?k.=̆^<+.Am-<>l!!!!TTlڄlL55|\8d;PlLC*|@1!5!#tM&'#"'#&5332653:UV[mqV'h\)R86T ]փk}d| n 7 T^RT^T^RT^T^^TPA#3C!&&546632#>54&&#"3&&546632#>54&&#"3QkUZa[TZ`:N,+L/1P.-N0UZa[TZ`:N,+L/1P.-N0<@/Y_c\W]e^8b<7Z35^9:^6vY_c\W]e^8b<7Z35^9:^6P b#3CSc!&&546632#>54&&#"3&&546632#&&546632#$6654&&#"36654&&#"3QkUZa[TZ`:N,+L/1P.-N0UZa[TZ`ƔUZa[TZ`N,+L/1P.-N0QN,+L/1P.-N0<@/Y_c\W]e^8b<7Z35^9:^6vY_c\W]e^Y_c\W]e^8b<7Z35^9:^68b<7Z35^9:^6+ !5!3!!#{mlmm !5!3!!#!!{mlmTmmw@3#@3#3#4HW#5&'#"&&54663254&#"'66326654$#"3267# $$! 6655&&#"3cѨ7bFc[^s}pn*Dz/5ujӏ32vo'WvA2zBk5`?Qy`f2T0>a^JGfxn  ux#ŕ54&&#"67&'3vzyqZgyckd]fsR2u/UbfS6^:;_7V㘁PU*_hr`g^c0kdai`p;_L`x]K.QnI>e:?oD@OICxO=b8TB"&&54663!####UNDuGjllFyLLyCg3}:$54$32#6$54$#"3.54666&#"3267#YX˩힞hceˆF0"mo;\I,IF!YYʋ謬頩jƈm0}-5#"$54$3$54$#"3###3232654#[XY̩힞SJޯ2䀑=LVJYY謬y&zq76V6C#&&'7>74&&'.5667&&'6632&&#$667&&'?KQ6M6?_26PFZqPOKHRJ797p.\Z3LCZpQ=;2JBBEOKNYsY(%#&*C%0?' =r[Y#)h;O3B&!@lT|#;#X=?I\MLt#5!##333#####Ɯ;Ljhhl&&546632#>54&&#"33HH~MNIHN+H*)H,,H))G+INM}HH}MNIu+J-,H))H,-J+p3###Aɖ˓k0V #%%35c <^r0%%#57'53%####66: 3# &&'332673#xxF {5KL{JAwNI>MwBn 373#nswք P0F'53254#"32!$+ym c]kPn<>PHd3#'#;؎k6653kC2WI}y|cj#467#=.QE$tpt]~ &&54632# &54632#q8!E22H!6 OFD12GD3!7 3DE2 8 E33DE22F &&54632#7!G12EE2 7!0EC22FA3#Aɝ3#3#v`…a>1!!1p 546673327#,20|b1]p0V91{FTu z&&546632#6654&#"3\57_;9]57`;-77)'55'z2W58Z42X67Z3f5'(55('5~!!v~]t!!]Vq&'&&#"#46323253#D3*9DraU$<,(8Jv,P6]l`Fl<3#ԩmXs 3#R %J&&'332673#xF {5KL{JAwNI>MwBf 373#fswք 3PF'53254#"32!W$,ym c]kPn<>PH\3#'#3؎h~ &&54632# &54632#8!E22H!6 OFD12GD3!7 3DE2 8 E33DE22FWF &&54632#7!G12EE2 7!0EC22Ff3#fɝ@3#3#`…a>2 1!!21Hp546673327#H,20|b1]p0V91{FTu R&&546632#6654&#"3\57_;9]57`;-77)'55'2W58Z42X67Z3f5'(55('5#&'&&#"#46323253#D3*9DraU$<,(8Jv,P6]l`Fl<YF6653Y,!A7 }y|cVJJ ;  #% #% LH& ^ N  & N D \ vz *  F F J L 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.RegularSelawik RegularVersion 1.01Selawik-RegularSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.1 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.RegularSelawik RegularVersion 1.01Selawik-RegularSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.12  "@MPQ@ DFLTlatn 4AZE >CAT HCRT RKAZ \MOL fROM pTAT zTRK     markzmarkmarkmarkmarkmarkmarkmarkmarkmarkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmk0 Nv|jpd                     $ * 0 6 < B H N $ ZT f` fl r` fx ~ ~                         & ,   2 D 8 > D J > D P > D V > D \ > D 8 > D b > D 8 > D h > n t z D >           "   ( 4 . @ : @ F @ L @ R @ X d ^ p j p v p | p p      $ 6 * 0 6 * 0 6 * 0 < B H < B N < B T < B Z < B ` < B f < B l < B r < B H ~ x 6 * 6 6 6      & , 2 8 > P D J P V J P \ J P b J P h J P D J P n J P D J P t J z 6 * ,    "  . ( . 4 . : . @ . F R L ^ X ^ d p j ^ v ^ |  9/~+Q3w^Wj hX!L JKKJz|PJ3 $J/&&&&&hJ:J JhnnRR@|J .Jh. ZJ>>=@eH|?~. J +""PJP Jk;h|h|JB\\6J6A88HJHSJJ           IIZZ=  ?P[[ #   AA]]DD  s TTrrO F  FXXc ZZ ZZ] ]do f   Pr[*~egP. sFF FF _  j   @@ 9/;P0 > JPV\bhntz `flrx~~+Q3w^W  _S5 Y@MPQ=?<CE @ABDFGHIJKMP @ABDFGHIKMP DFLTlatn 4AZE BCAT PCRT ^KAZ lMOL zROM TAT TRK    !"#$% &'aaltaaltaaltaaltaalt aaltaaltaalt$aalt,aalt4ccmp>>0!0 +>ks\/gZ003oe-XmF(o0  *H 0w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA0 150320173202Z 160620173202Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR1'0%U nCipher DSE ESN:C0F4-3086-DEF81%0#UMicrosoft Time-Stamp Service0"0  *H 0 m*ͮ^ؕO-CGs;BWS6wՈE$jȫfŪF*6of^g^%5/8^Svy;cOq .LmX,$p{i,lx mI:>fOx`{WQKmQ4: :8뭪Că44T6,nx)Dq/ 6byW}|LN0?'P8f]>ŐB$&TkC{Wj261DhZ+1L <$$]|SL Fw~)ʟFb4i\y1GSQkㅿYYgL䠴:jHpS=pq|cKQYt5=zut ϡ;# 00Ԡ3l25U0  *H 0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0 140422173900Z 150722173900Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR10UMicrosoft Corporation0"0  *H 0 q]F˝[Fǰ9s`맶nhttp://www.microsoft.com/pki/certs/MicCodSigPCA_08-31-2010.crt0  *H w\ב=ͽ{مCs|6ǵ,^T:q@ q&^}l;ɪ_]*'~e T(8Z{V2˓ۯn]D԰N ']a( "pr#z,C3Roӈlޤ5Sew 5Y؆1},wrlMY&²W5|P+Y)8RE)N[_'Pm4 8W7(5:8j]"^{00 a3&10  *H 0_10 &,dcom10 &,d microsoft1-0+U$Microsoft Root Certificate Authority0 100831221932Z 200831222932Z0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0"0  *H 0 rY\0d` BvSl>ok:t/2BN#r5W ʮ IhMKyKqG%ߝuϪsDׁ6\Eܯ=(hrsV5rv_wE8s[gRi/ t)v/T0Yҍb_F1P'@0r)("7N=2=͡8\NV(*2KOc-bE=F[&SzJF7<8w\V< _^0Z0U00UҴX7.3L 0 U0 +70# +71N&`;1o<-0 +7  SubCA0U#0`@V'%* SY0PUI0G0ECA?http://crl.microsoft.com/pki/crl/products/microsoftrootcert.crl0T+H0F0D+08http://www.microsoft.com/pki/certs/MicrosoftRootCert.crt0  *H Y9>&Fo@2j/nI_uL;-C -1#|P!]=/LVpyIr>A i˥ - PV-JҼp VชKWB4nZ>G^2$+jJs2$΃"o;~c'Z S"A{*.1J&5~VğۅߜepK"$~Bdӝ&uRET* PytN#-Q|cy$9Oa!,ĩ0}6c"(0$ *H  1000w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA3oe-XmF(o0 +]0 *H  1  *H 0 *H  1 150414213647Z0# *H  19[ n#[%0  *H aQ-m СVjd"#oMѕ/ÿ7ŶLw&)ENtj]_1R1n􌼅 fLut.ZQU:=|3:MA'N KԌNr%%R XSM_* z7EA+]G% kӻ|5WÚiu` G׶vl2`N=h/QQrאˍC}AGtW߯kiwix-desktop-2.4.1/resources/fonts/Selawik/selawkb.ttf000066400000000000000000001260441473106011000232310ustar00rootroot00000000000000pDSIGFxHGDEF{ JGPOSDs{XGSUBsttOS/2Iyx`cmap"LXgasp { glyf+$dPheadޕ6hhea74$hmtx^Hlocaȧf `maxppX name#3ttipost2z ̄_<DSR|^ Q ``XJ332H MS !"Q   *5          {!JJJJJ**BBBBBBBBB)JJJJ!!P111RRRRRRJJJJJJJJJHJ9999|P|P|P|P|PV      >++++N8N8N8N8N8N8N8N8N8N87JJJJJHHHHTHTHTHTHTHTHTHTHTH0EEEEFxFFFFFjFxFzFRF{F{yyFFFHwTIIIIIIIIeDH///a/JBBBBB)))))uuuuuuuuuVaaaaakNNNNN!!!!bv/kd`##y'-<b<|}+ca+\+L'+{|bX+ERhJF_<<!55 1dSReRR;s3_mN(Z ZrHZ+Q s@!@!Mu/uD*m#!3GJ@!R!3+'-AP "/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' ?C^uywx}|>< %:798;RW G2&-~,$ HI(n#?0)*+-ABD\]_V^[SX]UZ\TV@ /9~#'+37HM[gk~7 (6    " & 0 : !" 0: &*.69JP^jn7 &5    & 0 9 !"m4wTp$,>@^bdnvz|"/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' %!&4:W8,9[<2R-7U  -)*+?DABHC.G_\]^lKyuw}x|~(zv {"$#&./,(246578;=<>FEINPORTSYXWac`bgmnqsrUZVTSX]\^ZI@DPKAHGMJBECLONifho>?(X@pDlPHTnFfJ"0<Rl "Dt ( T 6 @  \  B h 4n62FdB2xZ(Jt $Fl* >jvHT nDhv @LZfr~*Xd*$BNZfb  0 < H T ` l x !"!.!:!F!R!t!!!!!!!!""8"L"""##V#j##$>$p$$%%4%V%f%|%%%%& &&L&b&&&&&'''8'D'V'b'''''''((("(.(R(t((((())\))**4*`*****+ +.+, ,&,H,V,l,-B-^-..n..../"/2/L/^/z/////0 0 0.0J0v00000011 121X1t1111122( !!!!&&'#R ~fA9H  % !7!!!!!&&'#jsR ~<fA9H  = &'33273#!!!!&&'# R ~2UUfA9H  E!3!'!!!!&&'#5(R ~< >fA9H  \ )&54632# &54632#!!!!&&'#YYPPXXPzXXPPYYP0R ~.OHHOOHHOOHHOOHHOfA9H   '!!!!!&&'#)_R ~<fA9H   !5!!!!!&&'#=&XR ~?fA9H  ]!7#"&5467!!!3&&'#)bv^g:5SR ~mw1, `XD|+f!M&$(A9H  #-&&546632#32654&#!!!!&&'#l=?mDCm?@oE//#!,,!R ~)8b=>e:8b=>e:%* ** *fA9H  a *#46323253#"&'.#!!!!&&'#'nc#G0,/DnaG30! nR ~X[ pfA9H 9%!!!!!!!9?<"q$7!2#2654&##2654&##2unWumzodp|Nf{& ]`|eO^UV^ja]frJ$54$32&&#"3267#̡_HRO/GkZzAbBIPiȍh" KJ% !!$54$32&&#"3267#s ̡_HRO/GkZzAbB%IPiȍh" KJ'#!7!#$54$32&&#"3267#* 2̡_HRO/GkZzAbB'bbIPiȍh" KJ9.!"'532654#5&4$32&&#"3267#"'3%#%25[_HRO/GkZzAbB GB4p&Piȍh" K+Ji,&&546632#$54$32&&#"3267#V01T55T//T5̡_HRO/GkZzAbB,L.0J**K//L+ͬIPiȍh" K ! 26654&'eka mѓt*"O'!7!#! 26654&0 M'eka'bb mѓt*"O !!!!!!<<"%!!!!!!!!s<<"%'!7!#!!!!!! <<"'bbE3!'!!!!!!!(<<"E\ #&54632# &54632#!!!!!! YYPPXXPzXXPPYYP<<".OHHOOHHOOHHOOHHOi&&546632#!!!!!! V01T55T//T5d<<",L.0J**K//L+!!!!!!!!_<<"ߢ!!!!!!!!&.<<"ܥ]#"5467!!!!!!327bvRO<<"-0!pOo-T@'%  !!!!!=:J<!$54$32&&#"3267#5!#FmefUDQrb=i#(w۔GX nѓp 1:@J<= -&'33273#$54$32&&#"3267#5!#nmefUDQrb=i#(w۔2UUGX nѓp 1:@J<!)$54$32&&#"3267#5!#667!FmefUDQrb=i#(w۔)1GDGX nѓp 1:@ZJLLJ<i1&&546632#$54$32&&#"3267#5!#V01T55T//T5mefUDQrb=i#(w۔,L.0J**K//L+ˬGX nѓp 1:@} !!!!!!8f<FfH!#!!!#535!!5!3!!!ȣ8f< fHͦ!!8f"'0%!!!!s8%fE 3!'!!!(8Ef\ &54632# &54632#!!YYPPXXPzXXPPYYP8.OHHOOHHOOHHOOHHOfi&&546632#!!V01T55T//T58,L.0J**K//L+f!!!!B_ 8ߢf!!!!(&8ܥfP]#"5467#!3327bvROH8-0!pOo-fT@'% 1 >5!1a5 1|u+R =!!667!:&Y6H%="w=!!!!66767!'=ï:&Y6~1GDH%="LLx!!!:% !!!!!s:%"3Q !!!667!:)1GDDJLL"3# !7!%:$$RRܔ!3!!47#!&'#!EB  fA{4?"!l5!3&&5!!&&'#!eH ' &  M%;fD>%!!!3&&5!!&&'#!kseH ' &  %M%;fD>'!7!#!3&&5!!&&'#! eH ' &  'bbM%;fD>!3&&5!!&&'#!667!eH ' &  )1GDM%;fD>DJLL!>7&&'#!!3&&5!3^n6  e> ' 0 " .O?eB>M%;a0&'.#"#46323253#!3&&5!!&&'#!G30! Pnc#G0,/DnaeH ' &  : X[M%;fD>J$54$32#6654&&#"34í=Bp\[ol[[lNRsҋwv֎tJ%#!!$54$32#6654&&#"3Ms3í=Bp\[ol[[l%NRsҋwv֎tJE&3!'!$54$32#6654&&#"3(í=Bp\[ol[[lENRsҋwv֎tJ\ '7&54632# &54632#$54$32#6654&&#"3YYPPXXPzXXPPYYPDí=Bp\[ol[[l.OHHOOHHOOHHOOHHONRsҋwv֎tJ#!!$54$32#6654&&#"3_0í=Bp\[ol[[lNRsҋwv֎tJ '!#%!#$54$32#6654&&#"3rBí=Bp\[ol[[l NRsҋwv֎tJ#!!$54$32#6654&&#"3&í=Bp\[ol[[lNRsҋwv֎tJ",#"&''7&&54$327&#"6654'3rV|V}LP=zV}{*]l[ڨ\3.tCiB@h`R>;gzjxOv֎-sҋr+.Ja(8&'.#"#46323253#$54$32#6654&&#"3G30! Pnc#G0,/Dnaí=Bp\[ol[[l: X[NRsҋwv֎tH;'%!"#"$54$323!!!!327&#";,\xG̨O>WT"lLS{4PK~{|7@;,SE%6'0Y|_(% EJ"2%.\oP8%0!!&'32654&&'.546632'&&#"#s׋ixXxn;ZT}iZ_>lLS{4PK~{|%7@;,SE%6'0Y|_(% EJ"2%.\oP8'3!7!#&'32654&&'.546632'&&#"# ׋ixXxn;ZT}iZ_>lLS{4PK~{|'bb7@;,SE%6'0Y|_(% EJ"2%.\oP98=!"'532654#5&&'32654&&'.546632'&&#"4PK~{e‰3%#%25[g}ixXxn;ZT}iZ_>lLS{2%.\~v. B89;,SE%6'0Y|_(% EJP8,4&'32654&&'.546632'&&#"#667!׋ixXxn;ZT}iZ_>lLS{4PK~{|)1GD7@;,SE%6'0Y|_(% EJ"2%.\oYJLL!!!!ctbh3#!#53!!ctlD'!7!#!!!! ctb'bb\h9!!"'532654#5#!!!3%#%25[Zctb> Bh!!!!667!ctbF)1GDhDJLL5!! !!: 9*m3g5%!!!! !!'s: 9%*m3g5E3!'!!! !!f(i: 9E*m3g5\ &&54632# &54632#!! !!YYPPXXPzXXPPYYP: 9.OHHOOHHOOHHOOHHO*m3g5!!!! !!^_Ì: 9*m3g5 !#%!#!! !!LB: 9 *m3g5!!!! !!x&:: 9*m3g]5327#"5467&!! 5P-0!bvA?: MN<'% Fg*'m3g5*&&546632#6654&#"3!! !!l=?mDCm?@oE',,!#//#: 9)8b=>e:8b=>e:* ** *.*m3g P !3667! T- 8IS,E!f!3667!3677!!&&'#!W  G<Ea/T$=G?G&f!RGIO%"!!!3667!3677!!&&'#![sW  G<%Ea/T$=G?G&f!RGIOE%3!'!!3667!3677!!&&'#!(W  G<EEa/T$=G?G&f!RGIO\ 6&54632# &54632#!3667!3677!!&&'#!YYPPXXPzXXPPYYPW  G<.OHHOOHHOOHHOOHHOEa/T$=G?G&f!RGIO"!!!3667!3677!!&&'#!_W  G<ߢEa/T$=G?G&f!RGIO936767!!&'#!Q`]#N"9 "'9-7G!3667!!4w  e)U? P%!!!3667!!s4w  e)%U? PE3!'!!3667!!(4w  e)EU? P\ &&54632# &54632#!3667!!9YYPPXXPzXXPPYYPy4w  e).OHHOOHHOOHHOOHHOU? P!!!3667!!_4w  e)U? P+ 7!!!!+\~/Q(+% !!!!!!sa\~%Q(+'!7!#!!!! ;\~'bbQ(+i&&546632#!!!!;V01T55T//T5\~,L.0J**K//L+Q(8!!-&'#"&&54663254&#"'6632$667&#"3/ZuahQ./NH+J+60!*8!"t@8!"tA8!"tD8!"tG8!"tI8!"tK8]!1=7#"&5467&'#"&&54663254&#"'66323667&#"3 ahQ./NH0a)$(+J+60!*8!8"tM;8!"tP7~1:G3267#"&'#"&&546632554&#"66326354&#"%67&'&#"3Gey[CK3GY@kJh_hefWU5U9t̮T\Waww! ZbISJ:|wSTIT(`b3Z5>a_J-FC?[^eAU^S.'&#60!*#"'!!663654&#"3ronٜ:1|Hw ,&&5466327&''7''7%#>5#"3}yٍuXToQz:7MiK`4fureKZs`s.*h7I]H"QH)&'#"5466325!5!5!3655&#"3o$%/O|o5c{dm_WuMh\LMgbE萐k>|H 3267#"$466354&#"%ey[CK3GYy堮T\Waw|wSTIT(ueAU^SH"@H"BH"DH"GH"HAH"I H"KH])23267327#"&5467#"$466354&#"%ey[CK3EL!%%IPq|1/3/y堮T\Waw|wSTIT5k,$( [S55#"&&5466327&&#"3265qq\Ǔt윈~(2j/j{+[Dov2 =pY8{W=@wLxmEq"AEq"FuEq"H}\!4&#"!!63]TWc]J5!N--N00M-,N0Xjs.<-O0/N--N/0O- 8dSF { >5!js.< 8dSF v !!677!F=5;;gv:;^v"E3!!<"@i"QH^"Ey"b !7!7bą<SaTSR%!6&#"!&&#"!!6632663TJW;^(GQ9V*#L`X.Sndr4Rk3)4Ti.3pmH?;66;\!4&#"!!63]TWc\Irdr eAPZt\"@\"B^\"Eb\>74&#"!!63]T3cr4Wc\Irdr " 1VEeAPZt\"PI&&546632#667.#"3Kl>>lFIp==pI~旚ꀀꚘ~>qJJq=>qKJp=I"@I"DI"GOI"I=I"J\I"Ko&#"''7&5466327667.#"3534ǒ7xfl>>lFIp==pI%@_~Fk"6>qJJq=>qKJp=I"PDG#,<3267# '#"&&54663266354&#"%667.#"3ey[CK3GYIzyIB{T\Wawl>>lFIp==pI|wSTIT(AE~旚D@DEeAU^S>qJJq=>qKJp=*#"'!!663654&#"3yjnٜ5$/dftjAh!wlsݛrCIu&$@n* #"'!!663654&#"3yjnٜ5:/`ftjAh!wlsݛ?Du&$@nH(o#"5466327655&&#"3oUzA>0q54&#"!46632> 0,QnR42t#AFUqR,@3.4#bP_s~䗑y:P<1- =s&Q"-#FeE]7 +C0+3kYZ|gVfm?($)+$327#"&5#73!3#(3@Dŧ3^)+327#"&55#535#73!3#3#?P(3@DŦ3TXd^e)"Q)9+%$327#"'!"'53254#5&5#73!3#(3@DK<3%"&{o%d3 CIBJ^)^+"Eu&'#"&&5!32665!s( KYKF },BWM P"@P"DP"GP"If !3!!#!NPz,,,T6677!37%I/e_;9B}FG/NLN3T"@T"DT"GT"I! 7!5!!!!G^4q3/G!"@q!"B|!"Hb8&54632#2654&#"3pw塖owRZWOYb^V@ZM%3!)8 cLEv#74667>54#"676632!!vZfMW:?~V#\R Uv\;C+=S?XzP!ى͆S4EP.(32654! 54&#"'6676632#"&''Cw,d4h" HHhJa, FO+L? P cT /j !53#!^R32654&#"!!772#"&&''Pu++M 3`LhUecd3tʃ k.%# $32&#"63654&#'"3V|Ӂӄ l\Ci-NV]^JYZsr"kIgoVIf&ae^!!!7z ]d7)5&&54667&&546632#654&#"3654&#"3zJXikÁ~izdUGyܑBHG;BONAWijXXjkXi~Rr3[n[[nY4rQ~iOBAOOABO/lZUgfUZm`!#!"'3267#"&&546637.#"36_nZEYlqqҋB*TDZNkTG!FiϒykKwBlRhm#~V )'%3!4667>54#"'276632!!A]8p1D906$%O"Ds=:K6gdL8[B.&2=#y  }BxX4#~M '%3!!53##5E]8jB)ՎdLdjy~{$/2'73254&#'254#"'632#!53##5s]|`U`db^E\LbXFYijB)Վd!>$%L<%2[<8-Hn=~j-sg'%3!W8Lbu4667>54#"'276632!!b1D906$%O"Ds=:K6g8[B.&2=#y  }BxX4_ '73254&#'254#"'632#`U`db^E\LbXFYi_!>$%L<%2[<8-Hn=|B'#7'7'7'37y]]]]6a~~aa~~% RvRcm &54632#ZZJJ[[JmWHHXXHHW $6654&&#"3KKKK~IJ~JKJJ~JI~KKJ\ &&546632#&&546632#S01U55T/0V73S01U55T/0V71U35T//T56T/L1V35T//T56U/667!?I `]dh`)"#!#&54632##ZZJJ[[J,$WHHXXHHWQ 'w3#####737#733333!#31HHHG0JJLLa1uOS`d{) &54632#ZZJJ[[JWHHXXHHW|8*4667>54&'"'6632#&54632#-@2',F@d%AL2F8,2"5ZZJJ[[J fK) /G3CK#dO-$3M5WHHXXHHWb# 33#3#,,3#,E &&546632#667!S01U55T/0V7?I `]1U35T//T56T/dh`C@R[3h&&554#52554663"3 VVKUF𸸿ߊI?=bRJC @!#3!+FC @ 77zokvnx_\C@s!5!s!5!s!!#ss!s? !!!!!J4N̊J4NXPX5? 7!3!5N4JN4JPXPX5?!!5J4NX ?C@#d!67!67?I `]?I `]tdh`xdh`S667!7667!S?I `]?I `]dh`xdh`e!67?I `]tdh`-o;8$5.546677&#"3267d_^vQ2gm}5TEG֍և !#yx|31?3+77&547'76327'#"'6654&&#"33BBk~jDDj~ke::e?>d99d>ŠnwylAApursAA(9d==d99d==d9_.GT/!5&&'32654&&'.54675!'&&#"4PK~{XmixXxn<[R~_>lLS{2%.\' 62;,SE%7(0X{*< EJmW,%#"$'#53&547#536$32&&#"!!!!327WFR1mVWp52<32&#"3##M"2$rXirrQN(+2t[sq @וoZ h%!56655#53546!2&#"7#jL__ZGKQGI^Oگ# -XHEHD(3!!!!5!5!5!53!3677!@%?c  QsȭsU:"?663232673#"&'&&#"#N_6dK?O%+.N]3cD>T(g¿g$%LBg#"!v  &&54632#!!&&546632#G)WDDS)E)2G)(F-DS(E*@(F)EZXE,E(rZ'D).I*XF,D'u!!!!22uLT%5%Zu4DVLTC*@Z!!!V5%t&'#"'!!32665!( KY'*ahQm+J+60!*r#,6$'#"&&54667&&5!26676654#"7&'3dӒads?Aϩ`Q3.W[bjfwSi@*Zaj\mec1^J~RZZQmjr[cV'3xTgix'>G)sH&&5463!####AWb}:$54$32#6$654$#"3.54666&#"3267#`[֟XYxH0%RNj`c^)>45C>PTľ·\vu_[Z`] }-6#"$54$3$654$#"3###!232654&][`ؗ.MAUh|8%%!B½PTf1ukV$1)Zh,7!&'766'4&&'.567&&54632&#$654&'bUJpEG)>8\wXu;Bɕ9~g)>8]xXnV>WXPKG|MH32&9ydY(nM?=b(#A{_Y=$([4FjQs#5!##333#####~}:juus&&546632#6654&#"3?JJPPKKP3DD33DD3JOOIIOOJE43DD34Eb3!#!y"!V !%735 FT,!7%!57'5!%!66!!7M &&'33273#;V tnWaP]ssaM373#͛缼u9 <'53254#53!%"&{o%9IB3#'#u/^|667!/?I `]dh`u#67:E [X0_c] &54632# &54632#YYPPXXPzXXPPYYPOHHOOHHOOHHOOHHOD&&546632#V01T55T//T5,L.0J**K//L+!!-&3#3#L?!!R]5473327#y-0!bv]\T@'% 8&&546632#6654&#"3l=?mDCm?@oE',,!#//#8b=>e:8b=>e:* ** *!!!!*lT!!*<T&'.#"#46323253#G30! Pnc#G0,/Dna X[!##@!! 7 &&'33273#V tnWaP]ssaM!373#!͛缼39<'53254#53!X%#%{o%9IB3#'# uGc &54632# &54632#YYPPXXPzXXPPYYPOHHOOHHOOHHOOHHOJ&&546632#V01T55T//T5,L.0J**K//L+h!!-!f3#3#L?R!!R3]5473327#3y-0!bv]\T@'% 'V&&546632#6654&#"3l=?mDCm?@oE',,!#//#8b=>e:8b=>e:* ** *-&'.#"#46323253#G30! Pnc#G0,/Dna X[P667!P)1GDdg`VJ    ;  # # L?& ^ E    / G v_ *  F F / Lǩ 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.BoldSelawik BoldVersion 1.01Selawik-BoldSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.1 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.BoldSelawik BoldVersion 1.01Selawik-BoldSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.12  "@MPQ@ DFLTlatn 4AZE >CAT HCRT RKAZ \MOL fROM pTAT zTRK     markzmarkmarkmarkmarkmarkmarkmarkmarkmarkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmk  Nv|jpd p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p$ p* p0 p0 p6 p< pB pH p$ p pTN p p`Z p p`f p plZ p p`r p px~ p px~ p p p p p p p p p p p p p p p p p p p p p p p   p p   p p   p p  p p &  p p  , p p > 2 8 p > D 8 p > J 8 p > P 8 p > V 8 p > 2 8 p > \ 8 p > 2 8 p > b 8 h n t p p z p p z p p 8 p p p p p p p p p p p p p p p p p p p p p p p p p p p p           "   ( p 4 . p p @ : p p @ F p p @ L p p @ R p p @ X p p d ^ p p p j p p p v p p p | p p p p p p p p p j p p p v p p p | p p p p p p p p p p p p p p p p p p p p p p  p p p p  p p $   p $   p $   * 0 6 p * 0 < p * 0 B p * 0 B p * 0 H p * 0 N p * 0 T p * 0 Z p * 0 6 p p f ` p p $  p p $ l p p $ r p p $ x p p ~ p p p p p p p p p p p p p p p p p p p p p p p p p p p    p   p p & p p & , p p & 2 p p 8 p p & p p & > p p P D J p P V J p P \ J p P b J p P h J p P D J p P n J p P D J p P t J z p p p p p $  p p p p p p p p p p p p p p p p p p p p p p p p & & , & 2 & &  & & & &  p   p p ( " p p ( . p p ( 4 p p ( : p p ( @ p p L F p p p p p p p p p p p p X R p p X ^ p p X d p p X j p(  yv#5Wz= h oN2s Zxhh 9Lh !?hzAANALAh o Lh EEhQQGGNGLGZDh )h)d++s h F  Nm  s \zhuu  ^uw^Ch>~E9[XhZ9A h NGhhTN{nhnppNpL ''b)))))V) ^^{{FHf9Hzz *>y@@@@||iih ##^%%%%=='rb@Drlln-nrrttttW k%9\qt9P[ nnnV++11l33660@@  G90 > JPV\bhntz `flrx~yv#5Wz{x9%YV|@MPQ=?<CE @ABDFGHIJKMP @ABDFGHIKMP DFLTlatn 4AZE BCAT PCRT ^KAZ lMOL zROM TAT TRK    !"#$% &'aaltaaltaaltaaltaalt aaltaaltaalt$aalt,aalt4ccmp>>0!0 +0҆`@%Lf2j003q.kNq0  *H 0w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA0 150320173203Z 160620173203Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR1'0%U nCipher DSE ESN:B8EC-30A4-71441%0#UMicrosoft Time-Stamp Service0"0  *H 0 ꑽo!6(f3:f[K(4JC2=%{>b}tSct$P{9http://www.microsoft.com/pki/certs/MicCodSigPCA_08-31-2010.crt0  *H w\ב=ͽ{مCs|6ǵ,^T:q@ q&^}l;ɪ_]*'~e T(8Z{V2˓ۯn]D԰N ']a( "pr#z,C3Roӈlޤ5Sew 5Y؆1},wrlMY&²W5|P+Y)8RE)N[_'Pm4 8W7(5:8j]"^{00 a3&10  *H 0_10 &,dcom10 &,d microsoft1-0+U$Microsoft Root Certificate Authority0 100831221932Z 200831222932Z0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0"0  *H 0 rY\0d` BvSl>ok:t/2BN#r5W ʮ IhMKyKqG%ߝuϪsDׁ6\Eܯ=(hrsV5rv_wE8s[gRi/ t)v/T0Yҍb_F1P'@0r)("7N=2=͡8\NV(*2KOc-bE=F[&SzJF7<8w\V< _^0Z0U00UҴX7.3L 0 U0 +70# +71N&`;1o<-0 +7  SubCA0U#0`@V'%* SY0PUI0G0ECA?http://crl.microsoft.com/pki/crl/products/microsoftrootcert.crl0T+H0F0D+08http://www.microsoft.com/pki/certs/MicrosoftRootCert.crt0  *H Y9>&Fo@2j/nI_uL;-C -1#|P!]=/LVpyIr>A i˥ - PV-JҼp VชKWB4tC[&[QAӚ*3f.zWbGBmhVvoڏ3;VکU 5a{qDՉ1aD*KS"B8 "0ZDQ^"O2HX,|\aBя$HQIPKϡ(0$ *H  1000w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA3q.kNq0 +]0 *H  1  *H 0 *H  1 150414213647Z0# *H  1Ic(P"?.v%iK0  *H \4}lr}u!qRE\@Gqr<y7mrSU-1Z~ cg=c'Wm+ ƸIF#t[$ eVez@!>=ݘ%qNwڢr9>蝳Ώw$*c D>[x`&CqlN] *%5NIU%kː< %:798;RW G2&-~,$ HI(n#?0)*+-ABD\]_V^[SX]UZ\TV@ /9~#'+37HM[gk~7 (6    " & 0 : !" 0: &*.69JP^jn7 &5    & 0 9 !"m4wTp$,>@^bdnvz|"/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' %!&4:W8,9[<2R-7U  -)*+?DABHC.G_\]^lKyuw}x|~(zv {"$#&./,(246578;=<>FEINPORTSYXWac`bgmnqsrUZVTSX]\^ZI@DPKAHGMJBECLONifho>?(V>lBh F4@Xx"Bb0v.Fr6F\h < p * d D  b  * T :pD4\z&Lx2nR:z&lx&Zf:t@".:FR^jv ,F8DP\ht:r "`lx0V    & 2 > J !! !!$!F!h!t!!!!!!!" " "T"""#&#:##$ $R$$$%:%`%p%%%%%& &&T&j&&&&&'''@'L'^'j'''''''((($(0(R(r((((())p))**H*p*****++8+,2,J,j,x,--v--.R..//0/L/z//////0 020H0V0l0z00001 11(1B1T1p11111122>2h2z;!#3#&&'#H}n]sUf9H ;" #73!#3#&&'#n|%H}n]s>3f9H ; &'332673#!#3#&&'# cbSOa gy^H}n]s4f]6<<6]f!f9H ; #%3#'!#3#&&'#z- ~OH}n]s=ρf9H ; )&54632# &54632#!#3#&&'#//!1."./.!2/"H}n]s7,#!+, "-,#!+, "-f9H ; '3!#3#&&'#Rm-H}n]s>f9H ; !5!!#3#&&'#v H}n]s@Zf9H ;q"7#"&54673!#33&&'#3 3!blmI|H}n]imD>TZSQwUf2a@169H ;#-&&546632#32654&#!#3#&&'#K\44\99\44\92CC23DD3ZH}n]s0T44T00T44T0#=..==..=!f9H ;!+#463232653#"&'&&#!#3#&&'#0RYa-D.!0-)TU^'?)#4H}n]sDKur.-##ELzo,*%&f9H  %!!#!!!! AncZZU[ZWv#7!2'2654&#!265!!`V^TLo 3yZSQw[ZZ2a@16V !!!!#c[Zdm!$54$32&&#"3267!5!#9ҞH\^jOYB]uDU]ޘ.+Z:@m /&'332673#$54$32&&#"3267!5!#q cbSOa gyҞH\^jOYB]u4f]6<<6]fDU]ޘ.+Z:@mN!($54$32&&#"3267!5!#66739ҞH\^jOYB]ucADU]ޘ.+Z:@\qMzm -&54632#$54$32&&#"3267!5!#86&'97'ҞH\^jOYB]u.7('11'(7DU]ޘ.+Z:@ 3!3#!#c5bbcaf^=-##!##533!33!!-{bc{{c5b{5 ^[HH[3#__f"'0 3#3#|n__f 3#'#3#- ~z__ρf &54632# &54632#3##//!1."./.!2/"__-,#!+, "-,#!+, "-fI &54632#3#86&'97'/__$7('11'(7f3#3#+m___ޚf:!!3#Pv __Zfq&#"&546733#327&3!blmI_[`D> 3yZSQwf2a@16O >53OkM_Թ<R ! #37#bbV(s'yiN! !##37673'!y@bbV(s'ZcAFilqMz2Z3!!c?^ZZ 3#3!!|nc?^Z"3QNZ 3!!6673c?^cAZ\qMzZ"3FZ %!573%Z^rrcnZZ9E`E;`336673#47##&'##[  X_   cr&*Mfs+C#0;>33&&53#&'##JY& bNd}L%;fQ>3#33&&53#&'##|nJY& bNd}L%;fQ>373#33&&53#&'##-JY& bNd}L%;fQ>N33&&53#&'##6673JY& bNdcA}L%;fQ>\qMz %'>7&'##33&&53 >dJY& b PdvQ>}L%;0&'&&#"#463232653#33&&53#&'##3?)#460RYa-D.!0-)TU^^JY& bNd,*%&DKur.-##ELzo}}L%;fQ>m$54$32#6$54$#"3=Ԥ,6ˬNRZ%)ۡm"#3#$54$32#6$54$#"3|nԤ,6ˬ"NRZ%)ۡm &3#'#$54$32#6$54$#"3- ~zJԤ,6ˬ ρNRZ%)ۡm '7&54632# &54632#$54$32#6$54$#"3D//!1."./.!2/"Ԥ,6ˬ7,#!+, "-,#!+, "-NRZ%)ۡm#3#$54$32#6$54$#"3m_Ԥ,6ˬNRZ%)ۡm '3#%3#$54$32#6$54$#"3 nInJԤ,6ˬ NRZ%)ۡm#!!$54$32#6$54$#"3vlԤ,6ˬZNRZ%)ۡT$/#"&''7&&54$327&&#"$54&'3GdˉV?KO,}U@<:!HjPLJvYT3_RFC5ZRMRm)9&'&&#"#463232653#$54$32#6$54$#"3i?)#460RYa-D.!0-)TU^Ԥ,6ˬ",*%&DKur.-##ELzoŷNRZ%)ۡm(%!"#"$54$323!!!!327&#"q4c~NԤ5.j0f!o;~ZZ NR [Zۡ% !2#!#2654&~brʂcWbhZ#!#3!654&3brʂcb(ubhZm(.'#"$54$3232$54$#"Q͝j^pԤ,5Ƴl XJrNRSۡ%) !##!22654&^ccZl奄Y}ni{ٝ #73##!22654&Nn|\^ccZl奄4Y}ni{ٝ %373##!22654&蒞{^ccZl奄3늊Y}ni{ٝN !###!2'2654&673' ~^ccZldcAFY}niTqMz2n*&'732654&&'.54632'&&#"#puRS{hq_{t2Q:Mrcud^ )0Y4)NpJ15V`%V HfD.7Znz`n".3#&'732654&&'.54632'&&#"#|n?puRS{hq_{t2Q:Mrcud^")0Y4)NpJ15V`%V HfD.7Znz`n(1373#&'732654&&'.54632'&&#"#Β-YpuRS{hq_{t2Q:Mrcud^()0Y4)NpJ15V`%V HfD.7Znz`nN<2!"'53254#"5&&'732654&&'.54632'&&#"MrcudXwvy)'2$"UhuRS{hq_{t2Q:fD.7ZnvcBTSTf`),Y4)NpJ15V`%V nN*1&'732654&&'.54632'&&#"#6673puRS{hq_{t2Q:Mrcud^gcA )0Y4)NpJ15V`%V HfD.7Znz`\qMz=!5!!#bbb?[[=3###53!5!=bb?SxSt[[=(373#!5!!#ݒ-bbb([[=N!2!"'53254#"5#!5!!)vy)'2$"bbMTSTf`?[[=N!5!!#6673bbb1cA?[[\qMz3! 3!ba*m ]"3#3! 3!Q|nba"*m ] 3#'#3! 3!- ~zba ρ*m ] &&54632# &54632#3! 3!//!1."./.!2/"`ba7,#!+, "-,#!+, "-*m ]3#3! 3!m_ba*m ] 3#%3#3! 3!nInJba *m ]!!3! 3!]v@baZ*m ]q327#"&5467$3! nKOD> 3 3!blJ9 b4,[:16TZSBg!7m ]*&&546632#6654&#"33! 3!_\44\99\44\93DD32CC2ba0T44T00T44T0M=..==..=*m ]* 3367#*n  kKk7H>Df333667336673#&&'##3kO  d2P  Gh\S TsRW i4RP"fJS"V:3"#3#33667336673#&&'##a|nkO  d2P  Gh\S T"sRW i4RP"fJS"V:3 &3#'#33667336673#&&'##- ~zkO  d2P  Gh\S T ρsRW i4RP"fJS"V:3 7&54632# &54632#33667336673#&&'##//!1."./.!2/"kO  d2P  Gh\S T7,#!+, "-,#!+, "-sRW i4RP"fJS"V:3#3#33667336673#&&'##m_kO  d2P  Gh\S TޤsRW i4RP"fJS"V:;933673#&&'##SpH  %AqQz#u=H #9-K(G;%33673#GrY  jj2c"x4 3!7;%"3#33673#|nGrY  jj2c"x4 3!7;% 3#'#33673#- ~zGrY  jj2c ρx4 3!7;% &&54632# &54632#33673#a//!1."./.!2/"GrY  jj2c7,#!+, "-,#!+, "-x4 3!7;%3#33673#m_GrY  jj2cx4 3!7B? 7!5!!!Bp_ /[(ZB?" 3#!5!!!|n+p_ "[(ZB?(373#!5!!!-p_ ([(ZB? &54632#!5!!!"86&'97'p_ .7('11'(7[(Za-&'#"&5463254&#"'6632$6655&&#"3n6c[Ƹ.Hz/`fW7W'pg9[3f Z :LX47_S9[3f Z =w0*.vLX45!"3kuԊagt#LVd-#蠫n̊nVn\Wq]sF*>]G`МTn͊sщkZ"QZJ,&'#"&&546632!5!533665&&#"3VK?$huHHR^sRNAIb˺Cpodkrڙ~D?ESSVigCHgŊZ!3267#"$466354&&#"%Y =RHOoђ?KiynKE$&Z(vF$R[طZ"@Z"BZ"DZ8"GZK"HZ"IZ"KZq'13267327#"&5467#"$466354&&#"%Y =RU],( 353OWC?sWoђ?KiynKE$&ZD6.4ZUN55#"&&546632765&&#"32665 h+ivElW2)AJb̻]N2T ]RWrڙ~#=/uΔCIgŊViZ"AoZc"F-ZK"H#4&#"#363֗K^rl?^^dr4dU([3#4&#"##5353!!63֗K^rl?^qq^Tdr4dU(SSZ &54632#3#((((0^^ ((((23#^^2"@B"D\8"Git0K"H"I"[]"Kq@K"#HL:E &54632#>'3((((s;_ ((((dgF E >'3;_ngF  #3#^^i{p7"E3#\\"@B="Qf  "E" #5737߷\\DFu`.&#&&#"#.#"#36632663P^M/ ^1rbP1^= 4Vj(=Udr4cS7B4xShX%΂GU^TPb#4&#"#363חJ^ql?^= dr4cT&΅"@"B"E'>74&#"#363חJ ;ql?^= dr PecT&΅"PLZ%&&546632#>7.#"3zzޒvwُncdmuaau~痙ꀀ隘~Xh}jl}hZ%"@Z%"DZ%8"GZ%"IZ%"JZ%"KGF$.#"&''7&&5466327&&#"$'32667/0wُ_>=7:zޒe>{3267#"&'#"&&54663266354&&#"%667.#"3Y =RHO69ߖzzޒ93ٜ?KicdmuaauynKE$&Z(|~痙ꀇzF$R[ط3h}jl}h*!!#"&'#3636654&&#"3`eǐ_<Q^KfQtoHyݕ_f|}R`˚seFA*!"#"&'#3636654&&#"3`eǐ_]Q^KfQtoHyݕ_f|R`˚seFAZ(!##"&&5466327665&&#"3^+huKJNAIb˺ZjRWrڙ~ICrrVigCHgŊ632&#"#32_0(a9^@N`ZV/΁"@_"B"EV'&'7667.'.56632&##9X[?cm=XLUgIsUlIu9SGYmN&^)#_T>P-7hT\"[R7H+ =t^V"@V"BVN9'2#"'53254#"5&'7667.'.56632&##w )'2$$\o[?cm=XLUgIsUlIu9SGYmN]J\V0^)#_T>P-7hT\"[R7H+ =t^V"E"=#&&'7667.'.54667>54&#"#466323JAObFRX[?cm7PEL\@1F93<(r\[pbR1F;3;(L-#?{d&^)#obDW3"Rgï^2wPT^4+'pe-Z=gV{JFpF|KM"@"D8"G"I"J"Kq+77#"&5467&'#"&5332665330.OWQJ+Rgï^2wPT^4+OV,(ZUN<}6TW-Z=gV{JFpF|KM5!"'7632!^l}hyQA~Q4'~`tr]=ӌZKjZ1 c%v}RQyqT{'732654&#' !"'76632#"&'6I4b<" >o>bFV&qc+ ] P cT 2 !53##Tq\bJRi732654&#"!!6632#"&&'&Sΰ))1G"KjC\&ūTlz y)#"632&#"6636654&&#"3Vsxs^vgMK-^H@p[Tso|"kT[hfdjRx@X!5!#Y^ jCW]i-=&&54667&&546632#6654&&#"36654&&#"3j9gDO`]on\]LBd7i~VyBBxOWHGV^OO_bRRbi~Rs4Zn[[nY4sQ~iBCzQVHHVQzCUg[KKZgVj(#"'73267#"&&546637.#"3IVXe jTH7eieǎY?nrHcdaiϒxde__ ,!'%3#4667>54#"'76632!!FdL7:VEcO?I1)R27`4r@ZLCK3(IXLStT|S3(:K0 T d}LqJ1,;S6W_ !'%3#!53##BdL3:VuonwwR(IXLStd\JPG.9<!&'732654&&#'26654&#"'6632#!53##OdL~++y9JZByOIn=D83r+,@ZmNAN^BxOuonwwR(IYL [L1I)S*M2?LVn[MzxOHn=\JPs'%3#:VWLStNuo!4667>54#"'76632!!NEcO?I1)R27`4r@ZLCK3T|S3(:K0 T d}LqJ1,;S6WG_5*&'732654&&#'26654&#"'6632#~++y9JZByOIn=D83r+,@ZmNAN^BxO_L [L1I)S*M2?LVn[MzxOHn=R'#'%%7375j55j56\%\\%ܠ\7SOvn3 &54632#//#".."n1%#//#%13s6654&&#"3d99d>?f;;f?39b=>e::e>=b95 &54632#&54632#..""00""..""00"?0""-.!"0/"#--#"/;(>73;36 c+|eqPȴ0"#s3#&54632#pK//#".."1%#//#%1Qu F1w~!!#!#!7!!7!3!3!!!!XITWTTPSG'TSUWWWHWuqWTWnjW5 &54632#//#".."1%#//#%1*4667>54&'"'6632#&54632#Y6N?5=)fBK0D96?+o"//#".." ZR1*=V9w#WRsI/,BcE1%#//#%1\( q3#3#VVVV,,3#VV,;= &54632#>73--#"//"36 c+|q0""--""0eqPȴC@(*1[1^&54'565467x~~737>73e36 c+|36 c+|eqPȴ2eqPȴ{h#7h36 c+|eqP8fS+;($$#5&5475336&&#3267{MWWM1(0u;+|G"Q+U)&W9լ+77&547'76327'#"'$6654&&#"3TT84T ,_.T04HBT+'g'732#5376632&#"3##*+aiu!u+'!b MDR狐 Q R?Px%!5$55#574632'&#"%!xB$* {2;VVVI KQKߠE!!!!#!5!5!5!336673dNtYwOm@ =eTTMTTH 3> ?6323273#"&'&&#"#|g?\83G.M{g8Z@6H) N/-(&r-.'&` &54632#!!&54632#|.. ++ 9u.. ++ b. ,, !-T. ,, !-j`B!!!!uuBTT;)755ZAN{^-ZQ)C*K@`!5!# V+Ty&'#"'#&53326653>RgZ\^2wPT^4+'pe-Z=Z5gV{JFpF|KM# 7N<NM<N<NP;P;;PR#3C!&&546632#>54&&#"3&&546632#>54&&#"3CdLPWZ`\UX_Go?>lCFqA?oDWZ`\UX_Go?>lCFqA?oD(I \ce^^ed]PHNM}HIOL|G\ce^^ed]PHNM}HIOL|GR 5#3CSc!&&546632#>54&&#"3&&546632#&&546632#$6654&&#"36654&&#"3CdLPWZ`\UX_Go?>lCFqA?oDWZ`\UX_ژWZ`\UX_o?>lCFqA?oD|o?>lCFqA?oD(I \ce^^ed]PHNM}HIOL|G\ce^^ed]\ce^^ed]SHNM}HIOL|GHNM}HIOL|G` !5!3!!#qdTeT+TdTd`f !5!3!!#!!qdTeTduvTdTdT3#__3#3#____GU&'#"&5463254&#"'6632>54$# !267# $$! #$6655&&#"3I3c[Ƹ.Hz/J[q6Rx_h!WVW7W$jj9[3f Z y͑28GA:[/ziLX454&&#"7&&'3GyqL|XqY_VPf|L݉tW}#bpY9b=Cm?dPoyag*Qy`gck3˺[TMRkgDsd.kV;XW9\4=jAҏg{ElM~Hq`"&&54663!####VREuFLMFyINzCVDq;$54$32#6$54$#"3.54666&&#"3267#VX˳3̴ϵ2_gjˏF}-$)d4Ŵ'r?tmRQu:H#&&'76654&&'#'.5467&&546632&&#$6654&&'SN]DGO1kz8VE YjJ\OQZXh9n!/c#NxD;XM^rPaK=UP^k<[LVnuaOxA&U#*^_;O0!9iSW!%s^Mu@ L ,S8:K+!54&&#"3FuBBrFGuBBrF,N,+L/0O-,M/BuGFrBBrFGuBL/Q21O..O12Q//3###)`` eD #%%35;|jBjD%%#553%  j6jj6j_3#rd &'332673#[ Y_LDd ]mrMW[Ip{373#VR-N2<'53254#"532#'1%$MNJ\Vh3#'#`-`\ta>73t36 c+|eqPȴc#7J+/ c'l1\gIr_8 &54632# &54632#//!1."./.!2/",#!+, "-,#!+, "-K &54632#86&'97'7('11'(76y3#6m_3#3#nInJ=!!Zq&546673327#l51_@0D> 3 3!qZS.H?-EH*16T&&546632#6654&#"3\44\99\44\93DD32CC20T44T00T44T0M=..==..==-R!!=R[wx!!w#S&'&&#"#463232653#?)#460RYa-D.!0-)TU^,*%&DKur.-##ELzo&3#03#nrd%= &'332673# Y_LDd ]mrMW[Ipy373#VR-9N<'53254#"532#`'2$$MNJ\Vf3#'#^-`\8 &54632# &54632#//!1."./.!2/",#!+, "-,#!+, "-XK &54632#86&'97'7('11'(7[3#[m_Fd3#3#nInJ=(*!!(ZNqp&546673327#l51_@0D> 3 3!qZS.H?-EH*16T`&&546632#6654&#"3\44\99\44\93DD32CC20T44T00T44T0M=..==..=)&'&&#"#463232653#?)#460RYa-D.!0-)TU^,*%&DKur.-##ELzof+6673f4$ c _ߑuɵnJ    ;  # # LB& ^  ,   : R vl *  F F < L H  " 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.LightSelawik LightVersion 1.01Selawik-LightSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.1 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.Selawik LightRegularVersion 1.01Selawik-LightSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.12  "@MPQ@ DFLTlatn 4AZE >CAT HCRT RKAZ \MOL fROM pTAT zTRK     markzmarkmarkmarkmarkmarkmarkmarkmarkmarkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmk   Nv|jpd L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L L$ L* L* L0 L6 L< LB L L LNH L LZT L LZ` L LfT L LZl L Lrx L Lrx L~ L~ L~ L~ L~ L~ L~ L~ L~ L L L L L L L L L L L L L L  L L   L L   L L   L L  L L  & L L 8 , 2 L 8 > 2 L 8 D 2 L 8 J 2 L 8 P 2 L 8 , 2 L 8 V 2 L 8 , 2 L 8 \ 2 b h n L L L L L L z t 2 L L L L L L L L L L L L L L L L L L L L L L L L L L L L    L "  L L . ( L L . 4 L L . : L L . @ L L . F L L R L L L ^ X L L ^ d L L ^ j L L ^ p L L ^ v L L | L L L L L L L L L L L L L L L L L L L L L L L L L  L L L L  L L  L  L   $ * L  $ 0 L  $ 6 L  $ 6 L  $ < L  $ B L  $ H L  $ N L  $ * L L Z T L L L L ` L L f L L l L L r x L L r x L ~ L ~ L ~ L ~ L ~ L ~ L ~ L ~ L ~ L ~ L L L L L L L L L L L L L L L L L L r x L L r L L r L L  x L L r x L L r  L L    L   L  &  L  ,  L  2  L    L  8  L    L  >  J D P V L L L L L L L b \ L L b h L L b n L L t \ L L z L L L L L L z L L z L L L L L L r x r r r r r x r r x r L L Lr L Lr L Lr L Lr L Lr  L L  L L L L  L L  L L " L L ( L L 4 . L L 4 : L L 4 @ L L 4 F L 0&viILxM h) ] h--hNhM  h   ]h)sh ^33|q|SLLTrUU^| h ]) }h^9|hN  h"N h]khkh.AA)h)0++HhHOJJ 1 JJ>>N;q] !(##1#;-@@;$$ 1;Xvvr!r!+&&?i?FAA1KAm eRYTH^N0~:PN 4&10&1;1V;@@ 0&FN0 > JPV\bhntz `flrx~viILxMxVk1K;Y@MPQ=?<CE @ABDFGHIJKMP @ABDFGHIKMP DFLTlatn 4AZE BCAT PCRT ^KAZ lMOL zROM TAT TRK    !"#$% &'aaltaaltaaltaaltaalt aaltaaltaalt$aalt,aalt4ccmp>>0!0 +`e~`+zaU;Eʠ003q.kNq0  *H 0w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA0 150320173203Z 160620173203Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR1'0%U nCipher DSE ESN:B8EC-30A4-71441%0#UMicrosoft Time-Stamp Service0"0  *H 0 ꑽo!6(f3:f[K(4JC2=%{>b}tSct$P{9http://www.microsoft.com/pki/certs/MicCodSigPCA_08-31-2010.crt0  *H w\ב=ͽ{مCs|6ǵ,^T:q@ q&^}l;ɪ_]*'~e T(8Z{V2˓ۯn]D԰N ']a( "pr#z,C3Roӈlޤ5Sew 5Y؆1},wrlMY&²W5|P+Y)8RE)N[_'Pm4 8W7(5:8j]"^{00 a3&10  *H 0_10 &,dcom10 &,d microsoft1-0+U$Microsoft Root Certificate Authority0 100831221932Z 200831222932Z0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0"0  *H 0 rY\0d` BvSl>ok:t/2BN#r5W ʮ IhMKyKqG%ߝuϪsDׁ6\Eܯ=(hrsV5rv_wE8s[gRi/ t)v/T0Yҍb_F1P'@0r)("7N=2=͡8\NV(*2KOc-bE=F[&SzJF7<8w\V< _^0Z0U00UҴX7.3L 0 U0 +70# +71N&`;1o<-0 +7  SubCA0U#0`@V'%* SY0PUI0G0ECA?http://crl.microsoft.com/pki/crl/products/microsoftrootcert.crl0T+H0F0D+08http://www.microsoft.com/pki/certs/MicrosoftRootCert.crt0  *H Y9>&Fo@2j/nI_uL;-C -1#|P!]=/LVpyIr>A i˥ - PV-JҼp VชKWB4&I#vg٥d;dOnevz癨7%Ъ_F|pF/ϰ'L qEJp} ..*Q"?€`ęHǜǰb"199GQ(Imd5ȪC)AA[_-_vSKp 3F,n!™bS Zzt'nm+YצR]C?vj)=e38F(0$ *H  1000w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA3q.kNq0 +]0 *H  1  *H 0 *H  1 150414213647Z0# *H  1p=cX$X+W%lВc0  *H D{4nJwk1~%qQ답iҳ ao~=o0ZTh'FStTBۀrޯpPjcuBZa%3Xԑ*EcE`>{FrzB d^xwVAwJ 06Vf3\|Ed3;ݢ;[olf6k||K-59kJ#BfdZ{BFb)LQ.v 2 a(z`Mm6lt8kEkiwix-desktop-2.4.1/resources/fonts/Selawik/selawksb.ttf000066400000000000000000001262401473106011000234120ustar00rootroot00000000000000pDSIGܸGDEF{XJGPOSC {LGSUBstOS/2Ix`cmap"LXgasp {L glyf-YH$ddheadބ6hheaF4$hmtx%Qloca2 `maxppX namexptpost2{, fg_<DSR|q Q  ``[JX332H MS !"Q   *4xxxxxxxxxxHPPPPP;;000000000QQQQ ffffffffZT8 555555P P P P PPPP POPhPhPhPhPhP"""""7  ....:D:D:D:D:D:D:D:D:D:DCQQQQQQP}QQHPHPHPHPHPHPHPHPHP1OOOO)~)))))q)~)})L)s)sOO)))A&h/PPPPPPP PgMQ   Z CzIzIzIzIzI*****~~~~~~~~~+.....+)))))((((^s$la]C? A"b"pVgV\ "w|i-;gRdG@^99s5s;B-_V(`({(4sCakP}2W WaatL  Y,Oq+&+&p/*Ck#P ;9_> 83 3RNd+R:15*S "/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' ?C^uywx}|>< %:798;RW G2&-~,$ HI(n#?0)*+-ABD\]_V^[SX]UZ\TV@ /9~#'+37HM[gk~7 (6    " & 0 : !" 0: &*.69JP^jn7 &5    & 0 9 !"m4wTp$,>@^bdnvz|"/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' %!&4:W8,9[<2R-7U  -)*+?DABHC.G_\]^lKyuw}x|~(zv {"$#&./,(246578;=<>FEINPORTSYXWac`bgmnqsrUZVTSX]\^ZI@DPKAHGMJBECLONifho>?(X@pDl F8D\~,Ll4z &<T ,Zj  4 h  \  h ( v  4 \ :rP*HrFn>\"~:f*XBNZ&2>~ Z4\6DP\ht(4@LXr&2dp|T ,8p|:d  & 2 > J V b !!! !,!8!Z!!!!!!!!!" "4"h"""#2#F##$$$X$$$%0%R%b%x%%%%&&&H&^&&&&&'' '6'B'T'`'~''''''((( (,(N(n((((() )R)))***V*****++"+,,,>,L,`,->-^-..v..../*/:/V/h/////000(060R0~0000001 1*1<1b1~11111222g!!!!&&'#\9 ܣfj9H g$ !7!!!!!&&'#B@p\9 ܣGfj9H g+ &'332673#!!!!&&'#>H -\9 ܣ3}{U+*{}fj9H g;#%3#'!!!!&&'#$",\9 ܣbnIP,tۙsE&(P!!$54$32&&#"327#'@*ӝXE/Aoa>bnIP,tۙsE&(P"373#$54$32&&#"327#C랟JӝXE/Aoa>bnnnIP,tۙsE&(PA.!"'532654#5&4$32&&#"327#"'2x+&%#8;gXE/Aoa>bn B\VD1r*P,tۙsE&(,PH*&&546632#$54$32&&#"327#K,+K.G\*J/ӝXE/Aoa>bn(F)*D&SA*E(ϬIP,tۙsE&(| ! #%26654&krov*;|"O|373#! #%26654&8랟Skronnv*;|"O !!!!!!,2s!!!!!!!!@,2ݣs373#!!!!!!랟,2nns13#'#!!!!!!"죖 ,21s; #&54632# &54632#!!!!!!SRFFSRFlRQFFSRF,2"M@AKKAALLAAKKAALsH&&546632#!!!!!! K,+K.G\*J/v,2(F)*D&SA*E(s!!!!!!!!,,2s!!!!!!!!H.,2sc#"5467!!!!!!327Li_I,28P(.1"tMz&s;:('  !!!!!,jQ"!$54$32&&#"3267!5!#@òbbdKFSwk̎Cy,"rFV w䡝x4L:@Q"! .&'332673#$54$32&&#"3267!5!#u>H òbbdKFSwk̎Cy,"r)}{U+*{}FV w䡝x4L:@Q"!)$54$32&&#"3267!5!#6673@òbbdKFSwk̎Cy,"r))C>FV w䡝x4L:@fMMuKQ"H0&&546632#$54$32&&#"3267!5!#K,+K.G\*J/òbbdKFSwk̎Cy,"r(F)*D&SA*E(ͫFV w䡝x4L:@O !!!!!! o\fY #!!!#535!!5!3!!o So Y뼵!!f"'0f!!!!@ݣf1 3#'#!!"죖1f; &54632# &54632#!!SRFFSRFlRQFFSRF"M@AKKAALLAAKKAALfH&&546632#!!K,+K.G\*J/(F)*D&SA*E(f!!!!<,f!!!!(HfZc#"5467#!3327Li_IS8P(.1"tMz&f;:(' 8 >5!8[ 1|uZR  !!67!x #6#7@@A.x !!!!67673' #6#7)C>@@A.MuKg!!! ([ !!!!!@ (ݠ[i"3Q !!!6673 (ψ))C>[PMMuK"3  %!57!%Ϡ 0VV¥{!37!!47##&'##; CGnkGg#Lf_qR<'_9!3&&53!&&'##7t ' z HM%;EfD>!!!3&&53!&&'##t@7t ' z ݢHM%;EfD>373#!3&&53!&&'##랟7t ' z nnHM%;EfD>!3&&53!&&'##66737t ' z ))C>HM%;EfD>PMMuK!1'>7&'#!!3&&5!)gw8d7n '  7aMP>M%; I/&'&&#"#46323253#!3&&53!&&'##D5'2Li_#C/)4Fj\7t ' z 4Z\HM%;EfD>P$54$32#>54&&#"33Ǫ9=cb}cc}OR|㖚癗}P#!!$54$32#>54&&#"3b@LǪ9=cb}cc}OR|㖚癗}P1&3#'#$54$32#>54&&#"3"죖Ǫ9=cb}cc}1OR|㖚癗}P; '7&54632# &54632#$54$32#>54&&#"3SRFFSRFlRQFFSRFQǪ9=cb}cc}"M@AKKAALLAAKKAALŹOR|㖚癗}P#!!$54$32#>54&&#"3,LǪ9=cb}cc}OR|㖚癗}P'3#%3#$54$32#>54&&#"3"Ǫ9=cb}cc}OR|㖚癗}P#!!$54$32#>54&&#"3HǪ9=cb}cc}OR|㖚癗}P",#"&''7&&54$327&#"6654'3dYVmMQ9zUn_9Yf}ccF4PqGD[`RA=ZRxX|㖷724PI'7&'&&#"#46323253#$54$32#>54&&#"3D5'2Li_#C/)4Fj\Ǫ9=cb}cc}4Z\OR|㖚癗}O-(%!"#"$54$323!!!!327&#"-!0aOХM'W(X#-w\ulSqk OR sX{} !2##!2654#wyiΔq{x##!!3654#37wIͷiΔq:{xP'$&&'#"$54$32326654&&#"ݴi|PP`Ǫ9d_0{wopqlLb;[Rvy6>;,cS2H0#0WzY'# NS+@- 3\jP0!!&'732654&&'.546632'&&#"#@ ΅\uUzCe\seWU>lLb;[Rvy6>;,cS2H0#0WzY'# NS+@- 3\jP3373#&'732654&&'.546632'&&#"#랟+΅\uUzCe\seWU>lLb;[Rvynn6>;,cS2H0#0WzY'# NS+@- 3\jPA>!"'532654#5&&'732654&&'.546632'&&#";[Rvatx,%%#8;gh}\uUzCe\seWU>lLb@- 3\yq2\VD6:;,cS2H0#0WzY'# NSP,4&'732654&&'.546632'&&#"#6673΅\uUzCe\seWU>lLb;[Rvy梬))C>6>;,cS2H0#0WzY'# NS+@- 3\jbMMuK"f!5!!!cDbE"f3#!#53!5!cDo"f373#!5!!!랟cDbnnE"Af!!"'532654#5#!5!!tx+&&"8;gJcDb?\VDE"f!5!!!6673cDbD))C>EPMMuK!! !! <, *m[j!!!! !!2@ <, *m[j13#'#!! !!r"죖W <, 1*m[j; &&54632# &54632#!! !!SRFFSRFlRQFFSRF <, "M@AKKAALLAAKKAAL*m[j!!!! !!i, <, *m[j3#%3#!! !!c" <, *m[j!!!! !!}H2 <, *m[jc327#"5467&!! HEL.1"LiH; <,F!T (' Cm'' m[j*&&546632#6654&#"3!! !!f;aeO5@\U1T4=6+7D "t@D "tApD "tDD "tGD "tID f"tKDc 1=7#"&5467&'#"&&54663254&#"'66323665&#"3 5@lt75,\{?f^e}po`]2O6ILO%"me7\jUbXG YT8m1_\2T2>aeO5@\U7c('*1T4=6+7D %"tM4D "tPCs1:G3267#"&'#"&&546632754&#"'66326354&#"%67&'&#"3J`npCK3GY?lNf^e}qn`]3O6kٿaghsȂ `pTbXG}vPS\g(df6]7>a_J6MUNjmc Pkveu:2$) ?6,8 #"'#!663654&#"3[km؛=0 4`3ysHq8FtFzޓqQ&&54666&#"3267#tv[=/mu;[IAXSz坛~) Q"@Q"BQA+!"'53254#"5.54666&#"3267`,%%#zn |\v[=/mu;[IA\SLDAՋ~)2 DQ"HQ#&'#"&&546632!$655&&#"34Rh~蘆v%!5|>url'l^zޗOUW`@$%PW+&&5466327&''7&'7%#>5#"3yxَwXTpG"qXAF]Tn;Nq=uLaxVi F3{q3QfDPeQ"QQ+&'#"&&5466325!5!5!3655&&#"3O%!4Rh~蘆v5|>urlW`@Jl^zޗO˟?$%P 3267#"$466354&#"%`oqCK3GYwឿaghr}vPS]f(uZPmufP"@P"BP"DP"GP"H#P"IPf"KPc)23267327#"&5467#"$466354&#"%`oqCK3NS(&$'>Ppv76B55#"&&546632747&&#"3265Q`Yىr虏)6w6Pv@2jO{2Ee<{bHC!J_GU|OQ"AOQ"F^OQ"Ha;!4&#"!!63:U]k;k, qdrm,(EkQ!4&#"!#535!!!63PU]k;k,  pdrm,(Eˍj~&&546632#!!E((E+*E''E* (E+*E''E*+E(2!! 2x"@b"D"Gq"H"I~"c}f"KLc"#HLs&&546632#>5!F((F**D('E*]r{1 (F*)E((E)*F(RAtbF s >5!r{1 AtbF D !!67!/ /3! k)u5)qD"E!! {"@#"QUAq"E("G !57!7G ^Y_^]$!6&#"!&&#"!36632663RS`\ P\@g-!E_].Nldr4`{E714az23ViD?@;:A;!4&#"!363:U]k;j+sdrm+(D\v;"@;"Bq;"EH;#'>74&#"!363:U)kz6]k;j+sdr ;hTm+(D\v;"PP&&546632#>7.#"3QyDExNR}EE}R~旚ꀀꚘ~FTUGHUTEP"@P"DP"G7P"IP"J;Pf"K T&#"''7&5466327667.#"313@nyDExNR}EE}R%@_~Kt-FTUGHUTEP"PM:#,<3267# '#"&&54663266354&#"%667.#"3`npCK3GYG||GAŀaghsyDExNR}EE}R}vPS\g(HN~旚MGKNZPmveFTUGHUTE*!#"&'!3663654&#"3^im؛x%5d3ysF}.FtFsݛdUvEK֥.*dua>*"#"&'!!663654&#"3^im؛x5a3ysF}.FtFsݛdUBG֥.*dua>Q(O#"&&5466327655&&#"3OZהhxE@4yAwrlZ^zޗ|2/G#% 32&#"!334j!uΧ "@Z"B+Cq"EI<"'7674&&'.5!2&#!Cr.E<\sUm9pB@(<7]|[cMHc#+2p`3<6")#9wcI<"@/I<"B@IA<4$!"'53254#"5&'7674&&'.5!2&#<\`+&&"zn Cr.E<\sUm9pB@(<7]|[CSLDA:Hc#+2p`3<6")#9wcIq<"E;#&'73254&&'.54667>54&#"!46632%72PiM,Bz/(:6RiL-B505%cQEh9xܐl:P=40+,'*+327#"&5#73!623""HT(3@DWW6e^|*+!327#"&55#535#73!623""3#HT(3@DWW6es^sF*"Q*A+,327#"'!"'53254#"5&5#73!623""HT(3@DC:\`,%&"zn _WW6e LSLDAL^|*q+"Ej~&'#"&&5!32665!.NXK Vw:a9%!']Y$L5ni]k9mI(W`@~"@~"D~"G,~"I~"J1~f"K~c(7#"&547&'#"&&5!32665!3H;Lhuc(NXK Vw:a9%!D XNuiSU$L5ni]k9mI(W`@wRQ~%"Mv' !3667!!yspy-!!3667336677!&&'#!     y@O qCD ,] HH "@"D"G"I !3!!#!iJ% G+6677!37%I~/k*9>s[Z/NLs3+"@+"D+"G+"I( 7!5!!!()F3/+("@Z("Bk("H^$&54632#7254#"3nuបmuߝdnkaGd43aD@Z}s%'%3#(1TEs!74667>54#"'76632!!s`lS]??K))OSX|bGP59=S@Y}S يȁO9Nb<%732654!' 54&#"'76632#"&'-FNk^rJ{FcG_,Tc_M P cT $J !53##^ @F32654&#"!!7632#"&&')R}**#4'$cKf!dxqtrǁ l%# $32&#"63654&#&3 W{р΂j]JJ pE^gnVekrq"k]{XEe]=y{;!5!!+]a$,<&&54667&&546632#6654&#"36654&&#"3uKQezgunvbO~Iuْ2J,VJ4O,*O4Ee4Ef5:fAmzVo4]i_Xq\5pUzl*P5Kc-O20P//GþQiϒyF]L~aRq7C+ )'%3#4667>54#"'76632!!Wp1yR4J=49(HZ Ap=3E4( !W$L΋:`G1*6B%y y=lP3*? '%3#!53##Xp2zmPzzW$L΋eXH)47'732654&#'2654&#"'632#!53##p]\g48l`Zb'#bTaRyBQLZ`TcmOzzW$!'#+.2."$%2[54&#"'76632!!b4I=49(M=HZ Ap=3E4( !:`F2*6B%B7 y=lP3*_%'732654&#'2654&#"'632#a\f48k`Za&$cRaRyBQKZ_Td_!'#+/2/!$%2[54&'"'6632#&54632# /C6).WPb%BK1F9-3#0PPCCQQC hK+!0H4LT#dN-$4P9NAAPPA@Oi% 3#3#q,,{3#,;&&546632#6673J++L./K*+L0AA]V+L-.J**J./K*|mlaoC`@A[3dy&&54'56554667PPJVE}~G:7fVG\C @!#3!L|@C @p 71zomzdj^3C@e!5!e!5!e!!#ee5D? !!!!5?Dz@DXPX;Q? 7!3!<D@D@PXPXB?!!B@DXl?C@9# _R#67#67AA]V?@A]VxmlahlmbVJ667376673VAA]W@A]Vmlbgllb`#47AA]Wxmlb{[45$5.546677&#"3267t~^]{X/mu;[IAՍև &)CJ/.+77&547'76327'#"'6654&&#"3CEE~li}GG}iik>?k@@j==j@ʉoy{lEEpwusEE =j@?j==i@@j=a.'T/#5&&'732654&&'.546753'&&#";[Rv[o[vUyCgZt雕U>lLb@- 3\#64;,cS2H1"0Wy# = NSkF,%#"$'#53&547#53632&&#"!!!!327FFR.p\\r2+?<>"p0q&/M%k^A'.,4z00wFP'7327#537>32&#"3##C-#~!YhhiNC%&2}[Ѣ TgT }%!56655#5754632&#"3#o_Nca3T["RR+\n 6gU̼gPC2]3!!!!5!5!5!5!!36677!0L(  : . ! W663232673#"&'&&#"#K\6iI?S&17LY7fI?P&sή])'""SGw])'" ;b &&54632#!!&&54632#?%N%=?%N<>IN9L$?%=QL@(?#[$=$>SMA;Mr!!!!==r]Q%550sU8T]QC*@L!5!#,]t&'#"'!5!32665!+ NXG; Vw:a9%!'V`$L5|]k9mI(W`@o/ 77TVUTPTTMWx 0=&&546632#>54&#"3&&546632#>54&#"32pW^e^W]d-6A/5FC2X^e^W]d,6@04FB2W$YY_d^W]f_(E*:NS==R54&#"3&&546632#&&546632#$6654&#"3 6654&#"32pW^e^W]d-6A/5FC2X^e^W]dÙX^e^W]d 6@04FB2B6@04FB2W$YY_d^W]f_(E*:NS==R !5!3!!#`~ !5!3!!#!!`$?3#3#3#kOGT##&'#"&&54663254&#"'66326654$#"3267# $$! 6655&#"3p3\|?f^e}po`\2O6OK煋%~?w}t+ fe7\jTbXF\~i_2T2>aeO5@\UTS+ӎ5;D>68{1T4=6,6t#.:$'#"&&54667&546326676654&#"67&'3K⊆fao~žδrR30V^t}XNPYISSkAzk*\cm]kbc1²TpgUt`w\nT18[U`k_=9|)BN-EOL.54663!####dOH[%ef9LZ^I }9$54$32#6$54$#"3.54666&#"3267#^Yңy\]~G1%W[wj.F<3EASWũa|{d!ml}-6#"$54$3$54$#"3###!232654&#]Y^ԝ$PDջ/p935/.DSWؗm-vne&+6/YE.:#&'766'4&&'.567&&'4632&#$654&'AǦCpNU.C>[tU>G9vAB-E;[uUtr;OTbMHSWLH@4#.:w`S(sT<94;#1 "@}dO<"+f8HD>Os#5!##333#####ٕϟnṹ&ojqqq&&546632#6654&#"3;JIOOJJO8LL88KK8JONIINOJM98LL89Mg3###:&V #%%35CWC&%%#57'53%66!#p&&'332673#OP v7CTYKXy>;ZI/373#/A?'53254#"53!&&"zn \`ADASL*3#'#΅~Cq~6673CAA]Wmlb#67;=XQ,ff \ &54632# &54632#SRFFSRFlRQFFSRFM@AKKAALLAAKKAALk&&546632#K,+K.G\*J/(F)*D&SA*E(!# #3#3#>f!!0fPc54673327#PB>͈.1"Lic5qGaB(' %&&546632#6654&#"3f;2!#!&&'332673#P v7CTYKXy>;ZI8373#83A?'53254#"53!X%&!{o \`ADASL33#'#΅~R5 &54632# &54632#SRFFSRFlRQFFSRFM@AKKAALLAAKKAALN&&546632#K,+K.G\*J/(F)*D&SA*E(B!# +3#3#>Af!!0f:c54673327#:B>͈.1"Lic5qGaB(' 5C&&546632#6654&#"3f;CAT HCRT RKAZ \MOL fROM pTAT zTRK     markzmarkmarkmarkmarkmarkmarkmarkmarkmarkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmk0 Nv|jpd                     $ * 0 6 < B H N $ ZT f` fl r` fx ~ ~                         & ,   2 D 8 > D J > D P > D V > D \ > D 8 > D b > D 8 > D h > n t z >        "   (   .  : 4 F @ F L F R F X F ^ j d v p v | v v v       $ *   0  6  6  6 < B H < B N < B T < B Z < B ` < B f < B l < B r < B H ~ x            , & 8 2 8 > 8 D J 2 8 2 8 P b V \ b h \ b n \ b t \ b z \ b V \ b \ b V \ b \    z 8 2  8 >  8  8   8   8 2  8   8 2  8 "   ( 4 . 4 : 4 @ 4 F 4 L X R d ^ d j d p d v d | K ~y2K.WL hg?'f *L^zz^}A3^ 6^a8885838|  ^]3^i 44^_565636|E3[^~^F\ ^ 4  5s | \ [}^cciTwkyN7^4c9eAEC^EvA ^5C|h^)5h[^[]^5a^acd3 HC WWpp"(M#YA$ $1]33443qqrr]]ssG @ww(hXC25hu__`"aiiklkkY fAcjhwADC `aaaCC@~@@ CA0 > JPV\bhntz `flrx~~y2K.W{F4YC@MPQ=?<CE @ABDFGHIJKMP @ABDFGHIKMP DFLTlatn 4AZE BCAT PCRT ^KAZ lMOL zROM TAT TRK    !"#$% &'aaltaaltaaltaaltaalt aaltaaltaalt$aalt,aalt4ccmp>>0!0 +VE?Up6 o>6ý<003q.kNq0  *H 0w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA0 150320173203Z 160620173203Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR1'0%U nCipher DSE ESN:B8EC-30A4-71441%0#UMicrosoft Time-Stamp Service0"0  *H 0 ꑽo!6(f3:f[K(4JC2=%{>b}tSct$P{9http://www.microsoft.com/pki/certs/MicCodSigPCA_08-31-2010.crt0  *H w\ב=ͽ{مCs|6ǵ,^T:q@ q&^}l;ɪ_]*'~e T(8Z{V2˓ۯn]D԰N ']a( "pr#z,C3Roӈlޤ5Sew 5Y؆1},wrlMY&²W5|P+Y)8RE)N[_'Pm4 8W7(5:8j]"^{00 a3&10  *H 0_10 &,dcom10 &,d microsoft1-0+U$Microsoft Root Certificate Authority0 100831221932Z 200831222932Z0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0"0  *H 0 rY\0d` BvSl>ok:t/2BN#r5W ʮ IhMKyKqG%ߝuϪsDׁ6\Eܯ=(hrsV5rv_wE8s[gRi/ t)v/T0Yҍb_F1P'@0r)("7N=2=͡8\NV(*2KOc-bE=F[&SzJF7<8w\V< _^0Z0U00UҴX7.3L 0 U0 +70# +71N&`;1o<-0 +7  SubCA0U#0`@V'%* SY0PUI0G0ECA?http://crl.microsoft.com/pki/crl/products/microsoftrootcert.crl0T+H0F0D+08http://www.microsoft.com/pki/certs/MicrosoftRootCert.crt0  *H Y9>&Fo@2j/nI_uL;-C -1#|P!]=/LVpyIr>A i˥ - PV-JҼp VชKWB4< %:798;RW G2&-~,$ HI(n#?0)*+-ABD\]_V^[SX]UZ\TV@ /9~#'+37HM[gk~7 (6    " & 0 : !" 0: &*.69JP^jn7 &5    & 0 9 !"m4wTp$,>@^bdnvz|"/61 +)*5  !%'0139:@JLMQV[dejkp = Yt 3 ' %!&4:W8,9[<2R-7U  -)*+?DABHC.G_\]^lKyuw}x|~(zv {"$#&./,(246578;=<>FEINPORTSYXWac`bgmnqsrUZVTSX]\^ZI@DPKAHGMJBECLONifho>?(V>lDj H6BZz$Dd4z 4LxHXp| P @ x V  n 2 \ 6l@2Zz&Lx2lN4t dp| NZ0ht 4x".:FR^jz $>z.:FR^jv.fXdp*P~    * 6 B | !!!4!Z!f!r!~!!!!!!""J"""##0##$$H$$$%2%V%f%|%%%%&& &J&`&&&&&&''4'@'R'^'|'''''''(((((B(\(p(z((())R)))*,*T******++,,,,L,Z,n,-P-p-.*...//"/N/\/z/////0 0 0.0D0R0r00000011.1L1^11111122B2V*!#3#&&'#Sw!!Gf9H *" #73!#3#&&'#ُ Sw!!M%f9H * &'332673#!#3#&&'#TFCU ZSw!!4ka/55/bjf9H *#%3#'!#3#&&'#YKSw!!=}f9H * )&54632# &54632#!#3#&&'#;:()=;)?;9(*<:*Sw!!0:*)88)*:9+)88)*:f9H * '3!#3#&&'#MSw!!= f9H * !5!!#3#&&'#Sw!!@sf9H *p$7#"&546673!#33&&'#& $>ej8U)xSw!!Cf6:8d UR4`FGfDM#.09H *y#-&&546632#32654&#!#3#&&'#R\56]:9\56]:+<<-.==.USw!!1V46W21V55W2!9+*99*+9'f9H **!+#463232653#"&'&&#!#3#&&'#)b][(B,%3)'e[W&C-&7Sw!!9=qy$#:>ry$"f9H H%!!#!!!!H$ .yyGyyG^ #7!2'2654&##265!#h\k`WEqyM Nf{& ]`|e$pV e$54$32&&#"327#甪E嚪%5Jw堞,^pIP,Ow$1e3#$54$32&&#"327#lv甪E嚪%5Jw堞,^pIP,Ow$1e"373#$54$32&&#"327#X甪E嚪%5Jw堞,^pIP,Ow$1eO.!"'53254#"5&&54$32&&#"327##9y%$. ~E嚪%5Jw堞,^pGWRfVT:P,Ow$13e '&54632#$54$32&&#"327#@>,,?>,甪E嚪%5Jw堞,^p$?-,::,-?ȬIP,Ow$1 ! #%2$5!gl yHYj"O373#! #%2$5!MXWgl yHYj"O !!!!!!V$yyy3#!!!!!!V$դyyy373#!!!!!!֠XV$yyy 3#'#!!!!!!Y,V$ }}yyy #&54632# &54632#!!!!!!;;:()=;)?;9(*<:*V$!:*)88)*:9+)88)*:yyy &54632#!!!!!!@>,,?>,V$$?-,::,-?yyy3#!!!!!!~V$yyy!!!!!!!!"V$syyyp#"&54667!!!!!!3327#?ej8U)V6Q,;7&{ UR4`FyyyDM#.0u !!!!# yxtf!$54$32&&#"3267!5!#7ϠK\^(XSU>bzDUx)%y:@f /&'332673#$54$32&&#"3267!5!#|TFCU ϠK\^(XSU>bz%ka/55/bjŪDUx)%y:@f8!)$54$32&&#"3267!5!#66737ϠK\^(XSU>bz#2,DUx)%y:@YuLVGf -&54632#$54$32&&#"3267!5!#@>,,?>,ϠK\^(XSU>bz$?-,::,-?ƪDUx)%y:@ 3!3#!# lfr-`##!##533!33!!`󆍍  ry22y@3#f "'0I3#3#՟fH 3#'#3#Y}}f &54632# &54632#3#!<;()=;)?;9(*<:*:*)88)*:9+)88)*:fi &54632#3#@>,,?>,C?-,::,-?f@ 3#3#.~ fC!!3#=sf9pj#"&54667#33327j#?ej8U)36Q,;7'{ UR4`FfDM#.0J  >53JmN7R ^#3667#څ"/ (%')8^!##3667673'^]څ"/2,^ (%')RuLVG<3!!?;y 3#3!!?;Օy"3Q,8 3!!6673?;#2,ytYuLVG"3B4 %!573%;[yy-R|Sb}2337673#47##&'## 앁  9 Z(H"6fz)Nd);=\33&&53#&'## & L%;f!M>3#33&&53#&'## & ՞L%;f!M>373#33&&53#&'##X & L%;f!M>833&&53#&'##6673 & #2,L%;f!M>tYuLVG"%#'>7&'##33&&533~> '   xWyt!M>L%;0&'&&#"#463232653#33&&53#&'##NC-&7,)b][(B,%3)'e[WF &  $"9=qy$#:>ryL%;f!M>e$54$32#6654&#"38Ѥ/5Υ~~NR}躸e#3#$54$32#6654&#"3Ѥ/5Υ~~NR}躸e &3#'#$54$32#6654&#"3YaѤ/5Υ~~ }}NR}躸e '7&54632# &54632#$54$32#6654&#"3,;:()=;)?;9(*<:*|Ѥ/5Υ~~!:*)88)*:9+)88)*:ƻNR}躸e#3#$54$32#6654&#"3ޙ~Ѥ/5Υ~~NR}躸e'3#%3#$54$32#6654&#"3noѤ/5Υ~~NR}躸e#!!$54$32#6654&#"3kѤ/5Υ~~sNR}躸Y#.#"&''7&54$327&&#"654&'3Gc·WGMQ/|TG hBd~DBDpUP:aRFB:7:RqEIe)9&'&&#"#463232653#$54$32#6654&#"3lC-&7,)b][(B,%3)'e[WѤ/5Υ~~%$"9=qy$#:>ry»NR}躸e(%!"#"$54$323!!!!327&#"p4iV֢?/i.d$pG|韭pyy NR yy  !2###2654&#k|܌݆Wbm###3!654&#3k|܌݆ubme'&$'#"$54$3232654&#"yό8?ZeѤ/4~~G{NRW뗗a!##!22654&#g܆krY}%}ꔐa #73##!22654&#sDg܆k4rY}%}ꔐa%373##!22654&#ꠡbg܆k$눈rY}%}ꔐ8a!###!2'2654&#673'ag܆k2,^rY}%guLVG<_*&'732654&&'.54632'&&#"#v-tQQxgubЖ-9]BKnczjhȌ .5w7+}OlE-3Uk4yt~Ca@-7]vz`_.3#&'732654&&'.54632'&&#"#Bv-tQQxgubЖ-9]BKnczjhȌ.5w7+}OlE-3Uk4yt~Ca@-7]vz`_1373#&'732654&&'.54632'&&#"#͠XYv-tQQxgubЖ-9]BKnczjhȌ.5w7+}OlE-3Uk4yt~Ca@-7]vz`_O<2!"'53254#"5&&'732654&&'.54632'&&#"KnczjZzpy%$/`q-tQQxgubЖ-9]Ba@-7]vqe >WRfVT/3w7+}OlE-3Uk4yt~_8*2&'732654&&'.54632'&&#"#6673v-tQQxgubЖ-9]BKnczjhȌc#2, .5w7+}OlE-3Uk4yt~Ca@-7]vz`YuLVG3!5!!#bb!yy33###53!5!VՅb!rvr9yy3373#!5!!#ѠXbbyy3O!2!"'53254#"5#!5!!8py%$/bbGWRfVT!yy38!5!!#6673bb8#2,!yytYuLVG3! 3!z*m(g3#3! 3!Mz*m(g 3#'#3! 3!Y)z }}*m(g &&54632# &54632#3! 3!;:()=;)?;9(*<:*Dz!:*)88)*:9+)88)*:*m(g3#3! 3!~z*m(g3#%3#3! 3!noz*m(g!!3! 3!q3zs*m(gp327#"&5467$3! W@L;7& #?ejO8z4"f/.0d UR>q"7m(gj*&&546632#6654&#"33! 3!r\56]:9\56]:0==.-<<-z1V46W21V55W2Z9*+99+*9*m(g 3367#  z7H>De&+3366733673#&&'##&A  Qi@ 7c RT$o4R+_tf4S"OA&+"3#3366733673#&&'##YA  Qi@ 7c դRT$o4R+_tf4S"OA&+ %3#'#3366733673#&&'##YA  Qi@ 7c  }}RT$o4R+_tf4S"OA&+ 6&54632# &54632#3366733673#&&'##;:()=;)?;9(*<:*A  Qi@ 7c !:*)88)*:9+)88)*:RT$o4R+_tf4S"OA&+"3#3366733673#&&'##~A  Qi@ 7c RT$o4R+_tf4S"OA+k33673#&&'##M7  %:G¢#=H  9-:(G'C33673#=O  ^-T 3!7'C3#33673#Ѫ=O  ^-T 3!7'C 3#'#33673#Y=O  ^- }}T 3!7'C &&54632# &54632#33673#S;:()=;)?;9(*<:*=O  ^-!:*)88)*:9+)88)*:T 3!7'C3#33673#~=O  ^-T 3!7<C 7!5!!!<5;/y(y<C 3#!5!!!75;y(y<C373#!5!!!X5;y(y<C &54632#!5!!!@>,,?>,5;$?-,::,-? y(y^,&'#"&546325#"'6632$6655&&#"3\7cQ˳,Fz/[ZL5L|r'kd6W2Ut  ꝥPBvM ',]YP\^"t@h^"tA5^"tD^["tG^"tI^"tK^p.<7#"&5467&'#"&546325#"'663236655&&#"3( '2Y]NJ(cQ˳,Fz/[SV,*L5L|r l SO;x8UV6W2Ut  ꝥAp++.BvM ',]YP\^"tM%^"tP=\i0:I327#"&'#"&546325475#"'663266354&&#"%667&'&&#"3YX(DZ)GT9 h]˳,Fz/P<ƅ?`cHU 6O{r{qNHBs(vyBn?U E  Y]KJRI8hE */`[P\;##"&'#3636654&&#"3aiΔ"2QFUF`KlfC^Zyݕ^UfvXi\867f<]&&54666&&#"3267#rtO4(2w@µ7sN*KPy䟟{}Ĺ"#w$(]"@6]"BI]O,!"'53254#"5&54666&&#"3267#l%$/tO4(2w@µ7sN*KPoLI\LJ؟{}Ĺ"#w$(X]k"H_K$&'#"&&5466323$665&&#"3>(kwVTI>DtYMp'oe`dwݖuz]GQfJ;;`~ld]-&&5466327&''%&''7%#>5!"3nu׎^`q+m]Hf'-qԍjPhUQiVnTZ?3[SoݞohkĂe_"Q/_q,&'#"&&546632!5!533665&&#"3Vn>(kw?}.I>DtYMpCoe`dwݖu2rrQfJ;;`~ld] 327#"$466354&&#"%X(DZ)GTq֕?`c{pOHBs(vKJR]"@]"B]"D]["G]k"H]"I]"K]p+532710"327#"&5467#"$466354&&#"%X(DZ)[_1/"#.A^bEBkWq֕?`c{pOHBrG{1.0f UR9v8vKJR,7###5754632'&#J~P%),=u_n`l u_*'>55#"&&5466327&&#"32665g.}kxZH)>EtYNp_I2w ZcMPwݖBAiJ<;`~ldQf_"A_g"F/_k"H#4&#"#363Pm}a=xdr4OD%s(#4&#"##5353!!63Pm}a=}}?xdr4OD%rrB &54632#3#44''44'B4''44''42&3#2"@K"Dk["G{Pk"H("I "nf"K/pak"#HLWTA &54632#>'355'&44&m95&&55&&5^F T% >'39^F  #367#侁v"E%3#"@Lj"Q*5"EQ"4 #57378H\~K,%#&&#"#&&#"#36632663:PtP3lO5[8Zh*A`dr4KA[ zdr4OD%r"@"B"E '>54&'#363P:m}`>[ zdr x]OD%r"Pp]:&&546632#>7.#"3||㕓xyܒfZ[emZZm~痙ꀀꙘ~{`subbur_]:"@]:"D]:["G]:"I]:"J]:"KXQ#,#"&''7&&5466327&&#"$'3266712yܒ_?sFv7:|a?vEF .uDl[;]fZ1Bc~41y?{Ag97|Ad&+-bu_I`s]:"P[(#-=327#"&'#"&&54663266354&&#"%667.#"3X(DZ)GT;=ٌ||㕌=8Ք?`c[[emZZl{qNHBs(npku~痙siosKJRI`subbvr_*;"#"&'#36636654&&#"3diΔ[#EjFUF`cY]Zvݘe]}JMvXmXgQfJ9=ld632&#"#3PW,/X6^E ~CA!o"@U"B&"EV'&'76674&&'.56632&##EW)W#&&'76654&&'.54667>54&#"#46632G0F>ObFUZ^BSZ4KAL]A0F84:(scSzAezcR5L<.2#F'={f#)#_Y FL|"@3|"DS|["Gp|"Iki 333###mHlj66773377la/ w".9*l|PzR$NLsF"@F"De["G"I~:m 7!5!!!:jv3(s/v:m"@;:m"BN:mk"HZ!&54632#72654&#"3fmГgnҔbIHadKIb@Ztr'%3# JhqEe"74667>5!"'676632!ek|dqLCN'#WO_rixS=݌WGbYفzOIif~(732654&#' !"#'76632#"&'9J6h:?vA]CY)w  y P cT   !53##Y@ltD732654&#"!!6632#"&&''VȪ(*1o PiE_' ~;m| t)# 632&#"6636654&&#"3ԻVvzHxa{dQI+zT>54#"'67632!!egn`N(t@ZK=F/*U; }Rw?WG4<(2DCLlyJtQ6+o2[54#"'67632!!X@ZK=F/*U; }Rw?WG4<(JtQ6+o2[>lAAn@@mB >jAAm?@lA@k>wM &54632#&54632#==-.>>.-==-.>>.=,,;;,,=<,-;;-,<1<66731F4SḢt}fN" #3#&54632#ڎi 66++66+7,+77+,7Q F%w!!#!#!7!!7!3!3!!!!eETkTTdSCTgUWkWDauqa@anjaC &54632#66++66+7,+77+,7*4667>54&'"'6632#&54632#O6L=18%za CJ0F92;'%66++55+ cP/'6P7kv#w[{K.(=]B7,,66,,7j( @3#3#tt"tt++3#tt+1M &54632#6673::++;;+F4SHK;+*99*+;釵t}f C@-%J[1]&54'565467TLF;+Z/jfo/-P_,iEC X@#!#3!Vee5C X@ | 7'GztzIAAN|CZ@/!5!n/!5!n/!!"/n/l? 3#3#l $A!$XPX\? 7333^$ڪ!߹$ګ PXPXl7?3#l $XM?C@T_##  #6767 F4SHt} f  ''6673THgF3(e 41p,zp-07>pO^'732#5376632&#"3##6!*^hx}6-' ^g5nሖl n\Px!%!5$55#5754632&'&#"%!xޭ:-qz."ooo˻b d KxdЖE!!!!#!5!5!5!3366732^|m>. %ppppw 3> u63232673#"&'&&#"#s;dB54&&#"3&&546632#>54&&#"3Jhm|VZ`[UX`@_65\9;a76^:ҖVZa[UY_@^64\9?oDCl?[ad]Zad^o@pEBl=?oDCl?Q L#3CSc!&&546632#>54&&#"3&&546632#&&546632#$6654&&#"36654&&#"3Jhm|VZ`[UX`@_65\9;a76^:ҖVZa[UY_ЖVZa[UY_^64\9?oDCl?[ad]Zad^[ad^[ad^r@pEBl=?oDCl?@qEBl=?oDCm?z# !5!3!!#vimimmimhz !5!3!!#!!vimimiemimh~m,3#zz,3#3#zzzz%CQ5#"'66326654$#"!267# $$! #&'#"&54636655&&#"3J,Fz/@~rȔC|(kk$W]ĝ7cQ˳ML5L|r=Ut  ꇅɓ7=`F?j#.wkd6W2%BvM &,]YP\w%3?&'#"&&54667&546632667>54&&#"67$'3lyyqS_u^e]Wk}J5flapZ7a;?f;ަQwX^*Wbh`g`h1Ůc\W]hkBU݀=sY|6UyQ<`7>mB MHB^Ep@cQ"&&54663!####UPDuG[]FzJMyC^<w:$54$32#6$54$#"3.54666&#"3267#WWˮ#ޯݩ"degNjF/$`n1hC&CGVWl$&ڰܪkˍmp0j #w-5#"$54$3$54$#"3###322654#VWW˯#ޯݩ" `SNlxR]iVW$&ڰܪ{I*woECf7E#&&'76674&&'.5467&&546632&&#$6674&&'IQfHL)N4eu:VJYlMVMMVTjA~,&3i)ix7SG[qQNC7QIOW2P=Rdv\U|C'"o#([L7H+!;mWX"(xcSzAlOR6G)!>|eR}$C&`B4G. gQIj#5!##333#####t؄n?k)qqj))~&&546632#>54&&#"3=zEExIKzFEyJ+L++J-.K+*J-EzKIxEExIKyF`-N/.L,,L./N-c3###5{zh:8 #%%35O-mh:%%#57'53% 66M3#ϛ&&'332673#}vEsPE=WvLwI>sMHNRDLs?373#deXO1A'53254#"32!$. XflO\LJLIt3#'#NYwpoz6673oF4SHއt}fg#6677=.MA+}js_Et[ &54632# &54632#;:()=;)?;9(*<:*:*)88)*:9+)88)*:k &54632#@>,,?>,?-,::,-?<3#<~3#3#xUzV>!!sp &546673327#j%6.nH>;7'$?pUR/O>-JX(.0d &&546632#6654&#"3\56]:9\56]:0==.-<<-1V46W21V55W2Z9*+99+*9-`h!!-3hyjv!!j=r&'&&#"#463232653#C-&7,)b][(B,%3)'f\W$"9=qy$#:>ry3#wD|3#`%D&&'332673#vEsPE=WvLwI>sMHNRDLs?}373#}deX6OA'53254#"32!Z$. XflO\LJLIo{3#'#IYwp[ &54632# &54632#;:()=;)?;9(*<:*:*)88)*:9+)88)*:X-k &54632#@>,,?>,?-,::,-?a3#a~Cv3#3#xUzV>-%!!-sKp|&546673327#j%6.nH>;7& #?pUR/O>-JX(.0d Y&&546632#6654&#"3\56]:9\56]:0==.-<<-1V46W21V55W2Z9*+99+*9&&'&&#"#463232653#C-&7,)b][(B,%3)'e[W$"9=qy$#:>ry`96673`0#>7t}enJ  ; ! #+ #+ LN& ^ " @ " " N "f v *  F F X L T . 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.SemilightSelawik SemilightVersion 1.01Selawik-SemilightSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.1 2015 Microsoft Corporation (www.microsoft.com), with Reserved Font Name Selawik. Selawik is a trademark of Microsoft Corporation in the United States and/or other countries.Selawik SemilightRegularVersion 1.01Selawik-SemilightSelawik is a trademark of the Microsoft group of companies.Aaron Bellhttp://www.microsoft.com/typographyThis Font Software is licensed under the SIL Open Font License, Version 1.1.http://opensource.org/licenses/OFL-1.12  "@MPQ@ DFLTlatn 4AZE >CAT HCRT RKAZ \MOL fROM pTAT zTRK     markzmarkmarkmarkmarkmarkmarkmarkmarkmarkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmkmk $  Nv|jpd                     $ * 0 6 < B H N $ ZT f` fl r` fx ~ ~                         & ,   2 D 8 > D J > D P > D V > D \ > D 8 > D b > D 8 > D h > n t z >        "   (   .  : 4 F @ F L F R F X F ^ d p j p v p | p p       $  * < 0 6 < 0 6 < 0 6 B H N B H T B H Z B H ` B H f B H l B H r B H x B H N ~ < 0 < < <          , & 2 8 > D  J  P J  V J  \ J  b J  J  h J  J  n J z t   < 0 2     ( " ( . ( 4 ( : ( @ L F X R X ^ X d X j X p | v | | |  4*z]>akRw hA Y; Y<<YOY@ Y Y2~Y Taa~]]77JwwwT'Y   , lY66'OO0|*YOYO YC-JthtY8O0Y0922HYHQKK  \ X JJLL#O`MM &\`$X..OO`44 \`eXc c^^=77UNN\SXNe s[d]yOAF~P\O T67\;X7\M\``@@ 4*@O0 > JPV\bhntz `flrx~z]>akR|Z_\@`YX@MPQ=?<CE @ABDFGHIJKMP @ABDFGHIKMP DFLTlatn 4AZE BCAT PCRT ^KAZ lMOL zROM TAT TRK    !"#$% &'aaltaaltaaltaaltaalt aaltaaltaalt$aalt,aalt4ccmp>>0!0 +Ic{h󐠂003p#!Pp0  *H 0w1 0 UUS10U Washington10URedmond10U Microsoft Corporation1!0UMicrosoft Time-Stamp PCA0 150320173202Z 160620173202Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1 0 U MOPR1'0%U nCipher DSE ESN:F528-3777-8A761%0#UMicrosoft Time-Stamp Service0"0  *H 0 y-#4B+1)*+-n_pS3tJl(* xn oV{qOӫ-cgd4 ㊮(R5http://www.microsoft.com/pki/certs/MicCodSigPCA_08-31-2010.crt0  *H w\ב=ͽ{مCs|6ǵ,^T:q@ q&^}l;ɪ_]*'~e T(8Z{V2˓ۯn]D԰N ']a( "pr#z,C3Roӈlޤ5Sew 5Y؆1},wrlMY&²W5|P+Y)8RE)N[_'Pm4 8W7(5:8j]"^{00 a3&10  *H 0_10 &,dcom10 &,d microsoft1-0+U$Microsoft Root Certificate Authority0 100831221932Z 200831222932Z0y1 0 UUS10U Washington10URedmond10U Microsoft Corporation1#0!UMicrosoft Code Signing PCA0"0  *H 0 rY\0d` BvSl>ok:t/2BN#r5W ʮ IhMKyKqG%ߝuϪsDׁ6\Eܯ=(hrsV5rv_wE8s[gRi/ t)v/T0Yҍb_F1P'@0r)("7N=2=͡8\NV(*2KOc-bE=F[&SzJF7<8w\V< _^0Z0U00UҴX7.3L 0 U0 +70# +71N&`;1o<-0 +7  SubCA0U#0`@V'%* SY0PUI0G0ECA?http://crl.microsoft.com/pki/crl/products/microsoftrootcert.crl0T+H0F0D+08http://www.microsoft.com/pki/certs/MicrosoftRootCert.crt0  *H Y9>&Fo@2j/nI_uL;-C -1#|P!]=/LVpyIr>A i˥ - PV-JҼp VชKWB4 # # This file is part of kiwix-desktop. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . from pathlib import Path import xml.etree.ElementTree as ET import xml.etree script_path = Path(__file__) out_qrc_file = script_path.parent / "translations.qrc" translation_dir = script_path.parent / "i18n" root = ET.Element("RCC") root.text = "\n " qresource = ET.SubElement(root, "qresource") qresource.set("prefix", "/") qresource.text = "\n" + " " * 8 qresource.tail = "\n" json_files = translation_dir.glob("*.json") node = None for json in sorted(translation_dir.glob("*.json")): if node is not None: node.tail += " " * 8 node = ET.SubElement(qresource, "file") node.text = str(json.relative_to(script_path.parent)) node.tail = "\n" node.tail += " "*4 out_qrc_file.write_bytes(ET.tostring(root, encoding='utf8')) kiwix-desktop-2.4.1/resources/i18n/000077500000000000000000000000001473106011000171025ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/i18n/ar.json000066400000000000000000000162321473106011000204030ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Hanzo64", "LaMagiaaa", "McDutchie", "Meno25", "Mohammed Qays", "Ravan", "Tala Ali", "بهتين شوكت", "علاء", "محمد أحمد عبد الفتاح" ] }, "name": "العربية", "error-title": "خطأ", "error-downloader-window-title": "لا يمكن إنشاء برنامج التنزيل", "error-downloader-launch-message": "من المستحيل تشغيل برنامج التنزيل، سيبدأ تطبيق Kiwix-desktop لكن جميع وظائف التنزيل لن تعمل!", "error-launch-server-message": "حدث خطأ.", "error-archive": "لا يمكن الحصول على الأرشيف", "open-zim": "افتح ملف ZIM", "local-kiwix-server": "خادم Kiwix المحلي", "random-article": "مقالة عشوائية", "random-article-error": "فشل في فتح مقال عشوائي.", "home-page": "الصفحة الرئيسية", "main-menu": "القائمة الرئيسة", "print": "اطبع", "print-page-error": "حدث خطأ أثناء الطباعة.", "new-tab": "تبويب جديد", "close-tab": "إغلاق علامة التبويب", "close": "إغلاق", "reopen-closed-tab": "أعد فتح علامة التبويب المغلقة", "browse-library": "تصفح المكتبة", "open-file": "افتح ملفًا", "open-recent": "فتح الأحدث", "search-article": "البحث في المقالة", "search-in-library": "ابحث في المكتبة", "find-in-page": "البحث في الصفحة", "set-fullscreen": "ضبط ملء الشاشة", "quit-fullscreen": "غادر وضع الشاشة الكاملة", "table-of-content": "قائمة المحتويات", "reading-list": "قائمة القراءة", "zoom-in": "تكبير", "zoom-out": "تصغير", "zoom-reset": "إعادة تعيين التكبير", "help": "المساعدة", "feedback": "تعليقات", "report-a-bug": "الإبلاغ عن خطأ", "request-a-feature": "اطلب ميزة", "about-kiwix": "حول Kiwix", "donate-to-support-kiwix": "تبرع لدعم Kiwix", "exit": "مغادرة", "save-file-as-window-title": "حفظ الملف باسم", "download-finished-message": "تم تنزيل المستند.", "file": "الملف", "edit": "تعديل", "view": "عرض", "tools": "الأدوات", "window-title": "مكتبة - كيويكس", "search": "بحث", "browse-directory": "تصفح الدليل", "settings": "الإعدادات", "back": "رجوع", "forward": "إعادة توجيه", "search-files": "البحث في الملفات", "title": "العنوان", "size": "الحجم", "date": "التاريخ", "content-type": "نوع المحتوى", "reset-sort": "إعادة الترتيب", "open": "فتح", "delete": "حذف", "download": "تنزيل", "resume": "استئناف", "pause": "إيقاف مؤقت", "cancel": "إلغاء", "apply": "تطبيق", "port-for-local-kiwix-server-setting": "منفذ لخادم كيويكس المحلي", "zoom-level-setting": "مستوى التكبير الافتراضي", "download-directory-setting": "دليل التنزيل", "monitor-directory-setting": "دليل المراقبة", "reset": "إعادة الضبط", "clear": "مسح", "browse": "تصفح", "about-kiwix-desktop-title": "سطح المكتب كيويكس", "about-kiwix-desktop-description": "يتيح لك تطبيق Kiwix الوصول إلى كل ما يتعلق بموسوعة ويكيبيديا أينما ذهبت! سواء كنت على متن قارب أو في مكان ناءٍ أو في سجن، يتيح لك تطبيق Kiwix الوصول إلى كل المعارف البشرية. لست بحاجة إلى الإنترنت، فكل شيء مخزن على جهاز الكمبيوتر الخاص بك.", "about-learn-more-about-kiwix": "تعرف على المزيد عن كيويكس", "about-release-title": "الإصدار", "about-source-code": "تم إصدار هذا البرنامج بموجب شروط GNU General Public License الإصدار 3. اعرض الكود المصدري على Github .", "about-version": "الإصدار: {{VERSION}}", "about-reporting-problem-title": "الإبلاغ عن المشاكل", "about-report-issue": "لفتح مشكلة، قم بزيارة برنامج تعقب مشاكل سطح المكتب من Kiwix وافتح مشكلة تصف مشكلتك.", "about-report-issue-2": "يرجى ذكر الإصدار في العدد.", "about-libraries-title": "مكتبات", "kiwix-server-running-message": "خادم كيويكس قيد التشغيل ويمكن الوصول إليه من الشبكة المحلية على:", "kiwix-server-description": "يسمح بدء تشغيل الخادم لأجهزة الكمبيوتر الأخرى في الشبكة المحلية بالوصول إلى مكتبة كيويكس الخاصة بك باستخدام مستعرض ويب قياسي.", "fullscreen-notification": "أنت الآن في وضع ملء الشاشة. اضغط على ESC للإنهاء!", "local-files": "ملفات محلية", "hide": "إخفاء", "open-in-browser": "افتح في المتصفح", "start-kiwix-server": "ابدأ تشغيل خادم كيويكس", "stop-kiwix-server": "أوقف خادم كيويكس", "all": "الكل", "fulltext-search": "بحث في النص الكامل", "pictures": "الصور", "videos": "مقاطع فيديو", "ftindex": "فهرس النص الكامل", "details": "المقالة كاملة", "yes": "نعم", "no": "لا", "no-filter": "لا يوجد مرشح", "open-link-in-web-browser": "فتح الوصلة في متصفح الويب", "download-dir-dialog-title": "هل أنت متأكد أنك تريد تغيير دليل التنزيل؟", "download-dir-dialog-msg": "سيكون مسار دليل التنزيل الجديد: {{DIRECTORY}}", "invalid-port": "نموذج غير صالح.", "zim-open-fail-title": "مرشح غير صحيح", "zim-open-fail-text": "لا يمكن فتح ملف ZIM {{ZIM}} بشكل صحيح. ستتم إزالته من مكتبتك.", "monitor-dir-dialog-title": "هل أنت متأكد أنك تريد تغيير دليل الشاشة؟", "monitor-dir-dialog-msg": "سيكون مسار دليل الشاشة الجديد هو:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "هل أنت متأكد أنك تريد مسح دليل الشاشة؟", "monitor-clear-dir-dialog-msg": "سيؤدي هذا إلى إيقاف فحص دليل الشاشة لملفات ZIM الجديدة.", "monitor-directory-tooltip": "ستتم إضافة جميع ملفات ZIM الموجودة في هذا الدليل تلقائيًا إلى المكتبة.", "next-tab": "انتقل إلى علامة التبويب التالية", "previous-tab": "انتقل إلى علامة التبويب السابقة", "cancel-download": "إلغاء التنزيل", "file-not-found-title": "لم يبقي إيجاد ملف زيم", "file-not-found-text": "ملف زيم مش موجود أو مش قابل للقراءة", "zim-id": "معرف زيم", "zim-name": "اسم زيم", "zim-path": "مسار ملف زيم", "stop": "إيقاف", "voice": "صوت" } kiwix-desktop-2.4.1/resources/i18n/bcl.json000066400000000000000000000040731473106011000205410ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Kunokuno" ] }, "name": "Ingles", "error-title": "Sala", "error-downloader-window-title": "Dai makagibo nin downloader", "error-downloader-launch-message": "Imposible an paglansar kan downloader, mapuon an Kiwix-desktop alagad gabos na download functions dai magana!", "error-launch-server-message": "Igwa nin sala na nangyari!", "error-archive": "Dai makua an archive", "open-zim": "Bukaan an ZIM File", "local-kiwix-server": "Lokal na Kiwix Server", "random-article": "Dawa arin na Artikulo", "random-article-error": "Dai mabukaan an dawa arin na artikulo.", "home-page": "Harong na pahina", "main-menu": "Mayor na pilian", "print": "Iprint", "print-page-error": "Igwa nin salang nangyari mantang nagpiprint.", "new-tab": "Bagong tab", "close-tab": "Saradong tab", "close": "Sarado", "reopen-closed-tab": "Bukaan an nakasaradong tab", "browse-library": "Maghanap sa library", "open-file": "Bukaan an file", "open-recent": "Bukaan an pinakabago", "search-article": "Maghanap nin artikulo", "search-in-library": "Maghanap sa library", "find-in-page": "Maghanap sa pahina", "set-fullscreen": "Gibuhon na fullscreen", "quit-fullscreen": "Maghali sa fullScreen", "table-of-content": "Lista kan mga laog", "reading-list": "Lista kan mga babasahon", "zoom-in": "Padakulaon", "zoom-out": "Pasaditon", "zoom-reset": "Utruhon an pagpadakula", "help": "Tabang", "feedback": "Tuyaw", "report-a-bug": "Magreport nin bug", "request-a-feature": "Maghagad nin kakayahan", "about-kiwix": "Manungod sa Kiwix", "donate-to-support-kiwix": "Magdonar tangani na masuportahan na Kiwix", "exit": "Maghali", "save-file-as-window-title": "I-save an File bilang", "download-finished-message": "Nadownload na an dokumento.", "file": "Dokumento", "edit": "Baguhon", "view": "Hilingon", "tools": "Mga gamit", "window-title": "Library - Kiwix", "search": "Hanapon", "browse-directory": "Maghanap sa Directory", "settings": "Mga Kagustuhan", "back": "Magbalik", "forward": "Magpadagos", "search-files": "Hanapon an mga file", "title": "Titulo" } kiwix-desktop-2.4.1/resources/i18n/bn.json000066400000000000000000000046751473106011000204100ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "San1joy23", "Sibabrata Banerjee", "আজিজ", "আফতাবুজ্জামান" ] }, "name": "বাংলা", "print": "মুদ্রিত করুন", "new-tab": "নতুন ট্যাব", "close-tab": "ট্যাব বন্ধ করুন", "search-article": "নিবন্ধ অনুসন্ধান করুন", "help": "সাহায্য", "feedback": "প্রতিক্রিয়া", "exit": "প্রস্থান", "view": "দেখুন", "tools": "সরঞ্জাম", "search": "অনুসন্ধান", "back": "পিছন", "forward": "সামনে", "title": "শিরোনাম", "size": "আকার", "date": "তারিখ", "about-kiwix-desktop-title": "কিউইক্স ডেস্কটপ", "about-release-title": "মুক্তি", "about-version": "সংস্করণ: {{VERSION}}", "about-report-issue-2": "দয়া করে সমস্যাটিতে সংস্করণের নামটি লিখুন।", "all": "সব", "fulltext-search": "পূর্ণপাঠ অনুসন্ধান", "yes": "হ্যাঁ", "no": "না", "ok": "ঠিক আছে", "open-link-in-web-browser": "ওয়েব ব্রাউজারে সংযোগ খুলুন", "invalid-port": "পাতা অবৈধ", "next-tab": "পরবর্তী ট্যাবে যান", "previous-tab": "পূর্ববর্তী ট্যাবে যান", "disable-sandbox": "কিউইক্স একটি নেটওয়ার্ক ড্রাইভ থেকে চালু করা হয়েছে। এটি ব্রাউজিং স্যান্ডবক্সিং-এর সাথে সামঞ্জস্যপূর্ণ সমস্যার কারণ হিসেবে পরিচিত। ফলস্বরূপ, স্যান্ডবক্স অক্ষম করা হবে। আপনি কি চালিয়ে যেতে চান?", "portable-disabled-tooltip": "পোর্টেবল মোডে ফাংশন নিষ্ক্রিয় করা হয়েছে", "scroll-next-tab": "পরবর্তী ট্যাবে স্ক্রোল করুন", "scroll-previous-tab": "পূর্ববর্তী ট্যাবে স্ক্রোল করুন" } kiwix-desktop-2.4.1/resources/i18n/br.json000066400000000000000000000100261473106011000203770ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Adriendelucca", "Fulup" ] }, "name": "Brezhoneg", "error-title": "Fazi", "error-launch-server-message": "C'hoarvezet ez eus ur fazi!", "error-archive": "N’haller ket kaout an diell", "open-zim": "Digeriñ ar restr Zim", "local-kiwix-server": "Servijer Kiwix lec’hel", "random-article": "Pennad dre zegouezh", "home-page": "Pajenn degemer", "main-menu": "Lañser pennañ", "print": "Moullañ", "print-page-error": "Ur fazi zo bet en ur voullañ.", "new-tab": "Ivinell nevez", "close-tab": "Serriñ an ivinell", "close": "Serriñ", "reopen-closed-tab": "Addigeriñ ar steudenn bet serret", "browse-library": "Ergerzhout al levraoueg", "open-file": "Digeriñ ar restr", "open-recent": "Digeriñ ar re nevez", "search-article": "Klask ur pennad", "search-in-library": "Klask el levraoueg", "find-in-page": "Klask er bajenn", "set-fullscreen": "Mod skramm a-bezh", "quit-fullscreen": "Kuitaat ar skramm leun", "reading-list": "Roll lenn", "zoom-in": "Zoumañ", "zoom-out": "Dizoumañ", "zoom-reset": "Adderaouekaat ar zoum", "help": "Skoazell", "feedback": "Sonjoù", "report-a-bug": "Disklêriañ un draen", "about-kiwix": "Diwar-benn Kiwix", "donate-to-support-kiwix": "Reiñ un donezon evit skoazellañ Kiwix", "exit": "Kuitaat", "save-file-as-window-title": "Enrollañ ar restr evel", "download-finished-message": "Pellgarget eo bet an teul.", "file": "Restr", "edit": "Kemmañ", "view": "Gwelet", "tools": "Ostilhoù", "window-title": "Levraoueg - Kiwix", "search": "Klask", "settings": "Arventennoù", "back": "Distreiñ", "forward": "Da-heul", "search-files": "Klask restroù", "title": "Titl", "size": "Ment", "date": "Deiziad", "open": "Digeriñ", "delete": "Dilemel", "download": "Pellgargañ", "resume": "Adstagañ ganti", "pause": "Ehanañ", "cancel": "Nullañ", "apply": "Lakaat da dalvezout", "port-for-local-kiwix-server-setting": "Porzh evit ar servijer Kiwix lec’hel", "zoom-level-setting": "Live zoum dre ziouer", "clear": "Riñsañ", "browse": "Furchal", "about-kiwix-desktop-title": "Kiwix Desktop", "about-learn-more-about-kiwix": "Gouzout hiroc’h diwar-benn Kiwix", "about-version": "Handelv: {{VERSION}}", "about-reporting-problem-title": "Menegiñ ur gudenn", "about-report-issue-2": "Menegit ar stumm Kiwix en ho tanevell mar plij.", "about-libraries-title": "Levraouegoù", "online-files": "Restroù enlinenn", "local-files": "Restroù lec’hel", "category": "Rummad", "language": "Yezh", "hide": "Kuzhat", "open-in-browser": "Digeriñ er merdeer", "start-kiwix-server": "Loc’hañ ar servijer Kiwix", "stop-kiwix-server": "Ehanañ ar servijer Kiwix", "all": "An holl", "fulltext-search": "Klask en destenn glok", "pictures": "Skeudennoù", "videos": "Videoioù", "details": "Pennad a-bezh", "yes": "ya", "no": "ket", "ok": "mat eo", "no-filter": "sil ebet", "open-link-in-web-browser": "Digeriñ al liamm er merdeer", "invalid-port": "Porzh direizh", "zim-open-fail-title": "Restr direizh", "next-tab": "Mont d'ar steudenn da-heul", "previous-tab": "Mont d'ar steudenn gent", "cancel-download": "Nullañ ar pellgargañ", "cancel-download-text": "Sur oc’h e faot deoc’h nullañ pellgargañ ar restr {{ZIM}}?", "delete-book": "Dilemel al levr", "delete-book-text": "Sur oc’h e faot deoc’h dilemel {{ZIM}}?", "open-book": "Digeriñ al levr", "download-book": "Pellgargañ al levr", "pause-download": "Ehanañ ar pellgargañ", "resume-download": "Kenderc’hel da bellgargañ", "open-folder": "Digeriñ ar restr", "couldnt-open-location": "N’haller ket digeriñ al lec’hiadur", "couldnt-open-location-text": "Kiwix n’eo ket gouest da zigeriñ ar restr {{FOLDER}}", "move-files-to-trash-text": "Kement-se a lakay ar restr e-barzh ar pod-lastez.", "perma-delete-files-text": "Kement-se a zilamo ar restr da viken.", "language-searcher-placeholder": "Silañ dre yezh", "category-searcher-placeholder": "Silañ dre rummad", "no-details": "Digoradur hepken", "no-pictures": "Skeudenn ebet", "no-videos": "Video ebet" } kiwix-desktop-2.4.1/resources/i18n/ca.json000066400000000000000000000021601473106011000203570ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Alan Mena", "Fitoschido", "Mguix" ] }, "name": "Català", "main-menu": "Menú principal", "print": "Imprimeix", "new-tab": "Pestanya nova", "close-tab": "Tanca la pestanya", "open-recent": "Obre els recents", "find-in-page": "Cerca a la pàgina", "reading-list": "Llista de lectura", "zoom-in": "Apropa’t", "zoom-out": "Allunya’t", "help": "Ajuda", "report-a-bug": "Informa d’un error", "about-kiwix": "Quant al Kiwix", "exit": "Surt", "file": "Fitxer", "edit": "Edita", "view": "Visualitza", "tools": "Eines", "search": "Cerca", "settings": "Configuració", "back": "Enrere", "title": "Títol", "size": "Mida", "date": "Data", "content-type": "Tipus de contingut", "open": "Obre", "delete": "Suprimeix", "download": "Baixa", "resume": "Reprèn", "pause": "Pausa", "cancel": "Cancel·la", "apply": "Aplica", "download-directory-setting": "Directori de baixades:", "reset": "Reinicialitza", "browse": "Explora", "about-libraries-title": "Biblioteques", "local-files": "Fitxers locals", "hide": "Amaga", "all": "Tot", "yes": "sí", "no": "no" } kiwix-desktop-2.4.1/resources/i18n/cs.json000066400000000000000000000123431473106011000204050ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Klaras", "Spotter" ] }, "name": "Čeština", "error-title": "Chyba", "error-downloader-window-title": "Nelze vytvořit stahovač", "error-downloader-launch-message": "Stahovač nelze spustit, Kiwix se spustí, ale všechny funkce stahování budou přerušeny.", "error-launch-server-message": "Došlo k chybě!", "error-archive": "Archiv nelze získat", "open-zim": "Otevřít Zim", "local-kiwix-server": "Lokální Kiwix server", "random-article": "Náhodný článek", "random-article-error": "Nepodařilo se otevřít náhodný článek.", "home-page": "Domovská stránka", "main-menu": "Hlavní menu", "print": "Vytisknout", "print-page-error": "Při tisku došlo k chybě.", "new-tab": "Nová karta", "close-tab": "Zavřít kartu", "close": "Zavřít", "reopen-closed-tab": "Znovu otevřít zavřenou kartu", "browse-library": "Procházet knihovnu", "open-file": "Otevři soubor", "open-recent": "Otevřít nedávný", "search-article": "Hledat článek", "search-in-library": "Hledat v knihovně", "find-in-page": "Najít na stránce", "set-fullscreen": "Nastavit režim celé obrazovky", "quit-fullscreen": "Ukončit režim celé obrazovky", "table-of-content": "Obsah", "reading-list": "Seznam k přečtení", "zoom-in": "Přiblížit", "zoom-out": "Oddálit", "zoom-reset": "Resetovat přiblížení", "help": "Nápověda", "feedback": "Zpětná vazba", "report-a-bug": "Nahlásit chybu", "request-a-feature": "Požádat o novou funkci", "about-kiwix": "O Kiwix", "donate-to-support-kiwix": "Darováním podpořte Kiwix", "exit": "Opustit", "save-file-as-window-title": "Uložit soubor jako", "download-finished-message": "Dokument byl stažen.", "file": "Soubor", "edit": "Upravit", "view": "Zobrazit", "tools": "Nástroje", "window-title": "Knihovna - Kiwix", "search": "Hledat", "browse-directory": "Procházet složku", "settings": "Nastavení", "back": "Zpět", "forward": "Vpřed", "search-files": "Hledat soubory", "title": "Název", "size": "Velikost", "date": "Datum", "content-type": "Typ obsahu", "reset-sort": "Resetovat řazení", "open": "Otevřít", "delete": "Smazat", "download": "Stáhnout", "resume": "Obnovit", "pause": "Pozastavit", "cancel": "Zrušit", "apply": "Použít", "port-for-local-kiwix-server-setting": "Port pro místní server Kiwix", "zoom-level-setting": "Výchozí stupeň přiblížení", "download-directory-setting": "Složka stahování", "monitor-directory-setting": "Sledování adresáře", "reset": "Resetovat", "clear": "Vymazat", "browse": "Procházet", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix vám umožňuje mít po ruce celou Wikipedii, ať už jste kdekoli! Na lodi, uprostřed ničeho nebo ve vězení, Kiwix vám poskytuje přístup k celému lidskému poznání. Nepotřebujete internet, vše je uloženo v počítači.", "about-learn-more-about-kiwix": "Dozvědět se více o Kiwix", "about-release-title": "Vydání", "about-source-code": "Tento software je vydáván za podmínek GNU General Public License verze 3. Zdrojový kód naleznete na webu Github.", "about-version": "Verze: {{VERSION}}", "about-reporting-problem-title": "Hlášení problému", "about-report-issue": "Chcete-li problém otevřít, navštivte nástroj pro sledování problémů Kiwix-desktop a otevřete issue popisující váš problém.", "about-report-issue-2": "Uveďte verzi v issue.", "about-libraries-title": "Knihovny", "kiwix-server-running-message": "Server Kiwix je spuštěn a lze k němu přistupovat v místní síti na:", "kiwix-server-description": "Spuštění serveru umožňuje ostatním počítačům v místní síti přistupovat ke knihovně Kiwix pomocí standardního webového prohlížeče.", "fullscreen-notification": "Jste v režimu celé obrazovky. Pro ukončení stiskněte klávesu ESC!", "local-files": "Lokální soubory", "hide": "Skrýt", "open-in-browser": "Otevřít v prohlížeči", "start-kiwix-server": "Spustit Kiwix server", "stop-kiwix-server": "Zastavit Kiwix server", "all": "Vše", "fulltext-search": "Fulltextové vyhledávání", "pictures": "Obrázky", "videos": "Videa", "ftindex": "Fulltextový index", "details": "Celý článek", "yes": "ano", "no": "ne", "no-filter": "žádný filtr", "open-link-in-web-browser": "Otevřít odkaz ve webovém prohlížeči", "download-dir-dialog-title": "Opravdu chcete změnit složku pro stahování?", "download-dir-dialog-msg": "Nová cesta ke složce pro stahování bude:\n{{DIRECTORY}}", "invalid-port": "Neplatný port", "zim-open-fail-title": "Neplatný soubor", "zim-open-fail-text": "Soubor ZIM {{ZIM}} nelze správně otevřít. Bude z vaší knihovny odstraněn.", "monitor-dir-dialog-title": "Opravdu chcete změnit adresář monitorování?", "monitor-dir-dialog-msg": "Nová cesta k adresáři monitoru bude:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Opravdu chcete vymazat adresář monitorování?", "monitor-clear-dir-dialog-msg": "Tím se zastaví kontrola adresáře monitoru na nové soubory ZIM.", "monitor-directory-tooltip": "Všechny soubory ZIM v tomto adresáři budou automaticky přidány do knihovny." } kiwix-desktop-2.4.1/resources/i18n/da.json000066400000000000000000000041731473106011000203660ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "Saederup92", "Zakawer2" ] }, "name": "Dansk", "error-title": "Fejl", "error-launch-server-message": "Der opstod en fejl!", "error-archive": "Kan ikke hente arkivet", "open-zim": "Åbn ZIM-fil", "local-kiwix-server": "Lokal Kiwix-server", "random-article": "Tilfældig artikel", "main-menu": "Hovedmenu", "print": "Udskriv", "print-page-error": "Der opstod en fejl under udskrivningen.", "new-tab": "Ny fane", "close-tab": "Luk fane", "close": "Luk", "reopen-closed-tab": "Genåbn lukket fane", "browse-library": "Gennemse biblioteket", "open-file": "Åbn fil", "search-article": "Søg i artiklen", "search-in-library": "Søg i biblioteket", "find-in-page": "Find på siden", "table-of-content": "Indholdsfortegnelse", "reading-list": "Læseliste", "zoom-in": "Zoom ind", "zoom-out": "Zoom ud", "help": "Hjælp", "about-kiwix": "Om Kiwix", "exit": "Afslut", "save-file-as-window-title": "Gem fil som", "file": "Fil", "edit": "Redigér", "tools": "Værktøjer", "window-title": "Bibliotek - Kiwix", "search": "Søg", "settings": "Indstillinger", "back": "Tilbage", "title": "Titel", "size": "Størrelse", "date": "Dato", "content-type": "Indholdstype", "open": "Åbn", "delete": "Slet", "resume": "Fortsæt", "pause": "Sæt på pause", "reset": "Nulstil", "clear": "Ryd", "browse": "Gennemse", "about-learn-more-about-kiwix": "Lær mere om Kiwix", "about-version": "Version: {{VERSION}}", "about-libraries-title": "Biblioteker", "local-files": "Lokale filer", "hide": "Skjul", "open-in-browser": "Åbn i browser", "start-kiwix-server": "Start Kiwix-server", "stop-kiwix-server": "Stop Kiwix-server", "all": "Alle", "pictures": "Billeder", "videos": "Videoer", "details": "Fuld artikel", "yes": "ja", "no": "nej", "no-filter": "intet filter", "invalid-port": "Ugyldig port", "zim-open-fail-title": "Ugyldig fil", "zim-open-fail-text": "ZIM-filen {{ZIM}} kunne ikke åbnes korrekt. Den vil blive slettet fra dit bibliotek.", "next-tab": "Flyt til næste fane", "previous-tab": "Flyt til forrige fane", "cancel-download": "Annuller download" } kiwix-desktop-2.4.1/resources/i18n/dag.json000066400000000000000000000134211473106011000205310ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Dnshitobu", "Kalakpagh", "Munkaila Sulemana", "Peggy" ] }, "name": "Silimiinsili", "error-title": "Chirimbu", "error-downloader-window-title": "Di ku tooi nam deera", "error-downloader-launch-message": "Haiwezekani kuzindua upakuaji, Kiwix-desktop itaanza lakini kazi zote za upakuaji hazitafanya\n kufanya kazi", "error-launch-server-message": "Chiriŋ nyɛla din niŋ!", "error-archive": "Ku tooi nya polo deei niŋ shee ŋɔ", "open-zim": "Yoomi ZIM Fasara", "local-kiwix-server": "Tiŋbia Kiwix tum tumda", "random-article": "Gahim piigi lahabali", "random-article-error": "Zaɣisiya ni di yoogi gahim piigi lahabali.", "home-page": "Solɔɣu", "main-menu": "Piligu shee", "print": "Paɣibu", "print-page-error": "Chiriŋ daa nyɛla din niŋ yaabu maa shɛɛ.", "new-tab": "tab palli", "close-tab": "kparimi a tab", "close": "Kparima", "reopen-closed-tab": "labiyooi tapi shɛli din kpari ma", "open-file": "Yoomi Faali", "open-recent": "Yoomi din na yoli niŋ", "search-article": "Vihimi lahabali", "search-in-library": "Vihimi kpanjɔɣu ni", "find-in-page": "Bɔmili yaɣili maa ni", "set-fullscreen": "Niŋmi diɣi'zaa", "quit-fullscreen": "Yihimi diɣi'zaa", "table-of-content": "Din be yaɣili ŋɔ ni", "reading-list": "Binkarinda", "zoom-in": "Muɣilim li", "zoom-out": "Yɛliɣim li", "zoom-reset": "Zoom labi'niŋ", "help": "Sɔŋsim", "feedback": "Labisigu", "request-a-feature": "Suhi m-bo nahingbaŋ", "about-kiwix": "Kiwix Lahabali", "donate-to-support-kiwix": "Mali mi Kiwix sara", "exit": "Yima", "save-file-as-window-title": "Zaŋmi faali maa ni kpanjɔɣu ni kamani", "download-finished-message": "Kundi maa nyɛla din luna.", "file": "Lahabali kɔligu", "edit": "Maliniŋ", "view": "Lihima", "tools": "Mazagaya", "window-title": "Karimbu shee - Kiwix", "search": "Vihima", "settings": "Bintaɣindisi", "back": "Nyaaŋa", "forward": "Tooni", "search-files": "Vihimi Lahabali kɔlisi", "title": "Lahabali zuɣu", "size": "Galisim", "date": "Dali", "content-type": "Lahabali balli", "reset-sort": "labi'niŋ tabo", "open": "Yooi", "delete": "Yihima", "download": "Deei", "resume": "Tuɣi", "pause": "Zanibu", "cancel": "Kpihim", "apply": "Niŋ", "port-for-local-kiwix-server-setting": "Yaɣili zaŋ n-ti Kiwix tiŋbia tum tumda", "zoom-level-setting": "Chiriŋ zoom fahirili", "download-directory-setting": "Deebu wuhibu", "monitor-directory-setting": "Lihigu wuhibu", "reset": "Labi'bari", "clear": "Neei", "browse": "Browsɛ", "about-learn-more-about-kiwix": "Bɔhimmi pam zaŋ jɛndi Kiwix", "about-release-title": "Gaai", "about-source-code": "\"Software\" ŋɔ nyɛla bɛ ni daa bahi shɛli tam GNU zalikpana zuɣu 3. Lihimi Kundivihira jia ŋɔ Github.", "about-reporting-problem-title": "Yɛlli zaŋ wuhi salo", "about-report-issue-2": "Pahimi suɣilo bolimi yaɣa shɛli yɛlli'gola ŋɔ ni be", "about-libraries-title": "Karimbu shɛhi", "fullscreen-notification": "A pa be la diɣi yɛlinli zaa ni saha ŋɔ. Dihimi ESC yi!", "online-files": "Pohim zuɣu Lahabali kɔlisi", "local-files": "Dundɔŋ ni Lahabali kɔlisi", "category": "Pubu", "language": "Balli", "hide": "Sɔɣi", "open-in-browser": "Yooi browzɛr ni", "start-kiwix-server": "Piligi Kiwix tum tumda", "stop-kiwix-server": "Taɣimi Kiwix tum tumda", "all": "Zaa", "fulltext-search": "Lahabali pali vihibu", "pictures": "Anfooninima", "videos": "Siniinima", "details": "Lahabali pali", "yes": "iin", "no": "aayi", "ok": "tɔr", "no-filter": "Lɔŋ kani", "download-dir-dialog-title": "A niŋ dihitabili ni a borimi ni a taɣi deebu wuhibu?", "download-dir-dialog-msg": "Deebu wuhibu palli soli yɛn nyɛla :\n{{DIRECTORY}}", "zim-open-fail-title": "Bara fasara", "zim-open-fail-text": "ZIM fasara ŋɔ {{ZIM}} ku tooi yoogi viɛnyɛla. Bɛ ni yihi li a karimbu shee.", "monitor-dir-dialog-title": "A niŋ dihitabili ni a borimi ni a taɣi lihigu wuhibu?", "monitor-dir-dialog-msg": "Lihigu wuhibu palli ŋɔ soli yɛn nyɛla :\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "A niŋ dihitabili ni a borimi ni a neei lihigu wuhibu ŋɔ?", "monitor-clear-dir-dialog-msg": "Din bɔŋɔ nyɛla din yɛn taɣi ka chɛ lihigu wuhibu kaabu zaŋ n-ti ZIM fasara palli.", "monitor-directory-tooltip": "ZIM fasara nima zaa din be wuhibu ŋɔ ni nyɛla din daa pahi karimbu shee.", "next-tab": "Vuui chaŋ binshɛɣ'kam din paya ni.", "previous-tab": " Vuui chaŋ binshɛɣ'kam kurili", "cancel-download": "Kpihimi deebu", "cancel-download-text": "A niŋ dihitabili ni a borimi ni a kpihim deebu zaŋ n-ti {{ZIM}}?", "delete-book": "Yihimi buku", "delete-book-text": "A niŋ dihitabili ni a borimi ni a yihi {{ZIM}}?", "download-storage-error": "Deei niŋ shee Chiriŋ", "download-unavailable": "Deebu kani", "download-unavailable-text": "Din bɔŋɔ deebu nyɛla din kani", "open-book": "Yoomi buku", "download-book": "Deemi buku", "pause-download": "Cheli deebu", "resume-download": "Tuɣimi deebu", "open-folder": "Yoomi gbaŋ", "couldnt-open-location": "Bi tooi yoogi dooshee", "couldnt-open-location-text": "Kiwix bi tooi yoogi gbaŋ {{FOLDER}}", "move-files-to-trash": "Daami Lahabali kɔlisi shɛŋa a ni nyahi n zaŋ chaŋ saɣari guŋgɔŋ ni", "move-files-to-trash-text": "Niŋsim ŋɔ nyɛla bin shɛli din ni tooi zaŋ lahabali kɔligu n chaŋ saɣari guŋgɔŋ ni.", "perma-delete-files-text": "Niŋsim ŋɔ nyɛla bin shɛli din ni tooi nyahi lahabali kɔligu kuli mali wara.", "clear-filter": "Neemi saha ŋɔ lɔŋsi", "language-searcher-placeholder": "Lɔŋ balli", "category-searcher-placeholder": "Lɔŋ pubu", "content-type-searcher-placeholder": "Lɔŋ lahabali ballibu", "no-details": "Piligu koŋko", "no-pictures": "Anfooni nima kani", "no-videos": "Sinii nima kani" } kiwix-desktop-2.4.1/resources/i18n/de.json000066400000000000000000000166121473106011000203730ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Brettchenweber", "DraconicDark", "Falwye", "IMayBeABitShy", "Justman10000", "Magiczocker", "Rofiatmustapha12", "Susann Schweden", "ThisCarthing", "Umlaut", "Wolfdietmann" ] }, "name": "Deutsch", "error-title": "Fehler", "error-downloader-window-title": "Erstellen vom Downloader nicht möglich", "error-downloader-launch-message": "Der Downloader konnte nicht gestartet werden, Kiwix-desktop wird gestartet, aber alle Funktionen zum Herunterladen werden nicht funktionieren!", "error-launch-server-message": "Es ist ein Fehler aufgetreten!", "error-archive": "Das Archiv konnte nicht geöffnet werden.", "open-zim": "Öffne ZIM-Datei", "local-kiwix-server": "Lokaler Kiwix-Server", "random-article": "Zufälliger Artikel", "random-article-error": "Ein zufälliger Artikel kann nicht geöffnet werden.", "home-page": "Startseite", "main-menu": "Hauptmenü", "print": "Drucken", "print-page-error": "Beim Drucken ist ein Fehler aufgetreten.", "new-tab": "Neue Registerkarte", "close-tab": "Registerkarte schließen", "close": "Schließen", "reopen-closed-tab": "Geschlossene Registerkarte wieder öffnen", "browse-library": "Bibliothek durchsuchen", "open-file": "Datei öffnen", "open-recent": "Öffne zuletzt Benutztes", "search-article": "Such Artikel", "search-in-library": "Such in der Bibliothek", "find-in-page": "In Seite suchen", "set-fullscreen": "Vollbild aktivieren", "quit-fullscreen": "Vollbild beenden", "table-of-content": "Inhaltsverzeichnis", "reading-list": "Leseliste", "zoom-in": "Vergrößern", "zoom-out": "Verkleinern", "zoom-reset": "Zoom zurücksetzen", "help": "Hilfe", "feedback": "Rückmeldung", "report-a-bug": "Einen Fehler melden", "request-a-feature": "Eine Funktion anfordern", "about-kiwix": "Über Kiwix", "donate-to-support-kiwix": "Spenden zur Unterstützung von Kiwix", "exit": "Beenden", "save-file-as-window-title": "Datei speichern als", "download-finished-message": "Das Dokument wurde heruntergeladen.", "file": "Datei", "edit": "Bearbeiten", "view": "Ansehen", "tools": "Werkzeuge", "window-title": "Bibliothek - Kiwix", "search": "Suchen", "browse-directory": "Verzeichnis durchsuchen", "settings": "Einstellungen", "back": "Zurück", "forward": "Vorwärts", "search-files": "Dateien durchsuchen", "title": "Titel", "size": "Größe", "date": "Datum", "content-type": "Inhaltstyp", "reset-sort": "Sortierung zurücksetzen", "open": "Öffnen", "delete": "Löschen", "download": "Herunterladen", "resume": "Fortfahren", "pause": "Pausieren", "cancel": "Abbrechen", "apply": "Anwenden", "port-for-local-kiwix-server-setting": "Port für den lokalen Kiwix-Server:", "zoom-level-setting": "Zoom-Einstellung", "download-directory-setting": "Verzeichnis für Downloads", "monitor-directory-setting": "Zu beobachtender Ordner", "reset": "Zurücksetzen", "clear": "Leeren", "browse": "Durchsuchen", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix ermöglicht es Ihnen, die gesamte Wikipedia immer und überall zur Hand zu haben! Auf einem Boot, mitten im Nirgendwo oder im Gefängnis, Kiwix ermöglicht Ihnen den Zugang zum gesamten menschlichen Wissen. Sie brauchen kein Internet, alles ist auf Ihrem Computer gespeichert.", "about-learn-more-about-kiwix": "Mehr über Kiwix erfahren", "about-release-title": "Veröffentlichung", "about-source-code": "Diese Software unterliegt einer Lizenz, der GNU General Public License Version 3. Anzeige des Quellcodes unter Github.", "about-version": "Version: {{VERSION}}", "about-reporting-problem-title": "Meldung von Problemen", "about-report-issue": "Um ein Problem zu melden, bitte Kiwix-Desktop Issue tracker aufrufen und dort ein Thema erstellen, das Ihr Problem beschreibt.", "about-report-issue-2": "Bitte im Thema die Version angeben.", "about-libraries-title": "Bibliotheken", "kiwix-server-running-message": "Der Kiwix-Server ist aktiv und ein Zugriff ist möglich im lokalen Netzwerk unter:", "kiwix-server-description": "Wenn ein Server gestartet wird, eröffnet das anderen Rechnern im lokalen Netzwerk die Möglichkeit, mit einem normalen Browser auf Ihre Kiwix-Bibliothek zuzugreifen.", "fullscreen-notification": "Sie sind im Vollbildmodus. Drücken Sie ESC, um ihn zu verlassen!", "online-files": "Online Dateien", "local-files": "Lokale Dateien", "category": "Kategorie", "language": "Sprache", "hide": "Verbergen", "open-in-browser": "Im Browser öffnen", "start-kiwix-server": "Kiwix-Server starten", "stop-kiwix-server": "Kiwix-Server stoppen", "all": "Alle", "fulltext-search": "Volltextsuche", "pictures": "Bilder", "videos": "Videos", "ftindex": "Volltextindex", "details": "Ganzer Artikel", "yes": "ja", "no": "nein", "ok": "Ok", "no-filter": "kein Filter", "open-link-in-web-browser": "Link im Browser öffnen", "download-dir-dialog-title": "Sind Sie sicher, dass Sie das Download-Verzeichnis wechseln möchten?", "download-dir-dialog-msg": "Der neue Download-Verzeichnis-Pfad ist:\n{{DIRECTORY}}", "invalid-port": "Ungültiger Port", "zim-open-fail-title": "Ungültige Datei", "zim-open-fail-text": "Die ZIM-Datei {{ZIM}} kann nicht ordnungsgemäß geöffnet werden. Sie wird aus Ihrer Bibliothek entfernt.", "monitor-dir-dialog-title": "Sind Sie sicher, dass Sie das zu beobachtende Verzeichnis ändern wollen?", "monitor-dir-dialog-msg": "Der Pfad des zu beobachtenden Ordners wird auf Folgendes geändert: {{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Sind Sie sicher, dass Sie den zu beobachtenden Ordner leeren wollen?", "monitor-clear-dir-dialog-msg": "Hierdurch wird der zu beobachtende Ordner nicht mehr nach neu hinzugekommenen ZIM-Dateien durchsucht.", "monitor-directory-tooltip": "Alle ZIM-Dateien in diesem Verzeichnis werden automatisch zur Bibliothek hinzugefügt.", "next-tab": "Zur nächsten Registerkarte wechseln", "previous-tab": "Zur vorherigen Registerkarte wechseln", "cancel-download": "Download abbrechen", "cancel-download-text": "Sind Sie sicher, dass Sie den Download von {{ZIM}} abbrechen wollen?", "delete-book": "Buch löschen", "delete-book-text": "Sind Sie sicher, dass Sie {{ZIM}} löschen wollen?", "download-storage-error": "Speicherfehler", "download-storage-error-text": "Das System hat nicht genug Speicherplatz zur Verfügung.", "download-unavailable": "Download nicht verfügbar", "download-unavailable-text": "Dieser Download ist nicht verfügbar.", "open-book": "Buch öffnen", "download-book": "Buch herunterladen", "pause-download": "Download pausieren", "resume-download": "Download fortsetzen", "open-folder": "Ordner öffnen", "couldnt-open-location": "Pfad konnte nicht geöffnet werden", "couldnt-open-location-text": "Es ist Kiwix nicht möglich, den Ordner {{FOLDER}} zu öffnen", "move-files-to-trash": "Gelöschte Dateien in den Papierkorb verschieben", "move-files-to-trash-text": "Durch diese Aktion wird die Datei in den Papierkorb verschoben.", "perma-delete-files-text": "Durch diese Aktion wird die Datei unwiderruflich gelöscht.", "clear-filter": "Aktuell eingestellte Filter Löschen", "language-searcher-placeholder": "Nach Sprache filtern", "category-searcher-placeholder": "Nach Kategorie filtern", "content-type-searcher-placeholder": "Nach Inhaltstyp filtern", "no-details": "Nur Einführung", "no-pictures": "Keine Bilder", "no-videos": "Keine Videos" } kiwix-desktop-2.4.1/resources/i18n/diq.json000066400000000000000000000105761473106011000205630ustar00rootroot00000000000000{ "@metadata": { "authors": [ "1917 Ekim Devrimi", "Mirzali", "Orbot707" ] }, "name": "Zazaki", "error-title": "Xeta", "error-downloader-window-title": "Ronayoğ nêvırazeno", "error-downloader-launch-message": "Kewtışê ronayoği mımkın niyo ke serê masaya Kiwixi bıguriyo, feqet karê ronayışi pêro nêguriyeno!", "error-launch-server-message": "Yew xeta biye!", "open-zim": "Zim'i akerê", "local-kiwix-server": "Mehali Serverê Kiwixi", "random-article": "Raştameye meqale", "home-page": "Pela Seri", "main-menu": "Menuyo esas", "print": "Çap ke", "new-tab": "Taba newiye", "close-tab": "Tab racıne", "close": "Kip ke", "reopen-closed-tab": "Racınayi tabi reyna akerê", "browse-library": "Çımberze kıtıbxane", "open-file": "Dosya ake", "open-recent": "Bahdoyên ake", "search-article": "Meqale cı geyre", "search-in-library": "Kıtıbxaney de cıgeyrayış", "find-in-page": "Pela vinayış", "set-fullscreen": "Tam ekran eyar kerê", "quit-fullscreen": "Tam ekran ra bıvıciyê", "table-of-content": "Tabloy zerreki", "reading-list": "Lista wanayışi", "zoom-in": "Nezdı fiyê", "zoom-out": "Duri fiyê", "zoom-reset": "Zoomi reset ke", "help": "Pheşti", "feedback": "Peyderıştış", "report-a-bug": "Xeta rapor ke", "request-a-feature": "Xısusiyetê bıwazê", "about-kiwix": "Heqa Kiwixi", "donate-to-support-kiwix": "Pheştiya Kiwixi bec bıdê", "exit": "Veciyayış", "save-file-as-window-title": "Ciya qeyd kereu", "download-finished-message": "Dokuman roniya", "file": "Dosya", "edit": "Bıvurnê", "view": "Bıvêne", "tools": "Haceti", "window-title": "Kıtıbxane - Kiwix", "search": "Cıgeyrayış", "browse-directory": "Çımberze Rêze", "settings": "Eyari", "back": "Peyser", "forward": "Şıkıtış", "search-files": "Dosya cıgeyrayış", "title": "Serey", "size": "Ebad", "date": "Tarix", "content-type": "Tewrê zerreki", "reset-sort": "Rêzer reset ke", "open": "Ake", "delete": "Bestere", "download": "Ronê", "resume": "Dewam kerê", "pause": "Bıvındarne", "cancel": "Bıtexelne", "apply": "Tetbiq bıkerê", "port-for-local-kiwix-server-setting": "Nuxta gıreyê ardoğê Kiwixiyo mehali", "zoom-level-setting": "Sewiyaya nêzdikerdışiya hesebiyayiye", "download-directory-setting": "Zerrekê ronayışi", "reset": "Reset kerê", "clear": "Pak ke", "browse": "Çımberze", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix şıma koti ke vanê se şırê wikipedia daba şıma desti bın! Yee kelek de, warte dê cayê de ya zi hebısxane de, Kiwik şıma rê resayışê insanan pêroyın kena. İhtiyacê şıma interneti ra zi çıniyo, pêro komputerê şıma de nımneyêno.", "about-learn-more-about-kiwix": "Heqa Kiwixi teyna melumat", "about-release-title": "Ramate", "about-source-code": "No software GNU şertanê Umumiyê Lisansê Şari 3ın bın de neşr biyo. Kodê çımey Github sero bımusê.", "about-version": "Versiyon: {{VERSION}}", "about-reporting-problem-title": "Xırabey rapor kerê", "about-report-issue": "Yew mewzu akerdışi rê Kiwix Desktopi Seyriyan mewzu ziyaret kerê u persê ho izah kerdê yew mewzu akerê.", "about-report-issue-2": "Xerpiyaye versiyoni bınısne", "about-libraries-title": "Kıtabxaney", "kiwix-server-running-message": "Serverê kiwixiyo guriyeno, pirıka mehaliye de be adrese ra şenê cı resê:", "kiwix-server-description": "Serveri sıftekerdış, tora mehalli de komputeranê binan ra standard yew rovıteri ra kıtabxaney Kiwixê şıma resayışi re mısade dano.", "fullscreen-notification": "Enewke modê tam ekranı derê.veciyayışi rê ESC bıpıloğne", "local-files": "Dosya mehali", "hide": "Bınımnê", "open-in-browser": "Browseri de akerê", "start-kiwix-server": "Serverê Kiwixi bıgureynê", "stop-kiwix-server": "Serverê Kiwixi vındarne", "all": "Pêro", "fulltext-search": "Tam Metin cıgeyrayış", "pictures": "Resımi", "videos": "Videoy", "ftindex": "Tammetin index", "details": "Meqale pêro", "yes": "eya", "no": "nê", "no-filter": "parzûn çıniyo", "open-link-in-web-browser": "Browserê webi de gırey akerê", "download-dir-dialog-title": "Şıma qayılê ke zerrekê ronayışi bıvurnê?", "download-dir-dialog-msg": "Zerrekê ronayışiyo newe do wına bo:\n{{DIRECTORY}}", "invalid-port": "Nuqtaya xırab" } kiwix-desktop-2.4.1/resources/i18n/en.json000066400000000000000000000215631473106011000204060ustar00rootroot00000000000000{ "@metadata": { "authors": [ ] }, "name":"English", "error-title":"Error", "error-downloader-window-title":"Cannot create downloader", "error-downloader-launch-message":"Impossible to launch downloader, Kiwix-desktop will start but all download functions will not working!", "error-launch-server-message":"An error has occured!", "error-archive":"Cannot get the archive", "error-opening-file": "There was an error opening the file.", "open-zim":"Open ZIM File", "local-kiwix-server":"Local Kiwix Server", "random-article":"Random Article", "random-article-error":"Failed to open a random article.", "home-page":"Home page", "main-menu":"Main menu", "print":"Print", "print-page-error":"An error has occured while printing.", "new-tab":"New tab", "close-tab":"Close tab", "close":"Close", "reopen-closed-tab":"Reopen closed tab", "browse-library":"Browse library", "open-file":"Open file", "save-file": "Save file", "open-recent":"Open recent", "search-article":"Search article", "search-in-library":"Search in library", "find-in-page":"Find in page", "set-fullscreen":"Set fullscreen", "quit-fullscreen":"Quit fullScreen", "table-of-content":"Table of content", "add-bookmark": "Add to the reading list", "remove-bookmark": "Remove from the reading list", "reading-list":"Reading List", "zoom-in":"Zoom in", "zoom-out":"Zoom out", "zoom-reset":"Zoom reset", "help":"Help", "feedback":"Feedback", "report-a-bug":"Report a bug", "request-a-feature":"Request a feature", "about-kiwix":"About Kiwix", "donate-to-support-kiwix":"Donate to support Kiwix", "exit":"Exit", "save-file-as-window-title":"Save File as", "download-finished": "Download Finished", "download-finished-message":"The document has been downloaded.", "file":"File", "edit":"Edit", "view":"View", "tools":"Tools", "window-title":"Library - Kiwix", "search":"Search", "browse-directory":"Browse Directory", "settings":"Settings", "back":"Back", "forward":"Forward", "search-files":"Search files", "title":"Title", "size":"Size", "date":"Date", "content-type":"Content type", "reset-sort":"reset sort", "open":"Open", "delete":"Delete", "download":"Download", "resume":"Resume", "pause":"Pause", "cancel":"Cancel", "apply":"Apply", "port-for-local-kiwix-server-setting":"Port for local Kiwix server", "zoom-level-setting":"Default zoom level", "download-directory-setting":"Download directory", "monitor-directory-setting":"Monitor directory", "reset":"Reset", "clear":"Clear", "browse":"Browse", "about-kiwix-desktop-title":"Kiwix Desktop", "about-kiwix-desktop-description":"Kiwix allows you to have the entirety of Wikipedia at hand wherever you go! On a boat, in the middle of nowhere, or in jail, Kiwix gives you access to all of human knowledge. You don't need Internet, everything is stored on your computer.", "about-learn-more-about-kiwix":"Learn more about Kiwix", "about-release-title":"Release", "about-source-code":"This software is released under the terms of the GNU General Public License version 3. View the source code on Github.", "about-version":"Version: {{VERSION}}", "about-reporting-problem-title":"Reporting problems", "about-report-issue":"To open an issue, visit Kiwix-desktop issue tracker and open an issue describing your problem.", "about-report-issue-2":"Please mention the version in the issue.", "about-libraries-title":"Libraries", "kiwix-server-running-message":"The Kiwix Server is running and can be accessed in the local network at:", "kiwix-server-description":"Starting a server allows other computers in the local network to access your Kiwix library with a standard web browser.", "fullscreen-notification":"You are now in full screen mode. Press ESC to quit!", "online-files":"Online Files", "local-files":"Local Files", "category":"Category", "language":"Language", "hide":"Hide", "open-in-browser":"Open in browser", "start-kiwix-server":"Start Kiwix Server", "stop-kiwix-server":"Stop Kiwix Server", "all":"All", "all_ips":"All - Dual Stack Mode", "ipv4":"IPv4 Only Mode", "ipv6":"IPv6 Only Mode", "fulltext-search":"Fulltext search", "pictures":"Pictures", "videos":"Videos", "ftindex":"Fulltext index", "details":"Full article", "yes":"yes", "no":"no", "ok":"ok", "no-filter":"no filter", "open-link-in-web-browser":"Open link in web browser", "open-link-new-tab":"Open link in new tab", "download-dir-dialog-title":"Are you sure you want to change the download directory?", "download-dir-dialog-msg":"The new download directory path will be:\n{{DIRECTORY}}", "invalid-port":"Invalid port", "zim-open-fail-title":"Invalid file", "zim-open-fail-text":"The ZIM file {{ZIM}} cannot be opened properly. It will be removed from your library.", "monitor-dir-dialog-title":"Are you sure you want to change the monitor directory?", "monitor-dir-dialog-msg":"The new monitor directory path will be:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title":"Are you sure you want to clear the monitor directory?", "path-was-copied": "Path was copied", "monitor-clear-dir-dialog-msg":"This will stop checking the monitor directory for new ZIM files.", "monitor-directory-tooltip":"All ZIM files in this directory will be automatically added to the library.", "next-tab":"Move to next tab", "previous-tab":"Move to previous tab", "cancel-download": "Cancel download", "cancel-download-text": "Are you sure you want to cancel the download of {{ZIM}}?", "delete-book": "Delete book", "delete-book-text": "Are you sure you want to delete {{ZIM}}?", "download-storage-error": "Storage Error", "download-storage-error-text": "The system doesn't have enough storage available.", "download-exceeds-max-file-size": "Download size exceeds the max file size supported by the target filesystem.", "download-dir-missing": "Download directory doesn't exist.", "download-dir-not-writable": "Download directory is not writable.", "download-unavailable": "Download Unavailable", "download-unavailable-text": "This download is unavailable.", "open-book": "Open book", "download-book": "Download book", "pause-download": "Pause download", "resume-download": "Resume download", "open-folder": "Open folder", "couldnt-open-location": "Couldn't open location", "couldnt-open-location-text": "Kiwix is not able to open folder {{FOLDER}}", "move-files-to-trash": "Move deleted files to trash", "move-files-to-trash-text": "This action will move the file to trash.", "perma-delete-files-text": "This action will permanently delete the file.", "clear-filter": "Clear the currently set filters", "language-searcher-placeholder": "Filter by language", "category-searcher-placeholder": "Filter by category", "content-type-searcher-placeholder": "Filter by content type", "no-details": "Introduction only", "no-pictures": "No Pictures", "no-videos": "No Videos", "open-previous-tabs-at-startup": "Open previous tabs at startup", "preview-book-in-web-browser": "Preview book in web browser", "file-not-found-title": "ZIM File Not Found", "file-not-found-text": "ZIM file doesn't exist or is not readable", "zim-id": "ZIM Id", "zim-name": "ZIM Name", "zim-path": "ZIM File Path", "bad-zim-file-error-page-title": "Invalid ZIM File", "bad-zim-file-error-page-text": "ZIM file is invalid or corrupted.", "zim-entry-path": "ZIM Entry Path", "export-reading-list": "Export reading list", "export-reading-list-error": "An error has occured during export of the reading list.", "import-reading-list": "Import reading list", "import-reading-list-error": "An error has occured during import of the reading list.", "disable-sandbox": "Kiwix has been launched from a network drive. This is known to cause compatibility issues with the browsing sandboxing. As a result, the sandbox will be disabled. Do you want to continue?", "save-page-as": "Save As...", "portable-disabled-tooltip": "Function disabled in portable mode", "scroll-next-tab": "Scroll to next tab", "scroll-previous-tab": "Scroll to previous tab", "kiwix-search": "Kiwix search", "search-options": "Search Options", "read-article": "Read article", "read-text": "Read selected text", "read-stop": "Stop reading", "stop": "Stop", "voice": "Voice", "select-read-voice": "Select reading voice", "select-read-language": "Select reading language", "save-or-open": "Save or Open file", "save-or-open-text": "What should Kiwix do with this file?" } kiwix-desktop-2.4.1/resources/i18n/eo.json000066400000000000000000000032671473106011000204100ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Jakub Fabijan", "Robin van der Vliet" ] }, "name": "Esperanto", "error-title": "Eraro", "error-launch-server-message": "Eraro okazis!", "local-kiwix-server": "Loka Kiwix-servilo", "home-page": "Ĉefpaĝo", "main-menu": "Ĉefa menuo", "print": "Presi", "new-tab": "Nova langeto", "close-tab": "Fermi langeton", "close": "Fermi", "reopen-closed-tab": "Remalfermi fermitan langeton", "open-file": "Malfermi la dosieron", "search-article": "Serĉi artikolon", "search-in-library": "Serĉi en biblioteko", "help": "Helpo", "about-kiwix": "Pri Kiwix", "exit": "Ĉesi", "save-file-as-window-title": "Konservi Dosieron kiel", "file": "Dosiero", "edit": "Redakti", "view": "Vido", "tools": "Iloj", "window-title": "Biblioteko - Kiwix", "search": "Serĉi", "settings": "Agordoj", "back": "Reveni", "search-files": "Serĉi dosierojn", "title": "Titolo", "size": "Grandeco", "date": "Dato", "open": "Malfermi", "delete": "Forigi", "download": "Elŝuti", "resume": "Daŭrigi", "pause": "Paŭzigi", "cancel": "Nuligi", "apply": "Apliki", "download-directory-setting": "Elŝutujo:", "browse": "Foliumi", "about-kiwix-desktop-title": "Kiwix Labortablo", "about-learn-more-about-kiwix": "Lerni plu pri Kiwix", "about-version": "Versio : {{VERSION}}", "about-libraries-title": "Bibliotekoj", "local-files": "Lokaj dosieroj", "hide": "Kaŝi", "open-in-browser": "Malfermi per retumilo", "all": "Ĉiuj", "pictures": "Bildoj", "videos": "Filmetoj", "yes": "jes", "no": "ne", "no-filter": "neniu filtro", "open-link-in-web-browser": "Malfermi ligilon en retumilo", "invalid-port": "Nevalida pordo", "zim-open-fail-title": "Nevalida dosiero" } kiwix-desktop-2.4.1/resources/i18n/es.json000066400000000000000000000225761473106011000204200ustar00rootroot00000000000000{ "@metadata": { "authors": [ "AlexanderFF", "Carlespera", "DDPAT", "Destinid10 2", "Eulalio", "Fitoschido", "Geryescalier", "Ice bulldog", "Josuert", "La Mantis", "Ncr", "Ovruni", "Sinopsistrans", "Vis4valentine" ] }, "name": "español", "error-title": "Error", "error-downloader-window-title": "No se puede crear el descargador", "error-downloader-launch-message": "No se puede iniciar el descargador. Kiwix-desktop se iniciará pero no funcionarán las prestaciones de descarga!", "error-launch-server-message": "¡Ha ocurrido un error!", "error-archive": "No se puede obtener el archivo", "open-zim": "Abrir archivo ZIM", "local-kiwix-server": "Servidor Kiwix local", "random-article": "Artículo al azar", "random-article-error": "Error al abrir un artículo aleatorio.", "home-page": "Página principal", "main-menu": "Menú principal", "print": "Imprimir", "print-page-error": "Ha ocurrido un error durante la impresión.", "new-tab": "Pestaña nueva", "close-tab": "Cerrar pestaña", "close": "Cerrar", "reopen-closed-tab": "Reabrir pestaña cerrada", "browse-library": "Explorar biblioteca", "open-file": "Abrir archivo", "open-recent": "Abrir recientes", "search-article": "Buscar en el artículo", "search-in-library": "Buscar en la biblioteca", "find-in-page": "Encontrar en la página", "set-fullscreen": "Establecer pantalla completa", "quit-fullscreen": "Salir de la pantalla completa", "table-of-content": "Sumario", "add-bookmark": "Añadir a lista de lectura", "remove-bookmark": "Quitar de la lista de lectura", "reading-list": "Lista de lectura", "zoom-in": "Acercar", "zoom-out": "Alejar", "zoom-reset": "Restablecer escala", "help": "Ayuda", "feedback": "Comentarios", "report-a-bug": "Informar de un defecto", "request-a-feature": "Solicitar una función", "about-kiwix": "Acerca de Kiwix", "donate-to-support-kiwix": "Dona para apoyar a Kiwix", "exit": "Salir", "save-file-as-window-title": "Guardar archivo como", "download-finished-message": "Se ha descargado el documento.", "file": "Archivo", "edit": "Editar", "view": "Ver", "tools": "Herramientas", "window-title": "Biblioteca - Kiwix", "search": "Buscar", "browse-directory": "Examinar directorio", "settings": "Configuración", "back": "Atrás", "forward": "Reenviar", "search-files": "Buscar archivos", "title": "Título", "size": "Tamaño", "date": "Fecha", "content-type": "Tipo de contenido", "reset-sort": "restablecer orden", "open": "Abrir", "delete": "Eliminar", "download": "Descargar", "resume": "Reanudar", "pause": "Pausar", "cancel": "Cancelar", "apply": "Aplicar", "port-for-local-kiwix-server-setting": "Puerto del servidor Kiwix local", "zoom-level-setting": "Nivel de escala predeterminado", "download-directory-setting": "Directorio de descargas", "monitor-directory-setting": "Supervisar directorio", "reset": "Restablecer", "clear": "Limpiar", "browse": "Explorar", "about-kiwix-desktop-title": "Escritorio Kiwix", "about-kiwix-desktop-description": "¡Kiwix te permite tener toda la Wikipedia a mano donde quiera que vayas! En un barco, en medio de la nada o en la cárcel, Kiwix te da acceso a todo el conocimiento humano. No necesitas Internet, todo está almacenado en tu computadora.", "about-learn-more-about-kiwix": "Para conocer más sobre Kiwix", "about-release-title": "Lanzamiento", "about-source-code": "Este software se ha publicado en virtud de la Licencia Pública General de GNU, versión 3. El código fuente puede verse en GitHub.", "about-version": "Versión: {{VERSION}}", "about-reporting-problem-title": "Informar de un problema", "about-report-issue": "Para abrir una incidencia, visite el rastreador de incidencias de Kiwix-desktop y abra una incidente que describa su problema.", "about-report-issue-2": "Menciona la versión en el problema.", "about-libraries-title": "Bibliotecas", "kiwix-server-running-message": "El servidor Kiwix se está ejecutando y se puede acceder a él en la red local en:", "kiwix-server-description": "Iniciar un servidor permite que otras computadoras en la red local accedan a su biblioteca Kiwix con un navegador web estándar.", "fullscreen-notification": "Ahora estás en modo de pantalla completa. Presione ESC para salir!", "online-files": "Archivos en línea", "local-files": "Archivos locales", "category": "Categoría", "language": "Idioma", "hide": "Ocultar", "open-in-browser": "Abrir en el navegador", "start-kiwix-server": "Iniciar servidor Kiwix", "stop-kiwix-server": "Detener servidor Kiwix", "all": "Todo", "all_ips": "Todos - Modo doble pila", "ipv4": "Solo IPv4", "ipv6": "Solo IPv6", "fulltext-search": "Búsqueda de texto completo", "pictures": "Imágenes", "videos": "Vídeos", "ftindex": "Índice de texto completo", "details": "Artículo completo", "yes": "sí", "no": "no", "ok": "correcto", "no-filter": "Sin filtro", "open-link-in-web-browser": "Abrir enlace en navegador web", "open-link-new-tab": "Abrir enlace en una nueva pestaña", "download-dir-dialog-title": "¿Está seguro de que desea cambiar el directorio de descarga?", "download-dir-dialog-msg": "La nueva ruta del directorio de descarga será:\n{{DIRECTORY}}", "invalid-port": "Puerto no válido", "zim-open-fail-title": "Archivo invalido", "zim-open-fail-text": "El archivo ZIM {{ZIM}} no se puede abrir correctamente. Será eliminado de tu biblioteca.", "monitor-dir-dialog-title": "¿Está seguro de que desea cambiar el directorio monitorio?", "monitor-dir-dialog-msg": "La nueva ruta del directorio de monitoreo será:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "¿Está seguro de que desea borrar el directorio de monitoreo?", "path-was-copied": "La ruta fue copiada", "monitor-clear-dir-dialog-msg": "Esto dejará de buscar en el directorio de monitorio por nuevos archivos ZIM.", "monitor-directory-tooltip": "Todos los archivos ZIM en este directorio se agregarán automáticamente a la biblioteca.", "next-tab": "Mover a la siguiente pestaña", "previous-tab": "Mover a la pestaña anterior", "cancel-download": "Cancelar descarga", "cancel-download-text": "¿Está seguro de que desea cancelar la descarga de {{ZIM}} ?", "delete-book": "Eliminar libro", "delete-book-text": "¿Está seguro de que desea eliminar {{ZIM}} ?", "download-storage-error": "Erro de almacenamiento", "download-storage-error-text": "El sistema no tiene suficiente almacenamiento disponible.", "download-exceeds-max-file-size": "El tamaño de la descarga supera el tamaño máximo de archivo admitido por el sistema de archivos de destino.", "download-dir-missing": "El directorio de descargas no existe.", "download-dir-not-writable": "El directorio de descarga no se puede escribir.", "download-unavailable": "Descarga no disponible", "download-unavailable-text": "Esta descarga no está disponible.", "open-book": "Abrir libro", "download-book": "Descargar libro", "pause-download": "Pausar descarga", "resume-download": "Continuar descarga", "open-folder": "Abrir carpeta", "couldnt-open-location": "No se pudo abrir la ubicación", "couldnt-open-location-text": "Kiwix no puede abrir la carpeta {{FOLDER}}", "move-files-to-trash": "Mover archivos eliminados a la papelera", "move-files-to-trash-text": "Esta acción moverá el archivo a la papelera.", "perma-delete-files-text": "Esta acción eliminará permanentemente el archivo.", "clear-filter": "Borrar los filtros establecidos actualmente", "language-searcher-placeholder": "Filtrar por idioma", "category-searcher-placeholder": "Filtrar por categoría", "content-type-searcher-placeholder": "Filtrar por tipo de contenido", "no-details": "Solo introducción", "no-pictures": "Sin imágenes", "no-videos": "Ningún video", "open-previous-tabs-at-startup": "Abrir pestañas anteriores al inicio", "preview-book-in-web-browser": "Vista previa del libro en el navegador web", "file-not-found-title": "Archivo ZIM no encontrado", "file-not-found-text": "El archivo ZIM no existe o no es legible", "zim-id": "Identificación del archivo ZIM", "zim-name": "Nombre del archivo ZIM", "zim-path": "Ruta del archivo ZIM", "bad-zim-file-error-page-title": "Archivo ZIM no válido", "bad-zim-file-error-page-text": "El archivo ZIM no es válido o está corrompido.", "zim-entry-path": "Vía de acceso ZIM", "export-reading-list": "Exportar lista de lectura", "export-reading-list-error": "Se ha producido un error durante la exportación de la lista de lectura.", "import-reading-list": "Importar lista de lectura", "import-reading-list-error": "Se ha producido un error durante la importación de la lista de lectura.", "disable-sandbox": "Kiwix se ha iniciado desde una unidad de red. Se sabe que esto causa problemas de compatibilidad con el sandboxing de navegación. Como resultado, el sandbox será desactivado. ¿Desea continuar?", "save-page-as": "Guardar como...", "portable-disabled-tooltip": "Función deshabilitada en modo portátil", "scroll-next-tab": "Desplazarse a la pestaña siguiente", "scroll-previous-tab": "Desplazarse a la pestaña anterior", "kiwix-search": "Búsqueda de Kiwix", "search-options": "Opciones de búsqueda", "read-article": "Leer artículo", "read-text": "Leer el texto seleccionado", "read-stop": "Dejar de leer", "stop": "Detener", "voice": "Voz", "select-read-voice": "Seleccionar la voz de lectura", "select-read-language": "Seleccione el idioma de lectura" } kiwix-desktop-2.4.1/resources/i18n/fa.json000066400000000000000000000044761473106011000203760ustar00rootroot00000000000000{ "@metadata": { "authors": [ "FarsiNevis", "Jeeputer", "Rulebased" ] }, "name": "انگلیسی", "error-title": "خطا", "random-article": "مقالهٔ تصادفی", "random-article-error": "ناتوان در گشودن مقالهٔ تصادفی.", "print": "چاپ", "new-tab": "برگهٔ جدید", "close-tab": "بستن برگه", "close": "بستن", "reopen-closed-tab": "برگهٔ بسته‌شده را دوباره باز کن", "browse-library": "مرور کتابخانه", "open-file": "باز کردن پرونده", "search-in-library": "جستجو در کتابخانه", "find-in-page": "جستجو در صفحه", "quit-fullscreen": "خروج از تمام‌صفحه", "reading-list": "فهرست مطالعه", "zoom-in": "بزرگ‌نمایی", "zoom-out": "کوچک‌نمایی", "help": "راهنما", "feedback": "بازخورد", "report-a-bug": "گزارش یک اشکال", "exit": "خروج", "save-file-as-window-title": "ذخیرهٔ پرونده به‌صورت", "download-finished-message": "مدرک مورد نظر بارگیری شد.", "file": "پرونده", "edit": "ویرایش", "view": "مشاهده", "tools": "ابزارها", "search": "جستجو", "settings": "تنظیمات", "search-files": "جستجوی پرونده‌ها", "title": "عنوان", "size": "اندازه", "date": "تاریخ", "content-type": "نوع محتوا", "open": "باز کن", "delete": "حذف", "download": "بارگیری", "resume": "ادامه", "pause": "مکث", "cancel": "لغو", "apply": "اِعمال کن", "browse": "مرور", "about-reporting-problem-title": "گزارش مشکل", "about-libraries-title": "کتابخانه‌ها", "local-files": "پرونده‌های محلی", "language": "زبان", "hide": "پنهان کن", "open-in-browser": "در مرورگر باز کن", "all": "همه", "open-link-new-tab": "گشودن پیوند در زبانه‌ای جدید", "export-reading-list": "برون‌بری فهرست مطالعه", "export-reading-list-error": "در طول برون‌بری فهرست مطالعه خطایی رخ داد.", "import-reading-list": "درون‌ریزی فهرست مطالعه", "import-reading-list-error": "در طول درون‌ریزی فهرست مطالعه خطایی رخ داد." } kiwix-desktop-2.4.1/resources/i18n/fi.json000066400000000000000000000112471473106011000204000ustar00rootroot00000000000000{ "@metadata": { "authors": [ "MITO", "Nike", "Pyscowicz", "Rönttönen" ] }, "name": "suomi", "error-title": "Virhe", "error-downloader-window-title": "Latausohjelmaa ei voi luoda", "error-launch-server-message": "Tapahtui virhe!", "open-zim": "Avaa ZIM-tiedosto", "local-kiwix-server": "Paikallinen Kiwix-palvelin", "random-article": "Satunnainen artikkeli", "random-article-error": "Virhe avattaessa satunnaista artikkelia.", "home-page": "Kotisivu", "main-menu": "Päävalikko", "print": "Tulosta", "print-page-error": "Tulostettaessa tapahtui virhe.", "new-tab": "Uusi välilehti", "close-tab": "Sulje välilehti", "close": "Sulje", "reopen-closed-tab": "Avaa suljettu välilehti uudelleen", "browse-library": "Selaa kirjastoa", "open-file": "Avaa tiedosto", "open-recent": "Avaa viimeisin", "search-article": "Hae artikkelia", "search-in-library": "Hae kirjastossa", "find-in-page": "Etsi sivulta", "set-fullscreen": "Siirry koko näytön tilaan", "quit-fullscreen": "Poistu koko näytön tilasta", "table-of-content": "Sisällysluettelo", "reading-list": "Lukulista", "zoom-in": "Lähennä", "zoom-out": "Loitonna", "zoom-reset": "Zoomauksen nollaus", "help": "Ohje", "feedback": "Palaute", "report-a-bug": "Ilmoita bugista", "request-a-feature": "Ehdota ominaisuutta", "about-kiwix": "Tietoja Kiwixistä", "donate-to-support-kiwix": "Lahjoita tukeaksi Kiwixiä", "exit": "Poistu", "save-file-as-window-title": "Tallenna tiedosto nimellä", "download-finished-message": "Asiakirja on ladattu", "file": "Tiedosto", "edit": "Muokkaa", "view": "Näytä", "tools": "Työkalut", "window-title": "Kirjasto - Kiwix", "search": "Hae", "browse-directory": "Selaa hakemistoa", "settings": "Asetukset", "back": "Takaisin", "forward": "Eteenpäin", "search-files": "Etsi tiedostoja", "title": "Otsikko", "size": "Koko", "date": "Päivämäärä", "content-type": "Sisältötyyppi", "reset-sort": "nollaa lajittelu", "open": "Avaa", "delete": "Poista", "download": "Lataa", "resume": "Jatka", "pause": "Tauko", "cancel": "Peruuta", "apply": "Käytä", "port-for-local-kiwix-server-setting": "Portti paikalliselle Kiwix-palvelimelle", "zoom-level-setting": "Oletuszoomaustaso", "download-directory-setting": "Lataushakemisto", "reset": "Nollaa", "clear": "Tyhjennä", "browse": "Selaa", "about-kiwix-desktop-title": "Kiwix-työpöytä", "about-learn-more-about-kiwix": "Lisätietoja Kiwixistä", "about-release-title": "Julkaisu", "about-version": "Versio: {{VERSION}}", "about-libraries-title": "Kirjastot", "fullscreen-notification": "Olet nyt koko näytön tilassa. Paina ESC poistuaksesi!", "online-files": "Online-tiedostot", "local-files": "Paikalliset tiedostot", "category": "Luokka", "language": "Kieli", "hide": "Piilota", "open-in-browser": "Avaa selaimessa", "start-kiwix-server": "Käynnistä Kiwix-palvelin", "stop-kiwix-server": "Pysäytä Kiwix-palvelin", "all": "Kaikki", "pictures": "Kuvat", "videos": "Videot", "details": "Koko artikkeli", "yes": "kyllä", "no": "ei", "open-link-in-web-browser": "Avaa linkki verkkoselaimessa", "open-link-new-tab": "Avaa linkki uudessa välilehdessä", "download-dir-dialog-title": "Haluatko varmasti vaihtaa lataushakemistoa?", "download-dir-dialog-msg": "Uusi lataushakemiston polku on:\n{{DIRECTORY}}", "invalid-port": "Virheellinen portti", "zim-open-fail-title": "Virheellinen tiedosto", "monitor-directory-tooltip": "Kaikki ZIM-tiedostot tässä hakemistossa lisätään automaattisesti kirjastoon.", "next-tab": "Siirry seuraavaan välilehteen", "previous-tab": "Siirry edelliseen välilehteen", "cancel-download": "Peruuta lataus", "cancel-download-text": "Haluatko varmasti peruuttaa tiedoston {{ZIM}} latauksen?", "delete-book": "Poista kirja", "delete-book-text": "Haluatko varmasti poistaa {{ZIM}}?", "open-book": "Avaa kirja", "download-book": "Lataa kirja", "pause-download": "Keskeytä lataus", "resume-download": "Jatka latausta", "open-folder": "Avaa kansio", "couldnt-open-location": "Sijaintia ei voitu avata", "couldnt-open-location-text": "Kiwix ei pystynyt avaamaan kansiota {{FOLDER}}", "move-files-to-trash": "Siirrä poistetut tiedostot roskakoriin", "move-files-to-trash-text": "Tämä toiminto siirtää tiedoston roskakoriin.", "perma-delete-files-text": "Tämä toiminto poistaa tiedoston pysyvästi.", "language-searcher-placeholder": "Suodata kielen perusteella", "category-searcher-placeholder": "Suodata luokan perusteella", "content-type-searcher-placeholder": "Suodata sisältötyypin perusteella", "no-pictures": "Ei kuvia", "no-videos": "Ei videoita", "open-previous-tabs-at-startup": "Avaa edelliset välilehdet käynnistyksen yhteydessä" } kiwix-desktop-2.4.1/resources/i18n/fr.json000066400000000000000000000243451473106011000204140ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Benoit74", "Constant", "Florian COLLIN", "Gomoko", "Goombiis", "Graineahumus", "Hecatonchire", "Mahabarata", "McDutchie", "Méthodes Bulebe Hangi", "Stephane", "Terio legale", "Verdy p", "Wladek92" ] }, "name": "Français", "error-title": "Erreur", "error-downloader-window-title": "Impossible de créer le processus de téléchargement", "error-downloader-launch-message": "Impossible de lancer le téléchargement, Kiwix-desktop démarrera mais toutes les fonctions de téléchargement ne fonctionneront pas !", "error-launch-server-message": "Une erreur s’est produite !", "error-archive": "Impossible d’obtenir l’archive", "error-opening-file": "Une erreur s'est produite lors de l'ouverture du fichier.", "open-zim": "Ouvrir un fichier ZIM", "local-kiwix-server": "Serveur local Kiwix", "random-article": "Article au hasard", "random-article-error": "Échec à l’ouverture d’un article au hasard.", "home-page": "Page principale", "main-menu": "Menu principal", "print": "Imprimer", "print-page-error": "Une erreur s’est produite lors de l’impression.", "new-tab": "Nouvel onglet", "close-tab": "Fermer l’onglet", "close": "Fermer", "reopen-closed-tab": "Rouvrir l’onglet fermé", "browse-library": "Parcourir la bibliothèque", "open-file": "Ouvrir un fichier", "save-file": "Enregistrer le fichier", "open-recent": "Fichiers récemment ouverts", "search-article": "Rechercher un article", "search-in-library": "Chercher dans la bibliothèque", "find-in-page": "Chercher dans la page", "set-fullscreen": "Mode plein écran", "quit-fullscreen": "Quitter le mode plein écran", "table-of-content": "Table des matières", "add-bookmark": "Ajouter à la liste de lecture", "remove-bookmark": "Supprimer de la liste de lecture", "reading-list": "Liste de lecture", "zoom-in": "Zoom avant", "zoom-out": "Zoom arrière", "zoom-reset": "Réinitialisation du zoom", "help": "Aide", "feedback": "Retour d’information", "report-a-bug": "Signaler une anomalie", "request-a-feature": "Demander une fonctionnalité", "about-kiwix": "À propos de kiwix", "donate-to-support-kiwix": "Faire un don pour soutenir Kiwix", "exit": "Quitter", "save-file-as-window-title": "Enregistrer le fichier sous", "download-finished": "Téléchargement terminé", "download-finished-message": "Le document a été téléchargé.", "file": "Fichier", "edit": "Modifier", "view": "Afficher", "tools": "Outils", "window-title": "Bibliothèque – Kiwix", "search": "Recherche", "browse-directory": "Parcourir un dossier", "settings": "Paramètres", "back": "Retour", "forward": "Suivant", "search-files": "Chercher des fichiers", "title": "Titre", "size": "Taille", "date": "Date", "content-type": "Type de contenu", "reset-sort": "réinitialiser le tri", "open": "Ouvrir", "delete": "Supprimer", "download": "Télécharger", "resume": "Reprendre", "pause": "Pause", "cancel": "Annuler", "apply": "Appliquer", "port-for-local-kiwix-server-setting": "Port pour le serveur Kiwix local", "zoom-level-setting": "Niveau de zoom par défaut", "download-directory-setting": "Dossier de téléchargement", "monitor-directory-setting": "Surveiller le répertoire", "reset": "Réinitialiser", "clear": "Effacer", "browse": "Parcourir", "about-kiwix-desktop-title": "Kiwix pour ordinateurs de bureau", "about-kiwix-desktop-description": "Kiwix vous permet d’avoir tout Wikipédia à portée de main où que vous alliez ! Sur un bateau, au milieu de nulle part, ou en prison, Kiwix vous donne accès à tout le savoir humain. Vous n’avez pas besoin d’Internet, tout est conservé dans votre ordinateur.", "about-learn-more-about-kiwix": "En savoir plus sur Kiwix", "about-release-title": "Publication", "about-source-code": "Ce logiciel est publié selon les termes de la licence GNU General Public License version 3. Vous pouvez consulter le code source sur Github.", "about-version": "Version : {{VERSION}}", "about-reporting-problem-title": "Signaler des problèmes", "about-report-issue": "Pour signaler un problème, allez sur la page de signalement et ouvrez un ticket en décrivant votre problème.", "about-report-issue-2": "Veuillez indiquer la version de Kiwix dans votre signalement.", "about-libraries-title": "Bibliothèques", "kiwix-server-running-message": "Le serveur Kiwix est lancé et peut être accédé sur le réseau local à :", "kiwix-server-description": "Démarrer un serveur permet à d’autres ordinateurs du réseau local d’accéder à votre bibliothèque Kiwix avec un navigateur web classique.", "fullscreen-notification": "Vous êtes maintenant en plein écran. Appuyez sur Échap pour quitter !", "online-files": "Fichiers en ligne", "local-files": "Fichiers locaux", "category": "Catégorie", "language": "Langue", "hide": "Masquer", "open-in-browser": "Ouvrir dans un navigateur", "start-kiwix-server": "Démarrer le serveur Kiwix", "stop-kiwix-server": "Arrêter le serveur Kiwix", "all": "Tout", "all_ips": "Tous - IPv4 et IPv6", "ipv4": "Mode IPv4 uniquement", "ipv6": "Mode IPv6 uniquement", "fulltext-search": "Recherche plein texte", "pictures": "Images", "videos": "Vidéos", "ftindex": "Index en plein texte", "details": "Article complet", "yes": "oui", "no": "non", "ok": "ok", "no-filter": "aucun filtre", "open-link-in-web-browser": "Ouvrir le lien dans votre navigateur web", "open-link-new-tab": "Ouvrir le lien dans un nouvel onglet", "download-dir-dialog-title": "Voulez-vous vraiment modifier le répertoire de téléchargement ?", "download-dir-dialog-msg": "Le nouveau chemin du répertoire de téléchargement sera :\n{{DIRECTORY}}", "invalid-port": "Port non valide", "zim-open-fail-title": "Fichier non valide", "zim-open-fail-text": "Le fichier ZIM {{ZIM}} ne peut être ouvert correctement. Il sera supprimé de votre bibliothèque.", "monitor-dir-dialog-title": "Voulez-vous vraiment modifier le répertoire de surveillance ?", "monitor-dir-dialog-msg": "Le nouveau chemin du répertoire du moniteur sera :\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Voulez-vous vraiment effacer le répertoire de surveillance ?", "path-was-copied": "Le chemin a été copié", "monitor-clear-dir-dialog-msg": "Ceci arrêtera la vérification du répertoire de surveillance des nouveaux fichiers ZIM.", "monitor-directory-tooltip": "Tous les fichiers ZIM dans ce répertoire seront automatiquement ajoutés à la bibliothèque.", "next-tab": "Passer à l’onglet suivant", "previous-tab": "Passer à l’onglet précédent", "cancel-download": "Annuler le téléchargement", "cancel-download-text": "Êtes-vous sûr de vouloir annuler le téléchargement de {{ZIM}} ?", "delete-book": "Supprimer le livre", "delete-book-text": "Êtes-vous sûr de vouloir supprimer {{ZIM}} ?", "download-storage-error": "Erreur de stockage", "download-storage-error-text": "Le système n’a pas assez de place de stockage disponible.", "download-exceeds-max-file-size": "La taille du téléchargement dépasse la taille de fichier maximale prise en charge par le système de fichiers cible.", "download-dir-missing": "Le répertoire de téléchargement n’existe pas.", "download-dir-not-writable": "Le répertoire de téléchargement n’est pas accessible en écriture.", "download-unavailable": "Téléchargement indisponible", "download-unavailable-text": "Ce téléchargement n’est pas disponible.", "open-book": "Ouvrir le livre", "download-book": "Télécharger le livre", "pause-download": "Mettre en pause le téléchargement", "resume-download": "Reprendre le téléchargement", "open-folder": "Ouvrir le dossier", "couldnt-open-location": "Impossible d’ouvrir l’emplacement", "couldnt-open-location-text": "Kiwix ne peut pas ouvrir le dossier {{FOLDER}}", "move-files-to-trash": "Déplacer les fichiers supprimés vers la corbeille", "move-files-to-trash-text": "Cette action déplacera le fichier vers la corbeille.", "perma-delete-files-text": "Cette action supprimera définitivement le fichier.", "clear-filter": "Réinitialiser les filtres actuels", "language-searcher-placeholder": "Filtrer par langue", "category-searcher-placeholder": "Filtrer par catégorie", "content-type-searcher-placeholder": "Filtrer par type de contenu", "no-details": "Introduction seulement", "no-pictures": "Aucune image", "no-videos": "Aucune vidéo", "open-previous-tabs-at-startup": "Ouvrir les onglets précédents au démarrage", "preview-book-in-web-browser": "Aperçu du livre dans un navigateur web", "file-not-found-title": "Fichier ZIM non trouvé", "file-not-found-text": "Le fichier ZIM n'existe pas ou n'est pas lisible", "zim-id": "ZIM Id", "zim-name": "Nom Zim", "zim-path": "Voie du fichier Zim", "bad-zim-file-error-page-title": "Fichier ZIM non valide", "bad-zim-file-error-page-text": "Le fichier ZIM est invalide ou corrompu.", "zim-entry-path": "Chemin d'accès ZIM", "export-reading-list": "Exporter la liste de lecture", "export-reading-list-error": "Une erreur s'est produite lors de l'exportation de la liste de lecture.", "import-reading-list": "Importer la liste de lecture", "import-reading-list-error": "Une erreur s'est produite lors de l'importation de la liste de lecture.", "disable-sandbox": "Kiwix a été lancé à partir d'un lecteur réseau. Ceci est connu pour causer des problèmes de compatibilité avec le sandbox (bac à sable) de navigation. Par conséquent, le sandbox (bac à sable) sera désactivé. Voulez-vous continuer ?", "save-page-as": "Enregistrer sous...", "portable-disabled-tooltip": "Fonction désactivée en mode portable", "scroll-next-tab": "Faire défiler vers l' onglet suivant", "scroll-previous-tab": "Faire défiler vers l' onglet précédent", "kiwix-search": "Recherche Kiwix", "search-options": "Options de recherche", "read-article": "Lire l’article", "read-text": "Lire le texte sélectionné", "read-stop": "Arrêter la lecture", "stop": "Arrêter", "voice": "Voix", "select-read-voice": "Sélectionner la voix de lecture", "select-read-language": "Sélectionner la langue de lecture", "save-or-open": "Enregistrer ou ouvrir le fichier", "save-or-open-text": "Que doit faire Kiwix avec ce fichier ?" } kiwix-desktop-2.4.1/resources/i18n/gsw.json000066400000000000000000000025421473106011000206000ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "Rschlegel" ] }, "name": "Schwiizerdütsch", "open-zim": "Zim öffnä", "random-article": "Zuefälligi Syte", "print": "Drucke", "browse-library": "Dur'd Bibliothek stöbere", "open-file": "Datei uftuä", "search-in-library": "Bibliothek dürsuechä", "find-in-page": "I de Syte finde", "feedback": "Rückmäldige", "about-kiwix": "Über Kiwix", "donate-to-support-kiwix": "Spände um Kiwix z'unterschtütze", "exit": "Beände", "save-file-as-window-title": "Datei speicherä als", "download-finished-message": "S Document isch abegladä worde.", "file": "Datei", "edit": "Bearbeite", "view": "Aaluege", "tools": "Wärchzüüg", "search": "Sueche", "settings": "Yystellige", "back": "Zrügg", "forward": "Wyter", "title": "Titel", "size": "Grössi", "date": "Datum", "content-type": "Inhaltstyp", "open": "Ufmache", "delete": "Lösche", "download": "Abelade", "resume": "Wiitermache", "pause": "Pousiere", "cancel": "Abbräche", "apply": "Aawände", "reset": "Zrüggsetze", "about-reporting-problem-title": "Es Problem mälde", "about-libraries-title": "Bibliotheke", "local-files": "Lokali Dateiä", "hide": "Uusblände", "all": "Alli", "fulltext-search": "Volltexschtsuechi", "pictures": "Bilder", "videos": "Videos", "ftindex": "Volltexschtindex", "no-filter": "kei Filter" } kiwix-desktop-2.4.1/resources/i18n/ha.json000066400000000000000000000154251473106011000203740ustar00rootroot00000000000000{ "@metadata": { "authors": [ "787IYO", "El-hussain14", "Rofiatmustapha12", "Yusuf Sa'adu" ] }, "name": "turanci", "error-title": "kuskure", "error-downloader-window-title": "Ba za a iya ƙirƙirar mai saukewa ba", "error-downloader-launch-message": "Ba zai yiwu a kaddamar da mai saukewa ba, Kiwix-desktop zai fara amma duk ayyukan saukewa ba za su yi aiki ba!", "error-launch-server-message": "An yi kuskure!", "error-archive": "Ba za a iya samun tarihin ba", "open-zim": "Buɗe Fayil na ZIM", "local-kiwix-server": "Sabar Kiwix ta gida", "random-article": "Labari na bazuwar", "random-article-error": "An kasa buɗe labarin bazuwar.", "home-page": "Shafin gida", "main-menu": "Babban menu", "print": "Bugawa", "print-page-error": "Kuskuren ya faru yayin bugawa.", "new-tab": "Sabon shafin", "close-tab": "Rufe shafin", "close": "Rufe", "reopen-closed-tab": "Sake bude shafin da aka rufe", "browse-library": "Nemo ɗakin karatu", "open-file": "Bude fayil", "open-recent": "Bude kwanan nan", "search-article": "Duba mukala", "search-in-library": "Bincika a cikin dakin karatu", "find-in-page": "Nema a shafi", "set-fullscreen": "Saita cikakken allo", "quit-fullscreen": "A daina cikakken allo", "table-of-content": "Abubuwan dake ciki", "reading-list": "Jerin karatu", "zoom-in": "Zuƙo ciki", "zoom-out": "Zuƙo waje", "zoom-reset": "Sake saitin zuƙowa", "help": "Taimako", "feedback": "Bayani", "report-a-bug": "ka bada labarin duk wata matsala", "request-a-feature": "Nemi fasali", "about-kiwix": "Game da Kiwix", "donate-to-support-kiwix": "Ba da gudummawa don tallafawa Kiwix", "exit": "Fita", "save-file-as-window-title": "Ajiye fayil kamar yadda", "download-finished-message": "An sauke takardar.", "file": "Fayil", "edit": "Gyara", "view": "Duba", "tools": "Akwatin kayan aiki", "window-title": "Laburaren - Kiwix", "search": "Bincike", "browse-directory": "Littafin Browse", "settings": "Saituttuka", "back": "Baya", "forward": "Gaba", "search-files": "Bincika fayiloli", "title": "Take", "size": "Girma", "date": "Kwanan wata", "content-type": "Irin abubuwan da ke ciki", "reset-sort": "sake saitawa", "open": "Buɗe", "delete": "Share", "download": "Sauke", "resume": "Ci gaba", "pause": "Dakatar da shi", "cancel": "Yanke", "apply": "Nema", "port-for-local-kiwix-server-setting": "Tashar jiragen ruwa don uwar garken Kiwix na gida", "zoom-level-setting": "Matsayin zoom na kuskure", "download-directory-setting": "Bayanan saukewa", "monitor-directory-setting": "Lissafin mai kula", "reset": "Sake saiti", "clear": "Share", "browse": "Browse", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix yana ba ka damar samun dukkan Wikipedia a hannu duk inda kuka tafi! A cikin jirgin ruwa, a tsakiyar babu inda, ko a kurkuku, Kiwix yana ba ku damar samun dukkan ilimin ɗan adam. Ba ka buƙatar Intanet, ana adana komai akan kwamfutarka.", "about-learn-more-about-kiwix": "Ƙara koyo game da Kiwix", "about-release-title": "Saki", "about-source-code": "An fito da wannan software a ƙarƙashin sharuɗɗan GNU Janar na Lasisi na Jama'a 3. Duba lambar tushe akan Github .", "about-version": "Siga: {{VERSION}}", "about-reporting-problem-title": "Bada rahoton matsala", "about-report-issue": "Don buɗe matsala, ziyarci Kiwix-tebur mai sa ido kuma buɗe batun da ke bayyana matsalar ku.", "about-report-issue-2": "Da fatan za a ambaci sigar a cikin fitowar.", "about-libraries-title": "Dakunan karatu", "kiwix-server-running-message": "Sabar Kiwix tana gudana kuma ana iya samun dama ga cibiyar sadarwar gida a:", "kiwix-server-description": "Fara uwar garken yana ba da damar wasu kwamfutoci a cikin hanyar sadarwar gida don samun damar ɗakin karatu na Kiwix tare da madaidaicin burauzar gidan yanar gizo.", "fullscreen-notification": "Yanzu kuna cikin yanayin cikakken allo. Latsa ESC don barin!", "online-files": "Fayilolin Kan layi", "local-files": "Fayilolin gida", "category": "Rukuni", "language": "Harshe", "hide": "Ɓoye", "open-in-browser": "Bude a browser", "start-kiwix-server": "Fara Sabar Kiwix", "stop-kiwix-server": "Dakatar da Sabar Kiwix", "all": "Duka", "fulltext-search": "Binciken cikakken rubutu", "pictures": "Hotuna", "videos": "Bidiyo", "ftindex": "Cikakken rubutun", "details": "Cikakken labarin", "yes": "eh", "no": "a'a", "ok": "ok", "no-filter": "babu tacewa", "open-link-in-web-browser": "Bude hanyar haɗi a cikin burauzar yanar gizo", "open-link-new-tab": "Bude mahadar a sabon shafi?", "download-dir-dialog-title": "Shin kun tabbata kuna so ku canza kundin saukewa?", "download-dir-dialog-msg": "Sabuwar hanyar duba jagorar za ta kasance:\n{{DIRECTORY}}", "invalid-port": "Rami marar inganci", "zim-open-fail-title": "Fayil mara inganci", "zim-open-fail-text": "Ba za a iya buɗe fayil ɗin ZIM {{ZIM}} yadda ya kamata ba. Za a cire shi daga ɗakin karatu.", "monitor-dir-dialog-title": "Shin kun tabbata kuna son canza kundin adireshi?", "monitor-dir-dialog-msg": "Sabuwar hanyar duba jagorar za ta kasance:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Shin kun tabbata kuna son share kundin adireshi?", "monitor-clear-dir-dialog-msg": "Wannan zai dakatar da duba kundin adireshi don sabbin fayilolin ZIM.", "monitor-directory-tooltip": "Duk fayilolin ZIM da ke cikin wannan kundin za a ƙara su ta atomatik zuwa ɗakin karatu.", "next-tab": "Matsar zuwa shafi na gaba", "previous-tab": "Ka matsa zuwa shafin da ya gabata", "cancel-download": "Ka soke saukewa", "cancel-download-text": "Shin kun tabbata kuna son soke zazzagewar {{ZIM}}?", "delete-book": "Share littafin", "delete-book-text": "Shin kun tabbata kuna son share {{ZIM}}?", "download-storage-error": "Kuskuren Ma'aji", "download-storage-error-text": "Tsarin ba shi da isasshen ma'aji.", "download-unavailable": "Saukewa Ba a samu ba", "download-unavailable-text": "Wannan saukewa ba ya samuwa.", "open-book": "Bude littafi", "download-book": "Sauke littafin", "pause-download": "Dakatar da saukewa", "resume-download": "Ci gaba da saukewa", "open-folder": "Bude fayil", "couldnt-open-location": "Ba za a iya bude wurin ba", "couldnt-open-location-text": "Kiwix ba zai iya bude folder ba {{FOLDER}}", "move-files-to-trash": "Matsar da fayilolin da aka goge zuwa sharar gida", "move-files-to-trash-text": "Wannan aikin zai motsa fayil ɗin zuwa sharar gida.", "perma-delete-files-text": "Wannan aikin zai share fayil ɗin har abada.", "clear-filter": "Share abubuwan tacewa a halin yanzu", "language-searcher-placeholder": "Harshen tacewa", "category-searcher-placeholder": "Nau'in tacewa", "content-type-searcher-placeholder": "Nau'in abun ciki na tacewa", "no-details": "Gabatarwa kawai", "no-pictures": "Babu Hotuna", "no-videos": "Babu Bidiyo" } kiwix-desktop-2.4.1/resources/i18n/he.json000066400000000000000000000250111473106011000203700ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Amire80", "McDutchie", "Steeve815", "YaronSh" ] }, "name": "עברית", "error-title": "שגיאה", "error-downloader-window-title": "לא ניתן ליצור מנגנון הורדה", "error-downloader-launch-message": "אי אפשר לטעון מנגנון הורדה, Kiwix לשולחן העבודה יופעל אך יכולות ההורדה לא תפעלנה!", "error-launch-server-message": "אירעה שגיאה!", "error-archive": "לא ניתן לקבל את הארכיון", "error-opening-file": "אירעה שגיאה בפתיחת הקובץ.", "open-zim": "פתיחת קובץ ZIM", "local-kiwix-server": "שרת Kiwix מקומי", "random-article": "ערך אקראי", "random-article-error": "פתיחת ערך אקראי לא עבדה.", "home-page": "דף הבית", "main-menu": "תפריט ראשי", "print": "הדפסה", "print-page-error": "אירעה שגיאה בעת הדפסה.", "new-tab": "כרטיסייה חדשה", "close-tab": "סגירת לשונית", "close": "סגירה", "reopen-closed-tab": "פתיחת הלשונית שנסגרה מחדש", "browse-library": "עיון בספרייה", "open-file": "פתיחת קובץ", "save-file": "שמירת קובץ", "open-recent": "פתיחת אחרון", "search-article": "חיפוש ערך", "search-in-library": "חיפוש בספרייה", "find-in-page": "איתור בעמוד", "set-fullscreen": "הגדרת מסך מלא", "quit-fullscreen": "יציאה ממסך מלא", "table-of-content": "תוכן עניינים", "add-bookmark": "הוספה לרשימת הקריאה", "remove-bookmark": "הסרה מרשימת הקריאה", "reading-list": "רשימת קריאה", "zoom-in": "להתקרב", "zoom-out": "להתרחק", "zoom-reset": "איפוס תקריב", "help": "עזרה", "feedback": "משוב", "report-a-bug": "דיווח על תקלה", "request-a-feature": "לבקש יכולת", "about-kiwix": "על אודות Kiwix", "donate-to-support-kiwix": "ניתן לתרום כדי לתמוך ב־Kiwix", "exit": "יציאה", "save-file-as-window-title": "שמירת הקובץ בשם", "download-finished": "ההורדה הסתיימה", "download-finished-message": "המסמך התקבל.", "file": "קובץ", "edit": "עריכה", "view": "תצוגה", "tools": "כלים", "window-title": "ספרייה - Kiwix", "search": "חיפוש", "browse-directory": "עיון בספרייה", "settings": "הגדרות", "back": "חזרה", "forward": "קדימה", "search-files": "חיפוש קבצים", "title": "כותרת", "size": "גודל", "date": "תאריך", "content-type": "סוג התוכן", "reset-sort": "איפוס מיון", "open": "פתיחה", "delete": "מחיקה", "download": "הורדה", "resume": "המשך", "pause": "השהיה", "cancel": "ביטול", "apply": "החלה", "port-for-local-kiwix-server-setting": "פתחה לשרת Kiwix מקומי", "zoom-level-setting": "רמת תקריב כברירת מחדל", "download-directory-setting": "תיקיית הורדה", "monitor-directory-setting": "תיקיית ניטור", "reset": "איפוס", "clear": "ניקוי", "browse": "עיון", "about-kiwix-desktop-title": "Kiwix לשולחן העבודה", "about-kiwix-desktop-description": "קיוויקס מאפשר לך לקחת אתך את ויקיפדיה לכל מקום שהוא! בסירה, באמצע שום מקום או בכלא, קיוויקס מעניק לך גישה לכל הידע האנושי. אין צורך באינטרנט, הכול מאוחסן אצלך במחשב.", "about-learn-more-about-kiwix": "מידע נוסף אודות Kiwix", "about-release-title": "מהדורה", "about-source-code": "תכנה זו מופצת בכפוף לתנאי גרסה 3 של הרישיון הציבורי הכללי של גנו. ניתן לצפות בקוד המקור ב־Github.", "about-version": "גרסה: {{VERSION}}", "about-reporting-problem-title": "דיווח תקלות", "about-report-issue": "כדי לדווח על תקלה, עליך בקר בעוקב התקלות של Kiwix לשולחן העבודה ולהוסיף דיווח שמתאר את הבעיה שלך.", "about-report-issue-2": "נא לציין בדיווח את מספר הגרסה.", "about-libraries-title": "ספריות", "kiwix-server-running-message": "שרת ה־Kiwix פעיל וניתן לגשת אליו דרך הרשת המקומית בכתובת:", "kiwix-server-description": "הפעלת שרת מאפשרת למחשבים אחרים ברשת המקומית לגשת לספריית ה־Kiwix שלך דרך דפדפן אינטרנט תקני.", "fullscreen-notification": "הגדלת למסך מלא. ESC ליציאה!", "online-files": "קבצים מקוונים", "local-files": "קבצים מקומיים", "category": "קטגוריה", "language": "שפה", "hide": "הסתרה", "open-in-browser": "פתיחה בדפדפן", "start-kiwix-server": "הפעלת שרת Kiwix", "stop-kiwix-server": "עצירת שרת Kiwix", "all": "הכול", "all_ips": "הכול - מצב שני תקנים (Dual Stack)", "ipv4": "מצב IPv4 בלבד", "ipv6": "מצב IPv6 בלבד", "fulltext-search": "חיפוש טקסט מלא", "pictures": "תמונות", "videos": "סרטונים", "ftindex": "מפתח כל הטקסט", "details": "ערך מלא", "yes": "כן", "no": "לא", "ok": "אישור", "no-filter": "ללא מסנן", "open-link-in-web-browser": "פתיחת קישור בדפדפן", "open-link-new-tab": "פתיחת קישור בלשונית חדשה", "download-dir-dialog-title": "להחליף את תיקיית ההורדה?", "download-dir-dialog-msg": "נתיב תיקיית ההורדה החדש הוא:\n{{DIRECTORY}}", "invalid-port": "פתחה שגויה", "zim-open-fail-title": "קובץ בלתי־תקין", "zim-open-fail-text": "קובץ ה־ZIM בשם {{ZIM}} אינו יכול להיפתח באופן הולם. הוא יוסר מהספרייה שלך.", "monitor-dir-dialog-title": "האם ברצונך באמת לשנות את תיקיית הניטור?", "monitor-dir-dialog-msg": "הנתיב החדש לתיקיית הניתור יהיה:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "האם ברצונך באמת לנקות את תיקיית הניטור?", "path-was-copied": "הנתיב הועתק", "monitor-clear-dir-dialog-msg": "זה יפסיק לדגום את תיקיית הניטור ולחפש בה קובצי ZIM חדשים.", "monitor-directory-tooltip": "כל קובצי ה־ZIM בתיקייה הזאת יוספו אוטומטית לספרייה.", "next-tab": "לעבור ללשונית הבאה", "previous-tab": "לעבור ללשונית הקודמת", "cancel-download": "ביטול הורדה", "cancel-download-text": "האם באמת לבטל את ההורדה של {{ZIM}}?", "delete-book": "מחיקת ספר", "delete-book-text": "האם באמת למחוק את {{ZIM}}?", "download-storage-error": "שגיאת אחסון", "download-storage-error-text": "במערכת אין מספיק אחסון זמין.", "download-exceeds-max-file-size": "גודל ההורדה חורג מגודל הקובץ המרבי הנתמך על־ידי מערכת הקבצים ביעד.", "download-dir-missing": "תיקיית ההורדות לא קיימת.", "download-dir-not-writable": "תיקיית ההורדות נעולה לכתיבה.", "download-unavailable": "הורדה אינה זמינה", "download-unavailable-text": "ההורדה הזאת אינה זמינה.", "open-book": "פתיחת ספר", "download-book": "הורדת ספר", "pause-download": "עצירת ההורדה", "resume-download": "המשך ההורדה", "open-folder": "פתיחת תיקייה", "couldnt-open-location": "לא ניתן לפתוח את המיקום", "couldnt-open-location-text": "קיוויקס לא הצליח לפתוח את התיקייה {{FOLDER}}", "move-files-to-trash": "להעביר קבצים שנמחקים לאשפה", "move-files-to-trash-text": "הפעולה הזאת תעביר את הקובץ לאשפה.", "perma-delete-files-text": "הפעולה האת תמחק את הקובץ לתמיד.", "clear-filter": "ניקוי המסננים שמוגדרים כעת", "language-searcher-placeholder": "סינון לפי שפה", "category-searcher-placeholder": "סינון לפי קטגוריה", "content-type-searcher-placeholder": "סינון לפי סוג תוכן", "no-details": "הקדמה בלבד", "no-pictures": "ללא תמונות", "no-videos": "ללא סרטים", "open-previous-tabs-at-startup": "לפתוח את הלשוניות הקודמות בעת ההפעלה", "preview-book-in-web-browser": "תצוגה מקדימה של ספר בדפדפן", "file-not-found-title": "קובץ ה־ZIM לא נמצא", "file-not-found-text": "קובץ ה־ZIM אינו קיים או אינו קריא", "zim-id": "מזהה ה־Zim", "zim-name": "שם ה־Zim", "zim-path": "נתיב קובץ ה־Zim", "bad-zim-file-error-page-title": "קובץ ZIM בלתי־תקין", "bad-zim-file-error-page-text": "קובץ ה־ZIM בלתי־תקין או מקולקל.", "zim-entry-path": "נתיב כניסה ל־ZIM", "export-reading-list": "יצוא רשימת קריאה", "export-reading-list-error": "אירעה שגיאה בעת יצוא רשימת קריאה.", "import-reading-list": "יבוא רשימת קריאה", "import-reading-list-error": "אירעה שגיאה בעת יבוא רשימת קריאה.", "disable-sandbox": "קיוויקס הופעל מכונן רשת. זה ידוע כגורם לבעיות תאימות בשל ארגז החול של העיון (browsing sandboxing). כתוצאה מזה, ארגז החול יושבת. האם להמשיך?", "save-page-as": "שמירה בשם...", "portable-disabled-tooltip": "הפונקציה מושבתת במצב נייד", "scroll-next-tab": "לגלול ללשונית הבאה", "scroll-previous-tab": "לגלול ללשונית הקודמת", "kiwix-search": "חיפוש קיוויקס", "search-options": "אפשרויות חיפוש", "read-article": "להקריא את הערך", "read-text": "להקריא את הטקסט שנבחר", "read-stop": "להפסיק להקריא", "stop": "עצירה", "voice": "קול", "select-read-voice": "בחירת קול ההקראה", "select-read-language": "בחירת שפת ההקראה", "save-or-open": "שמירה או פתיחה של קובץ", "save-or-open-text": "מה קיוויקס צריך לעשות עם הקובץ הזה?" } kiwix-desktop-2.4.1/resources/i18n/hi.json000066400000000000000000000277351473106011000204130ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Abijeet Patro", "Juuz0" ] }, "name": "हिन्दी", "error-title": "त्रुटि", "error-downloader-window-title": "डाउनलोडर बनाने में असमर्थ", "error-downloader-launch-message": "डाउनलोडर लॉन्च करना असंभव है, किविक्स-डेस्कटॉप शुरू हो जाएगा लेकिन सभी डाउनलोड फ़ंक्शन काम नहीं करेंगे!", "error-launch-server-message": "एक त्रुटि आई।", "error-archive": "पुरालेख नहीं मिल सका", "open-zim": "ZIM फ़ाइल खोलें", "local-kiwix-server": "स्थानीय किविक्स सर्वर", "random-article": "यादृच्छिक लेख", "random-article-error": "एक यादृच्छिक लेख खोलने में विफल.", "home-page": "मुख पृष्ठ", "main-menu": "मुख्य मेन्यू", "print": "प्रिंट करें", "print-page-error": "मुद्रण करते समय कोई त्रुटि उत्पन्न हुई है.", "new-tab": "नया टैब", "close-tab": "टैब बंद करें", "close": "बंद करें", "reopen-closed-tab": "बंद टैब पुनः खोलें", "browse-library": "पुस्तकालय ब्राउज़ करें", "open-file": "फ़ाइल खोलें", "open-recent": "हाल ही वाला खोलें", "search-article": "लेख खोजें", "search-in-library": "पुस्तकालय में खोजें", "find-in-page": "पृष्ठ में ढूंढें", "set-fullscreen": "पूर्ण स्क्रीन सेट करें", "quit-fullscreen": "पूर्ण स्क्रीन छोड़ें", "table-of-content": "विषयसूची", "reading-list": "पढ़ने की सूची", "zoom-in": "आकार बढ़ाएँ", "zoom-out": "आकार घटाएँ", "zoom-reset": "ज़ूम रीसेट करें", "help": "सहायता", "feedback": "आपके सुझाव", "report-a-bug": "समस्या को सूचित करें", "request-a-feature": "एक सुविधा का अनुरोध करें", "about-kiwix": "किवीक्स के बारे में", "donate-to-support-kiwix": "किवीक्स का समर्थन करने के लिए दान करें", "exit": "निकास", "save-file-as-window-title": "फ़ाइल को इस रूप में सहेजें", "download-finished-message": "दस्तावेज़ डाउनलोड कर लिया गया है।", "file": "फ़ाइल", "edit": "संपादित करें", "view": "देखें", "tools": "उपकरण", "window-title": "पुस्तकालय - किवीक्स", "search": "खोजें", "browse-directory": "निर्देशिका ब्राउज़ करें", "settings": "सेटिंग्स", "back": "पीछे", "forward": "आगे", "search-files": "फ़ाइलें खोजें", "title": "शीर्षक", "size": "आकार", "date": "दिनांक", "content-type": "सामग्री पृष्ठ", "reset-sort": "क्रम रीसेट करें", "open": "खोलें", "delete": "हटाएँ", "download": "डाउनलोड करें", "resume": "दुबारा शुरू करें", "pause": "थामें", "cancel": "रद्द करें", "apply": "लागू करें", "port-for-local-kiwix-server-setting": "स्थानीय किविक्स सर्वर के लिए पोर्ट", "zoom-level-setting": "डिफ़ॉल्ट ज़ूम स्तर", "download-directory-setting": "यहाँ डाउनलोड करे", "monitor-directory-setting": "इसकी निगरानी करें", "reset": "रीसेट करें", "clear": "खाली करें", "browse": "ब्राउज़", "about-kiwix-desktop-title": "किविक्स डेस्कटॉप", "about-kiwix-desktop-description": "किविक्स आपको जहाँ भी आप जाते हैं, संपूर्ण विकिपीडिया उपलब्ध रखने की अनुमति देता है! नाव पर, बीच रास्ते में, या जेल में, किविक्स आपको सभी मानवीय ज्ञान तक पहुंच प्रदान करता है। आपको इंटरनेट की आवश्यकता नहीं है, सब कुछ आपके कंप्यूटर पर संग्रहीत है।", "about-learn-more-about-kiwix": "कीविक्स के बारे में और जानें", "about-release-title": "प्रकाशन", "about-source-code": "यह सॉफ़्टवेयर GNU जनरल पब्लिक लाइसेंस संस्करण 3 की शर्तों के तहत जारी किया गया है। Github पर स्रोत कोड देखें।", "about-version": "संस्करण : {{VERSION}}", "about-reporting-problem-title": "समस्या की सूचना दें", "about-report-issue": "किसी समस्या को खोलने के लिए, किविक्स-डेस्कटॉप समस्या ट्रैकर पर जाएँ और अपनी समस्या का वर्णन करने वाला एक मुद्दा खोलें।", "about-report-issue-2": "कृपया अंक में संस्करण का उल्लेख करें।", "about-libraries-title": "पुस्तकालय", "kiwix-server-running-message": "कीविक्स सर्वर चल रहा है और स्थानीय नेटवर्क में पहुँचा जा सकता हैः", "kiwix-server-description": "सर्वर शुरू करने से स्थानीय नेटवर्क में अन्य कंप्यूटरों को एक मानक वेब ब्राउज़र के साथ आपकी कीविक्स लाइब्रेरी तक पहुंचने की अनुमति मिलती है।", "fullscreen-notification": "अब आप पूर्ण स्क्रीन मोड में हैं. छोड़ने के लिए ESC दबाएँ!", "online-files": "ऑनलाइन फ़ाइलें", "local-files": "स्थानीय फ़ाइलें", "category": "श्रेणी", "language": "भाषा", "hide": "छुपाएँ", "open-in-browser": "ब्राउज़र में खोलें", "start-kiwix-server": "किविक्स सर्वर प्रारंभ करें", "stop-kiwix-server": "कीविक्स सर्वर को रोकें", "all": "सभी", "fulltext-search": "पूरा पाठ खोजें", "pictures": "चित्र", "videos": "विडियो", "ftindex": "पूर्णपाठ अनुक्रमणिका", "details": "पूरा लेख", "yes": "हाँ", "no": "नहीं", "ok": "ठीक है", "no-filter": "कोई फिल्टर नहीं", "open-link-in-web-browser": "वेब ब्राउज़र में लिंक खोलें", "download-dir-dialog-title": "क्या आप निश्चित रूप से डाउनलोड निर्देशिका को बदलना चाहते हैं", "download-dir-dialog-msg": "नई डाउनलोड निर्देशिका पथ होगा:\n{{DIRECTORY}}", "invalid-port": "अमान्य पोर्ट", "zim-open-fail-title": "अमान्य फ़ाइल", "zim-open-fail-text": "ज़िम फ़ाइल {{ZIM}} ठीक से नहीं खोली जा सकती है। इसे आपके पुस्तकालय से हटा दिया जाएगा।", "monitor-dir-dialog-title": "क्या आप निश्चित रूप से मॉनिटर निर्देशिका को बदलना चाहते हैं", "monitor-dir-dialog-msg": "नया मॉनिटर निर्देशिका पथ होगा:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "क्या आप निश्चित रूप से मॉनिटर निर्देशिका को साफ़ करना चाहते हैं", "monitor-clear-dir-dialog-msg": "यह नई ZIM फ़ाइलों के लिए मॉनिटर निर्देशिका की जाँच करना बंद कर देगा।", "monitor-directory-tooltip": "इस निर्देशिका में सभी ज़िम फ़ाइलों को स्वचालित रूप से पुस्तकालय में जोड़ा जाएगा।", "next-tab": "अगले टैब पर जाएँ", "previous-tab": "पिछले टैब पर जाएँ", "cancel-download": "डाउनलोड रद्द करें", "cancel-download-text": "क्या आप निश्चित रूप से {{ZIM}} का डाउनलोड रद्द करना चाहते हैं?", "delete-book": "पुस्तक हटाएँ", "delete-book-text": "क्या आप वाकई {{ZIM}} को हटाना चाहते हैं?", "download-storage-error": "भंडारण त्रुटि", "download-storage-error-text": "सिस्टम में पर्याप्त भंडारण उपलब्ध नहीं है।", "download-unavailable": "डाउनलोड अनुपलब्ध", "download-unavailable-text": "यह डाउनलोड अनुपलब्ध है।", "open-book": "किताब खोले", "download-book": "पुस्तक डाउनलोड करें", "pause-download": "डाउनलोड रोकें", "resume-download": "डाउनलोड फिर से शुरू करें", "open-folder": "फोल्डर खोलें", "couldnt-open-location": "स्थान नहीं खुल सका", "couldnt-open-location-text": "किविक्स फ़ोल्डर {{FOLDER}} खोलने में सक्षम नहीं है", "move-files-to-trash": "हटाई गई फ़ाइलों को ट्रैश में ले जाएं", "move-files-to-trash-text": "यह क्रिया फ़ाइल को ट्रैश में ले जाएगी.", "perma-delete-files-text": "यह क्रिया फ़ाइल को स्थायी रूप से हटा देगी।", "clear-filter": "वर्तमान में सेट किए गए फिल्टर को साफ़ करें", "language-searcher-placeholder": "भाषा अनुसार छानें", "category-searcher-placeholder": "श्रणी के अनुसार छानें", "content-type-searcher-placeholder": "सामग्री प्रकार छानें", "no-details": "केवल परिचय", "no-pictures": "कोई चित्र नहीं", "no-videos": "कोई चलचित्र नहीं" } kiwix-desktop-2.4.1/resources/i18n/hy.json000066400000000000000000000026111473106011000204150ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Ajeje Brazorf", "Kareyac", "McDutchie", "Սերգեյ Սաֆարյան" ] }, "name": "Հայերեն", "home-page": "Հիմնական էջ", "main-menu": "Հիմնական ընտրացանկ", "print": "Տպել", "find-in-page": "Գտնել էջում", "zoom-in": "Խոշորացնել", "zoom-out": "Հեռվացնել", "help": "Օգնություն", "exit": "Դուրս գալ", "file": "Նիշք", "edit": "Խմբագրել", "view": "Դիտել", "tools": "Գործիքներ", "search": "Որոնել", "settings": "Կարգավորումներ", "back": "Հետ", "forward": "Առաջ", "search-files": "Որոնել նիշքեր", "title": "Վերնագիր", "size": "Չափ", "date": "Ամսաթիվ", "open": "Բացել", "delete": "Ջնջել", "download": "Ներբեռնել", "pause": "Դադար", "cancel": "Չեղարկել", "apply": "Կիրառել", "about-reporting-problem-title": "Հաղորդել խնդիրների մասին", "about-libraries-title": "Գրադարաններ", "category": "Կատեգորիա", "language": "Լեզու", "hide": "Թաքցնել", "all": "Բոլորը", "yes": "այո", "no": "ոչ", "language-searcher-placeholder": "Զտել ըստ լեզվի", "category-searcher-placeholder": "Զտել ըստ կատեգորիայի", "no-videos": "Տեսանյութ չկա" } kiwix-desktop-2.4.1/resources/i18n/ia.json000066400000000000000000000212331473106011000203670ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie" ] }, "name": "Interlingua", "error-title": "Error", "error-downloader-window-title": "Non pote crear discargator", "error-downloader-launch-message": "Impossibile lancear le discargator. Kiwix-desktop se initiara ma tote le functiones de discargamento non functionara!", "error-launch-server-message": "Un error ha occurrite!", "error-archive": "Non poter obtener le archivo", "open-zim": "Aperir file ZIM", "local-kiwix-server": "Servitor Kiwix local", "random-article": "Articulo aleatori", "random-article-error": "Non poteva aperir un articulo aleatori.", "home-page": "Pagina principal", "main-menu": "Menu principal", "print": "Imprimer", "print-page-error": "Un error ha occurrite durante le impression.", "new-tab": "Nove scheda", "close-tab": "Clauder scheda", "close": "Clauder", "reopen-closed-tab": "Reaperir scheda claudite", "browse-library": "Explorar bibliotheca", "open-file": "Aperir file", "open-recent": "Aperir recente", "search-article": "Cercar articulo", "search-in-library": "Cercar in bibliotheca", "find-in-page": "Cercar in pagina", "set-fullscreen": "Entrar in plen schermo", "quit-fullscreen": "Exir del plen schermo", "table-of-content": "Tabula de contento", "add-bookmark": "Adder al lista de lectura", "remove-bookmark": "Remover del lista de lectura", "reading-list": "Lista de lectura", "zoom-in": "Zoom avante", "zoom-out": "Zoom retro", "zoom-reset": "Reinitialisar zoom", "help": "Adjuta", "feedback": "Commentario", "report-a-bug": "Reportar un defecto", "request-a-feature": "Requestar un function", "about-kiwix": "A proposito de Kiwix", "donate-to-support-kiwix": "Donar pro sustener Kiwix", "exit": "Exir", "save-file-as-window-title": "Salveguardar file como", "download-finished-message": "Le documento ha essite discargate.", "file": "File", "edit": "Modificar", "view": "Vider", "tools": "Instrumentos", "window-title": "Bibliotheca – Kiwix", "search": "Recerca", "browse-directory": "Explorar directorio", "settings": "Parametros", "back": "Retro", "forward": "Avante", "search-files": "Cercar files", "title": "Titulo", "size": "Grandor", "date": "Data", "content-type": "Typo de contento", "reset-sort": "reinitialisar ordinamento", "open": "Aperir", "delete": "Deler", "download": "Discargar", "resume": "Reprender", "pause": "Pausar", "cancel": "Cancellar", "apply": "Applicar", "port-for-local-kiwix-server-setting": "Porto pro le servitor Kiwix local", "zoom-level-setting": "Nivello de zoom predefinite", "download-directory-setting": "Directorio de discargamento", "monitor-directory-setting": "Surveliar directorio", "reset": "Reinitialisar", "clear": "Rader", "browse": "Explorar", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix te permitte haber tote Wikipedia a portata de mano ubique tu va! Sur un barca, in le medio de nulle parte o in prision, Kiwix te da accesso a tote le cognoscentia human. Tu non ha besonio de Internet, toto es immagazinate sur tu computator.", "about-learn-more-about-kiwix": "Leger plus sur Kiwix", "about-release-title": "Edition", "about-source-code": "Iste software es publicate sub le terminos del Licentia Public General de GNU, version 3. Consulta le codice fonte sur GitHub.", "about-version": "Version: {{VERSION}}", "about-reporting-problem-title": "Signalar problemas", "about-report-issue": "Pro signalar un problema, visita le traciator de problemas de Kiwix-desktop e aperi un incidente que describe tu problema.", "about-report-issue-2": "Per favor mentiona le version in le incidente.", "about-libraries-title": "Bibliothecas", "kiwix-server-running-message": "Le servitor Kiwix es in execution e disponibile in le rete local a:", "kiwix-server-description": "Initiar un servitor permitte a altere computatores in rete local acceder a tu bibliotheca Kiwix con un navigator web standard.", "fullscreen-notification": "Tu es ora in modo de plen schermo. Preme ESC pro exir!", "online-files": "Files in linea", "local-files": "Files local", "category": "Categoria", "language": "Lingua", "hide": "Celar", "open-in-browser": "Aperir in navigator", "start-kiwix-server": "Initiar servitor Kiwix", "stop-kiwix-server": "Stoppar servitor Kiwix", "all": "Toto", "fulltext-search": "Recerca in texto complete", "pictures": "Imagines", "videos": "Videos", "ftindex": "Indice de texto complete", "details": "Articulo complete", "yes": "si", "no": "no", "ok": "ok", "no-filter": "necun filtro", "open-link-in-web-browser": "Aperir ligamine in navigator web", "open-link-new-tab": "Aperir ligamine in nove scheda", "download-dir-dialog-title": "Es tu secur de voler cambiar le directorio de discargamento?", "download-dir-dialog-msg": "Le nove directorio de discargamento essera:\n{{DIRECTORY}}", "invalid-port": "Porto non valide", "zim-open-fail-title": "File non valide", "zim-open-fail-text": "Le file ZIM ({{ZIM}}) non pote esser aperite correctemente. Illo essera removite de tu bibliotheca.", "monitor-dir-dialog-title": "Es tu secur de voler cambiar le directorio de surveliantia?", "monitor-dir-dialog-msg": "Le nove directorio de surveliantia essera:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Es tu secur de voler rader le directorio de surveliantia?", "path-was-copied": "Le percurso ha essite copiate", "monitor-clear-dir-dialog-msg": "Isto cessara le verification del directorio de surveliantia pro nove files ZIM.", "monitor-directory-tooltip": "Tote le files ZIM in iste directorio essera automaticamente addite al bibliotheca.", "next-tab": "Passar al scheda sequente", "previous-tab": "Passar al scheda precedente", "cancel-download": "Cancellar discargamento", "cancel-download-text": "Es tu secur de voler cancellar le discargamento de {{ZIM}}?", "delete-book": "Deler libro", "delete-book-text": "Es tu secur de voler deler {{ZIM}}?", "download-storage-error": "Error de immagazinage", "download-storage-error-text": "Le systema non ha bastante spatio de immagazinage disponibile.", "download-exceeds-max-file-size": "Le grandor del discargamento excede le dimension maxime de files supportate per le systema de files del destination.", "download-dir-missing": "Le directorio de discargamento non existe.", "download-dir-not-writable": "Necun permission de scriptura pro le directorio de discargamento.", "download-unavailable": "Discargamento indisponibile", "download-unavailable-text": "Iste discargamento non es disponibile.", "open-book": "Aperir libro", "download-book": "Discargar libro", "pause-download": "Pausar discargamento", "resume-download": "Reprender discargamento", "open-folder": "Aperir dossier", "couldnt-open-location": "Non poteva aperir le loco", "couldnt-open-location-text": "Kiwix non pote aperir le dossier {{FOLDER}}", "move-files-to-trash": "Displaciar files delite al corbe a papiro", "move-files-to-trash-text": "Iste action displaciara le file al corbe a papiro.", "perma-delete-files-text": "Iste action delera permanentemente le file.", "clear-filter": "Rader le filtros actualmente definite", "language-searcher-placeholder": "Filtrar per lingua", "category-searcher-placeholder": "Filtrar per categoria", "content-type-searcher-placeholder": "Filtrar per typo de contento", "no-details": "Introduction solmente", "no-pictures": "Necun imagine", "no-videos": "Necun video", "open-previous-tabs-at-startup": "Aperir previe schedas al initio", "preview-book-in-web-browser": "Previsualisar libro in navigator web", "file-not-found-title": "File ZIM non trovate", "file-not-found-text": "Le file ZIM non existe o non es legibile", "zim-id": "ID del ZIM", "zim-name": "Nomine del ZIM", "zim-path": "Percurso al file ZIM", "bad-zim-file-error-page-title": "File ZIM non valide", "bad-zim-file-error-page-text": "Le file ZIM non es valide o ha essite corrumpite.", "zim-entry-path": "Percurso de entrata ZIM", "export-reading-list": "Exportar lista de lectura", "export-reading-list-error": "Un error ha occurrite durante le exportation del lista de lectura.", "import-reading-list": "Importar lista de lectura", "import-reading-list-error": "Un error ha occurrite durante le importation del lista de lectura.", "disable-sandbox": "Kiwix ha essite lanceate desde un disco de rete. Isto es cognoscite pro causar problemas de compatibilitate con le isolator (sandbox) del navigator del web. Como resultato, le isolator essera disactivate. Vole tu continuar?", "save-page-as": "Salveguardar como…", "portable-disabled-tooltip": "Function disactivate in modo portabile", "scroll-next-tab": "Rolar al scheda sequente", "scroll-previous-tab": "Rolar al scheda precedente" } kiwix-desktop-2.4.1/resources/i18n/id.json000066400000000000000000000217131473106011000203750ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Akmaie Ajam", "Esiahaan", "Farras", "McDutchie", "Veracious" ] }, "name": "Bahasa Indonesia", "error-title": "Galat", "error-downloader-window-title": "Tidak dapat membuat pengunduh", "error-downloader-launch-message": "Tidak dapat meluncurkan pengunduh, Kiwix-desktop akan mulai tetapi semua fungsi pengunduhan tidak berfungsi!", "error-launch-server-message": "Telah terjadi kesalahan!", "error-archive": "Gagal memuat arsip", "error-opening-file": "Ada kesalahan saat membuka berkas.", "open-zim": "Buka Berkas ZIM", "local-kiwix-server": "Server Kiwix Lokal", "random-article": "Artikel Acak", "random-article-error": "Gagal membuka artikel acak.", "home-page": "Beranda", "main-menu": "Menu utama", "print": "Cetak", "print-page-error": "Terjadi kesalahan saat mencetak.", "new-tab": "Tab baru", "close-tab": "Tutup tab", "close": "Tutup", "reopen-closed-tab": "Buka kembali tab yang telah tertutup", "browse-library": "Lihat isi perpustakaan", "open-file": "Buka file", "save-file": "Simpan berkas", "open-recent": "Buka yang terbaru", "search-article": "Cari artikel", "search-in-library": "Cari di perpustakaan", "find-in-page": "Temukan di halaman", "set-fullscreen": "Setel layar penuh", "quit-fullscreen": "Keluar dari layar penuh", "table-of-content": "Daftar isi", "add-bookmark": "Tambah ke daftar bacaan", "remove-bookmark": "Hapus dari daftar bacaan", "reading-list": "Daftar bacaan", "zoom-in": "Perbesar", "zoom-out": "Perkecil", "zoom-reset": "Atur ulang zoom", "help": "Bantuan", "feedback": "Umpan balik", "report-a-bug": "Laporkan kesalahan", "request-a-feature": "Minta fitur", "about-kiwix": "Tentang Kiwix", "donate-to-support-kiwix": "Berikan donasi untuk mendukung Kiwix", "exit": "Keluar", "save-file-as-window-title": "Simpan Berkas sebagai", "download-finished": "Unduh Selesai", "download-finished-message": "Dokumen telah diunduh.", "file": "File", "edit": "Sunting", "view": "Lihat", "tools": "Peralatan", "window-title": "Perpustakaan - Kiwix", "search": "Cari", "browse-directory": "Telusuri Direktori", "settings": "Pengaturan", "back": "Kembali", "forward": "Teruskan", "search-files": "Cari berkas", "title": "Judul", "size": "Ukuran", "date": "Tanggal", "content-type": "Jenis konten", "reset-sort": "atur ulang pengurutan", "open": "Buka", "delete": "Hapus", "download": "Unduh", "resume": "Lanjutkan", "pause": "Jeda", "cancel": "Batal", "apply": "Terapkan", "port-for-local-kiwix-server-setting": "Port untuk server Kiwix lokal", "zoom-level-setting": "Tingkat zoom default", "download-directory-setting": "Direktori unduhan", "monitor-directory-setting": "Direktori pantauan", "reset": "Atur ulang", "clear": "Kosongkan", "browse": "Jelajahi", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix memungkinkan Anda memiliki seluruh Wikipedia dimanapun Anda berada! Di atas kapal, di tengah antah berantah, atau di penjara, Kiwix memberi Anda akses ke semua pengetahuan manusia. Anda tidak memerlukan Internet, semuanya tersimpan di komputer Anda.", "about-learn-more-about-kiwix": "Pelajari lebih lanjut tentang Kiwix", "about-release-title": "Rilis", "about-source-code": "Perangkat lunak ini dirilis berdasarkan ketentuan Lisensi Publik Umum GNU versi 3. Lihat kode sumber di Github .", "about-version": "Versi: {{VERSION}}", "about-reporting-problem-title": "Melaporkan masalah", "about-report-issue": "Untuk membuka masalah, kunjungi pelacak masalah Kiwix-desktop dan buka masalah yang menjelaskan permasalahan Anda.", "about-report-issue-2": "Harap sebutkan versi yang ada pada masalah tersebut.", "about-libraries-title": "Perpustakaan", "kiwix-server-running-message": "Server Kiwix sedang berjalan dan dapat diakses di jaringan lokal di:", "kiwix-server-description": "Memulai server memungkinkan komputer lain di jaringan lokal mengakses perpustakaan Kiwix Anda dengan peramban web standar.", "fullscreen-notification": "Anda sekarang berada dalam mode layar penuh. Tekan ESC untuk keluar!", "online-files": "File Online", "local-files": "Berkas Lokal", "category": "Kategori", "language": "Bahasa", "hide": "Sembunyikan", "open-in-browser": "Buka di browser", "start-kiwix-server": "Mulai Server Kiwix", "stop-kiwix-server": "Hentikan Server Kiwix", "all": "Semua", "all_ips": "Semua - Mode Tumpukan Ganda", "ipv4": "Mode Hanya IPv4", "ipv6": "Mode Hanya IPv6", "fulltext-search": "Pencarian teks lengkap", "pictures": "Gambar", "videos": "Video", "ftindex": "Indeks teks lengkap", "details": "Artikel lengkap", "yes": "ya", "no": "tidak", "ok": "ok", "no-filter": "tanpa filter", "open-link-in-web-browser": "Buka pranala di peramban web", "open-link-new-tab": "Buka pranala di tab baru", "download-dir-dialog-title": "Apakah Anda yakin ingin mengubah direktori unduhan?", "download-dir-dialog-msg": "Jalur direktori unduhan baru akan menjadi: \n{{DIRECTORY}}", "invalid-port": "Port tidak sah", "zim-open-fail-title": "Berkas tidak sah", "zim-open-fail-text": "Berkas ZIM {{ZIM}} tidak dapat dibuka dengan benar. Berkas ini akan dihapus dari pustaka Anda.", "monitor-dir-dialog-title": "Apakah Anda yakin ingin mengubah direktori pantauan?", "monitor-dir-dialog-msg": "Jalur direktori pantauan baru akan menjadi: \n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Apakah Anda yakin ingin menghapus direktori pantauan?", "path-was-copied": "Jalur telah disalin", "monitor-clear-dir-dialog-msg": "Ini akan menghentikan pemeriksaan direktori pantauan untuk berkas ZIM baru.", "monitor-directory-tooltip": "Semua berkas ZIM dalam direktori ini akan ditambahkan ke perpustakaan secara otomatis.", "next-tab": "Pindah ke tab berikutnya", "previous-tab": "Pindah ke tab sebelumnya", "cancel-download": "Batalkan unduhan", "cancel-download-text": "Apakah Anda yakin ingin membatalkan pengunduhan {{ZIM}}?", "delete-book": "Hapus buku", "delete-book-text": "Apakah Anda yakin ingin menghapus {{ZIM}}?", "download-storage-error": "Kesalahan Penyimpanan", "download-storage-error-text": "Sistem tidak memiliki penyimpanan yang cukup.", "download-exceeds-max-file-size": "Ukuran unduhan melebihi ukuran berkas maksimum yang didukung oleh sistem berkas target.", "download-dir-missing": "Direktori unduhan tidak ada.", "download-dir-not-writable": "Direktori unduhan tidak dapat ditulis.", "download-unavailable": "Unduh Tidak Tersedia", "download-unavailable-text": "Unduhan ini tidak tersedia.", "open-book": "Buka buku", "download-book": "Unduh buku", "pause-download": "Jeda unduhan", "resume-download": "Lanjutkan unduhan", "open-folder": "Buka folder", "couldnt-open-location": "Tidak dapat membuka lokasi", "couldnt-open-location-text": "Kiwix tidak dapat membuka folder {{FOLDER}}", "move-files-to-trash": "Pindahkan berkas yang dihapus ke tempat sampah", "move-files-to-trash-text": "Tindakan ini akan memindahkan berkas ke tempat sampah.", "perma-delete-files-text": "Tindakan ini akan menghapus berkas secara permanen.", "clear-filter": "Hapus filter yang saat ini ditetapkan", "language-searcher-placeholder": "Saring menurut bahasa", "category-searcher-placeholder": "Saring menurut kategori", "content-type-searcher-placeholder": "Saring menurut jenis konten", "no-details": "Hanya pengantar", "no-pictures": "Tanpa Gambar", "no-videos": "Tanpa Video", "open-previous-tabs-at-startup": "Buka tab sebelumnya saat memulai", "preview-book-in-web-browser": "Pratinjau buku di peramban web", "file-not-found-title": "Berkas ZIM Tidak Ditemukan", "file-not-found-text": "Berkas ZIM tidak ada atau tidak dapat dibaca", "zim-id": "Id ZIM", "zim-name": "Nama ZIM", "zim-path": "Jalur File ZIM", "bad-zim-file-error-page-title": "Berkas ZIM Tidak Sah", "bad-zim-file-error-page-text": "Berkas ZIM tidak sah atau rusak.", "zim-entry-path": "Jalur Masuk ZIM", "export-reading-list": "Ekspor daftar bacaan", "export-reading-list-error": "Ada kesalahan saat mengekspor daftar bacaan.", "import-reading-list": "Ekspor daftar bacaan", "import-reading-list-error": "Ada kesalahan saat mengimpor daftar bacaan.", "disable-sandbox": "Kiwix telah diluncurkan dari drive jaringan. Hal ini diketahui menyebabkan masalah kompatibilitas dengan isolasi keamanan (sandbox) peramban. Akibatnya, sandbox akan dinonaktifkan. Apakah Anda ingin melanjutkan?", "save-page-as": "Simpan Sebagai...", "portable-disabled-tooltip": "Fungsi dinonaktifkan dalam mode portabel", "scroll-next-tab": "Gulir ke tab berikutnya", "scroll-previous-tab": "Gulir ke tab sebelumnya", "kiwix-search": "Pencarian Kiwix", "search-options": "Opsi Pencarian", "read-article": "Baca artikel", "read-text": "Baca teks yang dipilih", "read-stop": "Berhenti membaca", "stop": "Berhenti", "voice": "Suara", "select-read-voice": "Pilih suara bacaan", "select-read-language": "Pilih bahasa bacaan", "save-or-open": "Simpan atau Buka berkas", "save-or-open-text": "Apa yang harus dilakukan Kiwix dengan berkas ini?" } kiwix-desktop-2.4.1/resources/i18n/ie.json000066400000000000000000000023031473106011000203700ustar00rootroot00000000000000{ "@metadata": { "authors": [ "OIS" ] }, "name": "Interlingue", "open-zim": "Aperter Zim", "print": "Printar", "new-tab": "Nov carte", "close-tab": "Cluder li carte", "browse-library": "Navigar li biblioteca", "open-file": "Aperter un file", "table-of-content": "Contenete", "zoom-in": "Agrandar", "zoom-out": "Diminuer", "help": "Auxilie", "report-a-bug": "Raportar un defecte", "about-kiwix": "Pri Kiwix", "exit": "Surtir", "file": "File", "edit": "Redacter", "view": "Vise", "tools": "Utensiles", "window-title": "Biblioteca - Kiwix", "search": "Serchar", "settings": "Preferenties", "title": "Titul", "size": "Grandor", "date": "Date", "open": "Aperter", "delete": "Deleter", "resume": "Reprender", "pause": "Pausar", "cancel": "Anullar", "apply": "Applicar", "browse": "Navigar", "about-version": "Version: {{VERSION}}", "about-libraries-title": "Bibliotecas", "local-files": "Local files", "hide": "Ocultar", "all": "Omni", "fulltext-search": "Plen-textual sercha", "pictures": "Images", "videos": "Videos", "ftindex": "Plen-textual index", "details": "Complet articul", "yes": "yes", "no": "no", "no-filter": "sin filtre", "invalid-port": "Ínvalid portu" } kiwix-desktop-2.4.1/resources/i18n/ig.json000066400000000000000000000161201473106011000203740ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Accuratecy051", "Akwugo", "Oby Ezeilo" ] }, "name": "Bekee", "error-title": "mmejọ", "error-downloader-window-title": "Enweghị ike ikepụta danloder", "error-downloader-launch-message": "Mgbe Enweghị ike ịnabata danloder, Kiwix-destop ga amalite mana ngwá ọrụ danlod agaghị arụ ọrụ.", "error-launch-server-message": "Enwere mmejọ gosịpụtara", "error-archive": "Enweghị ike inweta nke edebere", "open-zim": "Mehee faịlụ Zim", "local-kiwix-server": "Ihe nkesa Kiwix mpaghara", "random-article": "Edemede enweghị usoro", "random-article-error": "Emepeghị akụkọ enweghị usoro.", "home-page": "Peeji mbu", "main-menu": "Isi menu", "print": "Bipụta", "print-page-error": "Enwere mperi mgbe a na-ebi akwụkwọ.", "new-tab": "Taabụ ọhụrụ", "close-tab": "Mechie taabụ", "close": "Mechie", "reopen-closed-tab": "Mepee taabụ mechiri emechi", "browse-library": "Chọgharịa n'ọbá akwụkwọ", "open-file": "Mepee faịlụ", "open-recent": "Mepee nso nso a", "search-article": "Chọọ akụkọ", "search-in-library": "Chọọ n'ọbá akwụkwọ", "find-in-page": "chọta na ibe", "set-fullscreen": "Tọọ ihuenyo zuru oke", "quit-fullscreen": "Kwụsị ihuenyo zuru ezu", "table-of-content": "Tebulu ọdịnaya", "reading-list": "Ndetù ńwùzoro", "zoom-in": "Bugharịa", "zoom-out": "Wepụ ya", "zoom-reset": "Ntọgharị mbugharị", "help": "Enyemaka", "feedback": "Nzaghachi", "report-a-bug": "Kpesa ahụhụ", "request-a-feature": "Rịọ atụmatụ", "about-kiwix": "Banyere Kiwix", "donate-to-support-kiwix": "Nye onyinye iji kwado Kiwix", "exit": "Mèzi", "save-file-as-window-title": "Chekwaa faịlụ ka", "download-finished-message": "Ebudatala akwụkwọ ahụ.", "file": "Àfabà", "edit": "Mèzi", "view": "Lee", "tools": "Ngwaọrụ", "window-title": "Ụlọ akwụkwọ - Kiwix", "search": "Tùwe", "browse-directory": "Chọgharịa ndekọ", "settings": "Ntọala", "back": "Nke–azụ", "forward": "Gawa n'ihu", "search-files": "Họrọ faịlụ", "title": "Isiokwu", "size": "Ívụ", "date": "Ǹgụ́ụ̀bọ̀chị̀", "content-type": "Ihü ihe dị", "reset-sort": "tọgharịa ụdị", "open": "Mepee", "delete": "Kàcha", "download": "Budata", "resume": "maliteghachi", "pause": "Ịkwụsịtụ", "cancel": "Hapụ̀", "apply": "Tinye", "port-for-local-kiwix-server-setting": "Port maka sava Kiwix mpaghara", "zoom-level-setting": "Ọkwa mbugharị mbụ", "download-directory-setting": "Budata ndekọ", "monitor-directory-setting": "Nyochaa ndekọ", "reset": "Mẹ̀wárí n'ísí", "clear": "Kpochapụ", "browse": "Garia", "about-kiwix-desktop-title": "Kiwix Desktọpụ", "about-kiwix-desktop-description": "Kiwix na-enye gị ohere ịnweta Wikipedia niile n'aka ebe ọ bụla ị na-aga! N'elu ụgbọ mmiri, n'etiti ebe ọ bụla, ma ọ bụ n'ụlọ mkpọrọ, Kiwix na-enye gị ohere ịnweta ihe ọmụma mmadụ niile. Ịchọghị ịntanetị, a na-echekwa ihe niile na kọmputa gị.", "about-learn-more-about-kiwix": "Mụtakwuo maka Kiwix", "about-release-title": "Hapụ", "about-source-code": "A tọhapụrụ ngwanrọ a n'okpuru usoro nke GNU General Public License version 3. Lelee koodu isi mmalite na Github .", "about-version": "Ụdị: {{VERSION}}", "about-reporting-problem-title": "Nsogbu mkpesa", "about-report-issue": "Iji mepee esemokwu, gaa na Kiwix-desktop tracker ma mepee okwu na-akọwa nsogbu gị.", "about-report-issue-2": "Biko kwuo ụdịdị na mbipụta a.", "about-libraries-title": "Ụlọ akwụkwọ", "kiwix-server-running-message": "Ihe nkesa Kiwix na-agba ọsọ ma enwere ike ịnweta ya na netwọk mpaghara na:", "kiwix-server-description": "Ịmalite ihe nkesa na-enye ohere ka kọmputa ndị ọzọ dị na netwọk mpaghara nweta ọbá akwụkwọ Kiwix gị na ihe nchọgharị weebụ ọkọlọtọ.", "fullscreen-notification": "Ị nọ na ọnọdụ ihuenyo zuru oke ugbu a. Pịa ESC ka ị kwụsị!", "online-files": "Faịlụ dị n'ịntanetị", "local-files": "Faịlụ mpaghara", "category": "Ụdàkọ", "language": "Asụsụ", "hide": "Zònarị", "open-in-browser": "Mepee na ihe nchọgharị", "start-kiwix-server": "Malite sava Kiwix", "stop-kiwix-server": "Kwụsị sava Kiwix", "all": "Haníle", "fulltext-search": "Ọchụchọ ederede zuru oke", "pictures": "Foto", "videos": "Vịdịo", "ftindex": "Ndekọ ederede zuru oke", "details": "Edemede zuru ezu", "yes": "Ee", "no": "Mba", "ok": "Ọ dị mma", "no-filter": "enweghị nzacha", "open-link-in-web-browser": "Mepee njikọ na ihe nchọgharị weebụ", "download-dir-dialog-title": "Ị ji n'aka na ịchọrọ ịgbanwe ndekọ ntuziaka nbudata?", "download-dir-dialog-msg": "Ụzọ ndekọ nbudata ọhụrụ ga-abụ:\n{{DIRECTORY}}", "invalid-port": "Portụ na-abaghị uru", "zim-open-fail-title": "Faịlụ na-abaghị uru", "zim-open-fail-text": "Enweghị ike imepe faịlụ ZIM {{ZIM}} nke ọma. A ga-ewepụ ya n'ọbá akwụkwọ gị.", "monitor-dir-dialog-title": "Ị ji n'aka na ịchọrọ ịgbanwe ndekọ ntuziaka nbudata?", "monitor-dir-dialog-msg": "Ụzọ ndekọ nbudata ọhụrụ ga-abụ:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ị ji n'aka na ịchọrọ ịgbanwe ndekọ ntuziaka nbudata?", "monitor-clear-dir-dialog-msg": "Nke a ga-akwụsị ịlele ndekọ ndekọ maka faịlụ ZIM ọhụrụ.", "monitor-directory-tooltip": "A ga-atụkwasị faịlụ ZIM niile dị na ndekọ aha na-akpaghị aka n'ọbá akwụkwọ.", "next-tab": "Gaa na taabụ na-esote", "previous-tab": "Gaa na taabụ gara aga", "cancel-download": "Kagbuo nbudata", "cancel-download-text": "Ị ji n'aka na ịchọrọ ịkagbu nbudata nke {{ZIM}} ?", "delete-book": "Hichapụ akwụkwọ", "delete-book-text": "Ị ji n'aka na ịchọrọ ihichapụ {{ZIM}} ?", "download-storage-error": "Mperi nchekwa", "download-storage-error-text": "Sistemu enweghị nchekwa zuru oke dị.", "download-unavailable": "Budata adịghị", "download-unavailable-text": "nbudata a adịghị.", "open-book": "Mepee akwụkwọ", "download-book": "Budata akwụkwọ", "pause-download": "Kwụsị nbudata", "resume-download": "Malitegharịa nbudata", "open-folder": "Mepee folda", "couldnt-open-location": "Enweghị ike imepe ebe", "couldnt-open-location-text": "Kiwix enweghị ike imepe folda {{FOLDER}}", "move-files-to-trash": "Bugharịa faịlụ ehichapụ na ahịhịa", "move-files-to-trash-text": "Ihe omume a ga-ebuga faịlụ ahụ ka ọ bụrụ ahịhịa.", "perma-delete-files-text": "Omume a ga-ehichapụ faịlụ ahụ kpamkpam.", "clear-filter": "Hichapụ ihe nzacha edobere ugbu a", "language-searcher-placeholder": "Asụsụ nzacha", "category-searcher-placeholder": "Otu nzacha", "content-type-searcher-placeholder": "Ụdị ọdịnaya iyo", "no-details": "Naanị mmalite", "no-pictures": "Enweghị Foto", "no-videos": "Enweghị vidiyo" } kiwix-desktop-2.4.1/resources/i18n/igl.json000066400000000000000000000043531473106011000205550ustar00rootroot00000000000000{ "@metadata": { "authors": [ "AgnesAbah", "Beracy", "JosefAnthony", "Ogalihillary" ] }, "name": "Enéfu", "error-title": "Inyoñ", "error-downloader-window-title": "Ineke chen", "open-zim": "Bí Zim filu", "print": "Che dufu", "print-page-error": "Ẹnwu ka chi alu ki ache dufu", "close-tab": "Re apa", "close": "Re", "reopen-closed-tab": "Dabi bi APA kichẹ re", "open-file": "Bí filu", "open-recent": "Bi e titoi", "search-article": "Tene ita", "search-in-library": "Tene efu ugbo kami ẹwnu jọ", "find-in-page": "Tene efu apa", "zoom-in": "Che ki nana", "zoom-out": "Che ki nya", "zoom-reset": "Dabi Che tẹgwu", "help": "Abune", "feedback": "Ẹlọ", "report-a-bug": "Rainọ akanya", "about-kiwix": "Lugbo Kiwix", "donate-to-support-kiwix": "Du kẹ chatẹko Kiwix", "exit": "Kwefu", "save-file-as-window-title": "Fí filu kojo dabí", "file": "Filu", "edit": "Ñọche", "view": "Go", "tools": "Amí ewñ ane", "window-title": "Ugbo kuma kẹnwu jọ - Kiwix", "search": "Téné", "settings": "Eñoche", "back": "Ubi", "forward": "Ogba", "search-files": "Téné amí filu", "title": "Ojí", "size": "Unana", "date": "Iko", "content-type": "Ogbá kí ná óla wéwé", "reset-sort": "Dabi Che ẹre", "open": "Bi", "delete": "Kpalu", "resume": "Edabi wa", "pause": "Mọ́ ọ́wọ́ du no", "cancel": "Kpalú", "apply": "Tene", "about-release-title": "Tónó", "hide": "Du maja", "all": "Ocha ka du", "pictures": "Foto", "videos": "Vidíyo", "details": "Ola otakada Chakadu", "yes": "Iii", "no": "É e", "ok": "Ok", "next-tab": "Lo tí tap omune", "previous-tab": "Lotí tap igbele", "cancel-download": "Fí download kpalu", "delete-book": "Kpo taka da lu", "delete-book-text": "É ché sure ka kí ní é téné kpalu {{ZIM}}?", "open-book": "Bió takada", "pause-download": "Wei download", "resume-download": "Shane download", "open-folder": "Bí failu", "couldnt-open-location": "Mà méké bí ugbo kí de ñ", "couldnt-open-location-text": "Kiwix neké bí folder ñ{{FOLDER}}", "move-files-to-trash": "Amí failu kù ma kpalu mu ma ti ugbo iwa", "move-files-to-trash-text": "É ñwu ké ché í a jé nwí failu í lotí ugbo iwa", "no-pictures": "I foto dó món" } kiwix-desktop-2.4.1/resources/i18n/io.json000066400000000000000000000017431473106011000204110ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Joao Xavier" ] }, "open-zim": "Apertez Zim", "home-page": "Hem-pagino", "print": "Imprimar", "open-file": "Apertar arkivo", "open-recent": "Recente apertita", "search-article": "Serchez artiklo", "reading-list": "Lekto-listo", "zoom-reset": "Riajustar \"zoom\"", "help": "Helpo", "feedback": "Retro-informo", "report-a-bug": "Informez defekto", "donate-to-support-kiwix": "Donez por suportar Kiwix", "download-finished-message": "Ca dokumento descharjesis.", "edit": "Redaktez", "tools": "Utensili", "search": "Serchez", "back": "Addope", "search-files": "Serchar arkivi", "title": "Titulo", "size": "Grandeso", "content-type": "Tipo di kontenajo", "download": "Descharjez", "resume": "Durigar", "cancel": "Anular", "apply": "Aplikar", "hide": "Celez", "start-kiwix-server": "Startar servero Kiwix", "fulltext-search": "Serchar kompleta texto", "pictures": "Imaji", "yes": "yes", "no": "no", "no-filter": "nula filtrilo" } kiwix-desktop-2.4.1/resources/i18n/it.json000066400000000000000000000140661473106011000204200ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Ajeje Brazorf", "Albano", "Albe Albe460", "Beta16", "Gianfranco", "IrsY", "McDutchie", "Scompo", "Stefano" ] }, "name": "italiano", "error-title": "Errore", "error-downloader-window-title": "Impossibile creare downloader", "error-downloader-launch-message": "Impossibile avviare il downloader, Kiwix-desktop si avvierà ma tutte le funzioni di download non funzioneranno!", "error-launch-server-message": "Si è verificato un errore.", "error-archive": "Impossibile ottenere l'archivio", "error-opening-file": "Si è verificato un errore durante l'apertura del file.", "open-zim": "Apri file ZIM", "local-kiwix-server": "Server Kiwix locale", "random-article": "Voce a caso", "random-article-error": "Impossibile aprire un articolo casuale.", "home-page": "Pagina principale", "main-menu": "Menu principale", "print": "Stampa", "print-page-error": "Si è verificato un errore durante la stampa.", "new-tab": "Nuova scheda", "close-tab": "Chiudi scheda", "close": "Chiudi", "reopen-closed-tab": "Riapri scheda chiusa", "browse-library": "Esplora libreria", "open-file": "Apri file", "save-file": "Salva file", "open-recent": "Apri recenti", "search-article": "Ricerca voce", "search-in-library": "Cerca nella libreria", "find-in-page": "Trova nella pagina", "set-fullscreen": "Imposta a schermo intero", "quit-fullscreen": "Esci da schermo intero", "table-of-content": "Indice", "add-bookmark": "Aggiungi all'elenco di lettura", "remove-bookmark": "Rimuovi dall'elenco di lettura", "reading-list": "Elenco di lettura", "zoom-in": "Ingrandisci", "zoom-out": "Rimpicciolisci", "zoom-reset": "Reimposta ingrandimento", "help": "Aiuto", "feedback": "Commenti", "report-a-bug": "Segnala un errore", "request-a-feature": "Richiedi una funzionalità", "about-kiwix": "Su Kiwix", "donate-to-support-kiwix": "Dona per sostenere Kiwix", "exit": "Esci", "save-file-as-window-title": "Salva file come", "download-finished-message": "Il documento è stato scaricato.", "file": "File", "edit": "Modifica", "view": "Visualizza", "tools": "Strumenti", "window-title": "Libreria - Kiwix", "search": "Ricerca", "browse-directory": "Sfoglia la directory", "settings": "Impostazioni", "back": "Indietro", "forward": "Inoltra", "search-files": "Cerca nei file", "title": "Titolo", "size": "Dimensione", "date": "Data", "content-type": "Tipo di contenuto", "reset-sort": "reimposta ordinamento", "open": "Apri", "delete": "Cancella", "download": "Scarica", "resume": "Riprendi", "pause": "Pausa", "cancel": "Annulla", "apply": "Applica", "port-for-local-kiwix-server-setting": "Porta per il server Kiwix locale", "zoom-level-setting": "Livello di ingrandimento predefinito", "download-directory-setting": "Cartella dati scaricati", "monitor-directory-setting": "Monitora la directory", "reset": "Ripristina", "clear": "Pulisci", "browse": "Esplora", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix ti consente di avere l'intera Wikipedia a portata di mano ovunque tu vada! Su una barca, in mezzo al nulla o in prigione, Kiwix ti dà accesso a tutta la conoscenza umana. Non hai bisogno di Internet, tutto è archiviato sul tuo computer.", "about-learn-more-about-kiwix": "Ulteriori informazioni su Kiwix", "about-release-title": "Versione", "about-source-code": "Questo software è rilasciato secondo i termini della GNU General Public License versione 3. Visualizza il codice sorgente su Github.", "about-version": "Versione: {{VERSION}}", "about-reporting-problem-title": "Segnala problemi", "about-report-issue": "Per aprire un problema, visita Kiwix-desktop Issue Tracker e apri una segnalazione che descriva il tuo problema.", "about-report-issue-2": "Menziona la versione nel problema.", "about-libraries-title": "Biblioteche", "kiwix-server-running-message": "Il server Kiwix è in esecuzione ed è possibile accedervi nella rete locale all'indirizzo:", "kiwix-server-description": "L'avvio di un server consente ad altri computer nella rete locale di accedere alla tua libreria Kiwix con un browser web standard.", "fullscreen-notification": "Ora sei in modalità a schermo intero. Premi ESC per uscire!", "local-files": "File locali", "hide": "Nascondi", "open-in-browser": "Apri nel browser", "start-kiwix-server": "Avvia server Kiwix", "stop-kiwix-server": "Arresta il server Kiwix", "all": "Tutto", "ipv4": "Modalità solo IPv4", "ipv6": "Modalità solo IPv6", "fulltext-search": "Ricerca nell'intero testo", "pictures": "Immagini", "videos": "Video", "ftindex": "Indice del testo completo", "details": "Articolo completo", "yes": "sì", "no": "no", "ok": "ok", "no-filter": "Nessun filtro", "open-link-in-web-browser": "Apri collegamento nel browser web", "open-link-new-tab": "Apri collegamento in una nuova scheda", "download-dir-dialog-title": "Sei sicuro di voler cambiare la directory di download?", "download-dir-dialog-msg": "Il nuovo percorso della directory di download sarà:\n{{DIRECTORY}}", "invalid-port": "Porta non valida", "zim-open-fail-title": "File non valido", "zim-open-fail-text": "Il file ZIM {{ZIM}} non può essere aperto correttamente. Verrà rimosso dalla tua libreria.", "monitor-dir-dialog-title": "Sei sicuro di voler cambiare la directory di monitoraggio?", "monitor-dir-dialog-msg": "Il nuovo percorso della directory del monitor sarà:\n{{DIRECTORY}}", "monitor-directory-tooltip": "Tutti i file ZIM in questa directory verranno automaticamente aggiunti alla libreria.", "next-tab": "Passa alla scheda successiva", "previous-tab": "Passa alla scheda precedente", "cancel-download": "Annulla download", "cancel-download-text": "Sei sicuro di voler annullare il download di {{ZIM}} ?", "delete-book": "Cancella libro", "delete-book-text": "Sei sicuro di voler cancellare {{ZIM}} ?", "download-storage-error-text": "Il sistema non dispone di memoria sufficiente.", "download-unavailable-text": "Questo download non è disponibile.", "save-or-open": "Salva o apri file" } kiwix-desktop-2.4.1/resources/i18n/ja.json000066400000000000000000000036131473106011000203720ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Chqaz", "Funa-enpitu", "LaMagiaaa", "MathXplore", "Mugenpman", "Object*tofu", "Omotecho", "Shirayuki", "Tmv", "春春眠眠" ] }, "name": "英語", "error-title": "エラー", "error-launch-server-message": "エラーが発生しました。", "error-archive": "アーカイブを取得できない", "open-zim": "ZIMファイルを開く", "random-article": "おまかせ記事", "print": "印刷", "print-page-error": "印刷中にエラーが発生しました。", "new-tab": "新しいタブ", "close-tab": "タブを閉じる", "search-article": "記事を検索", "find-in-page": "ページ内検索", "feedback": "フィードバック", "file": "ファイル", "edit": "編集", "view": "閲覧", "search": "検索", "settings": "設定", "back": "戻る", "search-files": "ファイルを検索", "title": "タイトル", "size": "サイズ", "date": "日付", "open": "開く", "delete": "削除", "clear": "クリア", "about-kiwix-desktop-description": "Kiwix を使えば、あなたがどこへ行くときでもウィキペディア全体を一緒に持ち歩くことができます!ボートの上でも、なんでもない場所のど真ん中でも、あるいは刑務所でも、Kiwix は全人類の知識へのアクセスを可能にします。インターネットは必要ありません、すべてはあなたのコンピューター上に保存されます。", "about-reporting-problem-title": "問題を報告", "hide": "非表示", "open-in-browser": "ブラウザを開く", "all": "すべて", "open-link-in-web-browser": "Webブラウザでリンクを開く", "invalid-port": "無効なポート", "zim-open-fail-title": "無効なファイル", "next-tab": "次のタブに移動", "previous-tab": "前のタブに移動", "cancel-download": "ダウンロードをキャンセル" } kiwix-desktop-2.4.1/resources/i18n/ko.json000066400000000000000000000232231473106011000204100ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Apzp79", "Codenstory", "Fitoschido", "McDutchie", "Nuevo Paso", "Suleiman the Magnificent Television", "YeBoy371", "Ykhwong", "그냥기여자" ] }, "name": "한국어", "error-title": "오류", "error-downloader-window-title": "다운로더를 만들 수 없습니다", "error-downloader-launch-message": "다운로더를 시작할 수 없습니다. Kiwix-desktop이 시작되더라도 모든 다운로드 기능이 작동하지 않을 것입니다!", "error-launch-server-message": "오류가 발생했습니다!", "error-archive": "아카이브를 가져올 수 없습니다", "error-opening-file": "파일을 여는 중 오류가 발생했습니다.", "open-zim": "ZIM 파일 열기", "local-kiwix-server": "로컬 Kiwix 서버", "random-article": "임의의 문서", "random-article-error": "임의의 문서 열기를 실패했습니다.", "home-page": "홈페이지", "main-menu": "주 메뉴", "print": "인쇄", "print-page-error": "인쇄 중에 오류가 발생했습니다.", "new-tab": "새 탭", "close-tab": "탭 닫기", "close": "닫기", "reopen-closed-tab": "닫힌 탭 다시 열기", "browse-library": "라이브러리 찾아보기", "open-file": "파일 열기", "save-file": "파일 저장", "open-recent": "최근 항목 열기", "search-article": "문서 검색", "search-in-library": "라이브러리에서 검색", "find-in-page": "문서에서 찾기", "set-fullscreen": "전체 화면 설정", "quit-fullscreen": "전체 화면에서 나가기", "table-of-content": "목차", "add-bookmark": "읽기 목록에 추가", "remove-bookmark": "읽기 목록에서 제거", "reading-list": "읽기 목록", "zoom-in": "확대", "zoom-out": "축소", "zoom-reset": "확대/축소 재설정", "help": "도움말", "feedback": "피드백", "report-a-bug": "버그 보고", "request-a-feature": "기능 요청", "about-kiwix": "Kiwix 정보", "donate-to-support-kiwix": "Kiwix 후원하기", "exit": "나가기", "save-file-as-window-title": "다른 이름으로 파일 저장", "download-finished": "다운로드 완료", "download-finished-message": "문서가 다운로드되었습니다.", "file": "파일", "edit": "편집", "view": "보기", "tools": "도구", "window-title": "라이브러리 - Kiwix", "search": "검색", "browse-directory": "디렉터리 찾아보기", "settings": "설정", "back": "뒤로", "forward": "앞으로", "search-files": "파일 검색", "title": "제목", "size": "크기", "date": "날짜", "content-type": "콘텐츠 유형", "reset-sort": "정렬 초기화", "open": "열기", "delete": "삭제", "download": "다운로드", "resume": "계속하기", "pause": "일시 정지", "cancel": "취소", "apply": "적용", "port-for-local-kiwix-server-setting": "로컬 Kiwix 서버 포트", "zoom-level-setting": "기본 확대/축소 수준", "download-directory-setting": "다운로드 디렉터리", "monitor-directory-setting": "모니터 디렉터리", "reset": "재설정", "clear": "비우기", "browse": "찾아보기", "about-kiwix-desktop-title": "Kiwix 데스크톱", "about-kiwix-desktop-description": "Kiwix를 사용하면 어느 곳에 있든지 위키백과를 사용할 수 있습니다! 보트 위에서도, 인적이 드문 곳, 심지어 감옥에서도 Kiwix는 인류의 모든 지식에 접근하게 해 줍니다. 인터넷이 필요 없고 모든 것이 컴퓨터에 저장됩니다.", "about-learn-more-about-kiwix": "Kiwix에 관해 더 알아보기", "about-release-title": "릴리스", "about-source-code": "이 소프트웨어는 GNU GPLv3의 조항에 따라 출시됩니다. 소스 코드는 깃허브에서 볼 수 있습니다.", "about-version": "버전: {{VERSION}}", "about-reporting-problem-title": "문제점 보고", "about-report-issue": "이슈를 열려면 Kiwix-desktop 이슈 트래커를 방문하고 이슈를 열어서 문제를 기술하십시오.", "about-report-issue-2": "이슈에 버전을 언급해 주십시오.", "about-libraries-title": "라이브러리", "kiwix-server-running-message": "Kiwix 서버가 실행 중이며 다음의 로컬 네트워크에 접근이 가능합니다:", "kiwix-server-description": "서버를 시작하면 로컬 네트워크의 다른 컴퓨터가 표준 웹 브라우저를 사용하여 Kiwix 라이브러리에 접근할 수 있습니다.", "fullscreen-notification": "현재 전체 화면 모드입니다. 빠져나가려면 ESC를 누르십시오!", "online-files": "온라인 파일", "local-files": "로컬 파일", "category": "분류", "language": "언어", "hide": "숨기기", "open-in-browser": "브라우저에서 열기", "start-kiwix-server": "Kiwix 서버 시작", "stop-kiwix-server": "Kiwix 서버 중지", "all": "모두", "all_ips": "모두 - 듀얼 스택 모드", "ipv4": "IPv4 전용 모드", "ipv6": "IPv6 전용 모드", "fulltext-search": "본문 검색", "pictures": "사진", "videos": "동영상", "ftindex": "전문 색인", "details": "모든 문서", "yes": "예", "no": "아니오", "ok": "확인", "no-filter": "필터 없음", "open-link-in-web-browser": "웹 브라우저로 링크 열기", "open-link-new-tab": "새 탭에서 링크 열기", "download-dir-dialog-title": "다운로드 디렉터리를 변경하시겠습니까?", "download-dir-dialog-msg": "새 다운로드 디렉터리 경로는 다음과 같습니다:\n{{DIRECTORY}}", "invalid-port": "유효하지 않은 포트", "zim-open-fail-title": "잘못된 파일", "zim-open-fail-text": "{{ZIM}} ZIM 파일을 적절하게 삭제할 수 없습니다. 내 라이브러리에서 제거됩니다.", "monitor-dir-dialog-title": "모니터 디렉터리를 변경하시겠습니까?", "monitor-dir-dialog-msg": "새 모니터 디렉터리는 다음과 같습니다: {{DIRECTORY}}", "monitor-clear-dir-dialog-title": "모니터 디렉터리를 비우시겠습니까?", "path-was-copied": "경로가 복사되었습니다", "monitor-clear-dir-dialog-msg": "새 ZIM 파일의 모니터 디렉터리의 확인을 중단합니다.", "monitor-directory-tooltip": "이 디렉터리의 모든 ZIM 파일은 자동으로 라이브러리에 추가됩니다.", "next-tab": "다음 탭으로 이동", "previous-tab": "이전 탭으로 이동", "cancel-download": "다운로드 취소", "cancel-download-text": "{{ZIM}}의 다운로드를 취소하시겠습니까?", "delete-book": "책 삭제", "delete-book-text": "{{ZIM}} 파일을 삭제하시겠습니까?", "download-storage-error": "저장 오류", "download-storage-error-text": "시스템에 사용 가능한 저장공간이 부족합니다.", "download-exceeds-max-file-size": "다운로드 크기가 대상 파일 시스템에서 지원하는 최대 파일 크기를 초과했습니다.", "download-dir-missing": "다운로드 디렉터리가 존재하지 않습니다.", "download-dir-not-writable": "다운로드 디렉터리에 쓸 수 없습니다.", "download-unavailable": "다운로드 불가", "download-unavailable-text": "이 다운로드는 이용이 불가능합니다.", "open-book": "책 열기", "download-book": "책 다운로드", "pause-download": "다운로드 일시 중지", "resume-download": "이어서 다운로드", "open-folder": "폴더 열기", "couldnt-open-location": "위치를 열 수 없습니다", "couldnt-open-location-text": "Kiwix는 {{FOLDER}} 폴더를 열 수 없습니다", "move-files-to-trash": "삭제된 파일을 휴지통으로 이동", "move-files-to-trash-text": "이 작업을 수행하면 파일이 휴지통으로 이동됩니다.", "perma-delete-files-text": "이 작업을 수행하면 파일이 영구적으로 삭제됩니다.", "clear-filter": "현재 설정된 필터 지우기", "language-searcher-placeholder": "언어별 필터", "category-searcher-placeholder": "분류별 필터", "content-type-searcher-placeholder": "콘텐츠 유형별 필터", "no-details": "소개만", "no-pictures": "사진 없음", "no-videos": "동영상 없음", "open-previous-tabs-at-startup": "시작 시 이전 탭 열기", "preview-book-in-web-browser": "웹 브라우저에서 책 미리 보기", "file-not-found-title": "ZIM 파일이 없습니다", "file-not-found-text": "ZIM 파일이 존재하지 않거나 읽을 수 없습니다", "zim-id": "ZIM Id", "zim-name": "ZIM 이름", "zim-path": "ZIM 파일 경로", "bad-zim-file-error-page-title": "유효하지 않은 ZIM 파일", "bad-zim-file-error-page-text": "ZIM 파일은 유효하지 않거나 손상되었습니다.", "zim-entry-path": "ZIM 엔트리 경로", "export-reading-list": "읽기 목록 내보내기", "export-reading-list-error": "읽기 목록을 내보내는 동안 오류가 발생했습니다.", "import-reading-list": "읽기 목록 가져오기", "import-reading-list-error": "읽기 목록을 가져오는 동안 오류가 발생했습니다.", "disable-sandbox": "Kiwix가 파일서버에서 시작. 이는 검색의 샌드박스에 호환문제를 일으키는 것으로 알려짐. 따라서 샌드박스는 비활성화될 것임. 계속하기?", "save-page-as": "다른 이름으로 저장...", "portable-disabled-tooltip": "포터블 모드에서 기능이 비활성화됩니다", "scroll-next-tab": "다음 탭으로 스크롤", "scroll-previous-tab": "이전 탭으로 스크롤", "kiwix-search": "Kiwix 검색", "search-options": "검색 옵션", "read-article": "문서 읽기", "read-text": "선택한 텍스트 읽기", "read-stop": "읽기 중지", "stop": "중지", "voice": "음성", "select-read-voice": "읽기 음성 선택", "select-read-language": "읽기 언어 선택", "save-or-open": "파일 저장 또는 열기" } kiwix-desktop-2.4.1/resources/i18n/ku-latn.json000066400000000000000000000133031473106011000213500ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Balyozxane", "Bikarhêner" ] }, "name": "Kurdî", "error-title": "Çewtî", "error-downloader-window-title": "Nikare daxînerê çêke", "error-downloader-launch-message": "Nemimkun e ku daxînerê veke, wê Kîwîks-sermase dest pê bike lê wê hemû fonksiyonên daxistinê nexebitin!", "error-launch-server-message": "Çewtiyekê rû da!", "error-archive": "Arşîvê nikare bîne", "open-zim": "Dosyeya ZIMê Veke", "local-kiwix-server": "Servera Kiwixê ya Herêmî", "random-article": "Gotara Ketober", "random-article-error": "Bi ser neket ku gotareke ketober veke.", "home-page": "Serûpel", "main-menu": "Menuya esasî", "print": "Çap bike", "print-page-error": "Çewtiyeke qewimî gava çapkirinê.", "new-tab": "Hilpekîna nû", "close-tab": "Hilpekînê bigire", "close": "Bigire", "reopen-closed-tab": "Hilpekîna girtî ji nû ve veke", "browse-library": "Çavê xwe li kitêbxaneyê bigerîne", "open-file": "Dosyeyê veke", "open-recent": "Dosyeyên dawîn veke", "search-article": "Li gotarê bigere", "search-in-library": "Li kitêbxaneyê bigere", "find-in-page": "Di nav rûpelê de bibîne", "set-fullscreen": "Ekrana dagirtî mîheng bike", "quit-fullscreen": "Ji ekrana dagirtî derkeve", "table-of-content": "Tabloya naverokê", "reading-list": "Lîsteya xwendinê", "zoom-in": "Nêzîk bike", "zoom-out": "Dûr bike", "zoom-reset": "Nêzîkkirinê reset bike", "help": "Alîkarî", "feedback": "Paşragihan", "report-a-bug": "Çewtiyeke bişîne", "request-a-feature": "Taybetmendiyekê bixwaze", "about-kiwix": "Derbarê Kiwixê de", "donate-to-support-kiwix": "Ji bo piştgirîkirinê bexş bike", "exit": "Derkeve", "save-file-as-window-title": "Dosyeyê qeyd bike wek", "download-finished-message": "Dokûment hate daxistin.", "file": "Dosye", "edit": "Biguherîne", "view": "Bibîne", "tools": "Amûr", "window-title": "Kitêbxane - Kiwix", "search": "Lê bigere", "browse-directory": "Çav bi pelrêçê bixe", "settings": "Mîheng", "back": "Vegere", "forward": "Bişîne", "search-files": "Li dosyeyan bigere", "title": "Sernav", "size": "Mezinahî", "date": "Dîrok", "content-type": "Cureyê naverokê", "reset-sort": "rêzkirinê sifir bike", "open": "Veke", "delete": "Jê bibe", "download": "Daxîne", "resume": "Dewam bike", "pause": "Rawestîne", "cancel": "Betal bike", "apply": "Bisepîne", "port-for-local-kiwix-server-setting": "Nuqteya girêdanê ji bo servera Kiwixê yê lokal", "zoom-level-setting": "Dereceya nêzîkkirinê", "download-directory-setting": "Pelrêçê daxîne", "monitor-directory-setting": "Pelrêça monîtorê", "reset": "Sifir bike", "clear": "Paqij bike", "browse": "Çav pê bixe", "about-kiwix-desktop-title": "Kiwix Sermase", "about-kiwix-desktop-description": "Kiwix îmkan dide mirov ku mirov here ku jî temamê Wîkîpediyayê di destê mirov de be! Li ser qayikekê, di nîvê cihekî de an di hepsê de, Kiwix rê dide ku xwe bigihînî temamiya zanînên însanan. Ihtîyaciya te bi înternetê tine ye, her tişt li ser kombersa te tê depokirin.", "about-learn-more-about-kiwix": "Zêdetir hîn bibe derbarê Kiwixê de", "about-release-title": "Versiyon", "about-source-code": "Nivîsbarî di bin banê şertên Lîsansa Giştî ya GNUyê versiyon 3 de hate belavkirin. Koda çavkanî bibîne li ser Githubê.", "about-version": "Versiyon: {{VERSION}}", "about-reporting-problem-title": "Raporkirina probleman", "about-report-issue": "Ji bo vekirina pirsgirêkekî, serdana Kiwix-sermase şopgera probleman bike û pirsgirêka ku problema te îzah dike veke.", "about-report-issue-2": "Ji kerema xwe di pirsgirêkê de behsa versiyonê jî bike", "about-libraries-title": "Kitêbxane", "kiwix-server-running-message": "Servera Kiwixê dixebite û dikare were gihîn di tora lokal de li:", "kiwix-server-description": "Destpêkirina serverekê rê dide kombersên din yên di tora lokal de ku bi gerokeke webê ya standard re xwe bigihînin kitêbxaneya te ya Kiwixê.", "fullscreen-notification": "Tu vêga di moda ekrana dagirtî de yî. Ji bo derketinê pêlî ESC-ê bike!", "local-files": "Dosyeyên Lokal", "hide": "Veşêre", "open-in-browser": "Di gerokê de veke", "start-kiwix-server": "Servera Kiwixê Bide Destpêkirin", "stop-kiwix-server": "Servera Kiwixê Bide Sekinandin", "all": "Hemû", "fulltext-search": "Lêgerîna tam-nivîsê", "pictures": "Wêne", "videos": "Vîdeo", "ftindex": "Îndeksa tam-nivîsî", "details": "Gotara temamî", "yes": "erê", "no": "na", "no-filter": "bêparzûn", "open-link-in-web-browser": "Lînkê di geroka webê de veke", "download-dir-dialog-title": "Tu jê piştrast î ku tu dixwazî pelrêça daxistinê biguherînî?", "download-dir-dialog-msg": "Pelrêça daxistinê yê nû wê bibe:\n{{DIRECTORY}}", "invalid-port": "Nuqteya girêdanê yê nederbasdar", "zim-open-fail-title": "Dosyeya nederbasdar", "zim-open-fail-text": "Dosyeya ZIMê ya {{ZIM}} nikare bi awayekî rast were vekirin. Ew wê ji kitêbxaneya te were rakirin.", "monitor-dir-dialog-title": "Tu emîn î ku tu dixwazî pelrêça monîtorê biguherînî?", "monitor-dir-dialog-msg": "Pelrêça monîtorê yê nû wê bibe:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Tu jê piştrast î ku tu dixwazî pelrêça monîtorê paqij bikî?", "monitor-clear-dir-dialog-msg": "Ev wê kontrolkirina pelrêça monîtorê ji bo dosyeyên nû yên ZIMê bisekinîne.", "monitor-directory-tooltip": "Temamê dosyeyên ZIMê yên di vê pelrêçê de wê bi otomatîkî tevlî kitêbxaneyê bên kirin.", "next-tab": "Derbasî hilpekîna piştî bibe", "previous-tab": "Derbasî hilpekîna berî bibe" } kiwix-desktop-2.4.1/resources/i18n/lb.json000066400000000000000000000124261473106011000203770ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Les Meloures", "Robby", "Volvox" ] }, "name": "Lëtzebuergesch", "error-title": "Feeler", "error-launch-server-message": "Et ass e Feeler geschitt!", "error-opening-file": "Et gouf e Feeler beim Opmaache vum Fichier.", "open-zim": "ZIM Fichier opmaachen", "local-kiwix-server": "Lokale Kiwix-Server", "random-article": "Zoufällegen Artikel", "random-article-error": "En zoufällegen Artikel konnt net opgemaach ginn.", "home-page": "Haaptsäit", "main-menu": "Haaptmenü", "print": "Drécken", "print-page-error": "Beim Drécken ass ee Feeler geschitt.", "new-tab": "Neien Tab", "close-tab": "Tab zoumaachen", "close": "Zoumaachen", "open-file": "Fichier opmaachen", "save-file": "Fichier späicheren", "search-article": "Artikel sichen", "search-in-library": "An der Bibliothéik sichen", "find-in-page": "Op der Säit sichen", "table-of-content": "Inhaltsverzeechnes", "add-bookmark": "Op d'Lieslëscht derbäisetzen", "remove-bookmark": "Vun der Lieslëscht erofhuelen", "reading-list": "Lieslëscht", "zoom-in": "Vergréisseren", "zoom-out": "Verklengeren", "zoom-reset": "Zoom zrécksetzen", "help": "Hëllef", "feedback": "Feedback", "report-a-bug": "E Feeler mellen", "request-a-feature": "Eng Funktioun ufroen", "about-kiwix": "Iwwer Kiwix", "donate-to-support-kiwix": "Maacht en Don fir Kiwix z'ënnerstëtzen", "exit": "Eraus goen", "save-file-as-window-title": "Fichier späicheren als", "download-finished-message": "D'Dokument gouf erofgelueden.", "file": "Fichier", "edit": "Änneren", "view": "Weisen", "tools": "Geschierkëscht", "window-title": "Bibliothéik - Kiwix", "search": "Sichen", "settings": "Astellungen", "back": "Zeréck", "forward": "Virun", "search-files": "Fichiere sichen", "title": "Titel", "size": "Gréisst", "date": "Datum", "content-type": "Typ vum Inhalt", "reset-sort": "Zortéierung zrécksetzen", "open": "Opmaachen", "delete": "Läschen", "download": "Eroflueden", "resume": "Virufueren", "pause": "Paus", "cancel": "Ofbriechen", "apply": "Uwenden", "download-directory-setting": "Repertoire eroflueden", "reset": "Zrécksetzen", "browse": "Duerchsichen", "about-kiwix-desktop-description": "Kiwix gëtt Iech d'Méiglechkeet déi ganz Wikipedia dobäi ze hunn, egal wou Dir sidd! Ob op engem Boot, matzen am Néierewou oder am Prisong: Kiwix gëtt Iech Zougang zur Gesamtheet vum mënschleche Wëssen. Dir braucht keen Internetzougang, alles ass lokal op Ärem Computer gespäichert.", "about-learn-more-about-kiwix": "Méi iwwer Kiwix gewuer ginn", "about-version": "Versioun: {{VERSION}}", "about-reporting-problem-title": "Problemer mellen", "about-libraries-title": "Bibliothéiken", "online-files": "Online-Fichieren", "local-files": "Lokal Fichieren", "category": "Kategorie", "language": "Sprooch", "hide": "Verstoppen", "open-in-browser": "Am Browser opmaachen", "start-kiwix-server": "Kiwix-Server starten", "stop-kiwix-server": "Kiwix-Server stoppen", "all": "All", "fulltext-search": "Volltext-Sich", "pictures": "Biller", "videos": "Videoen", "ftindex": "Volltext-Index", "details": "Kompletten Artikel", "yes": "jo", "no": "neen", "ok": "ok", "no-filter": "kee Filter", "open-link-in-web-browser": "Link am Browser opmaachen", "open-link-new-tab": "Link an engem neien Tab opmaachen", "invalid-port": "Ongültege Port", "zim-open-fail-title": "Ongültege Fichier", "cancel-download": "Download ofbriechen", "cancel-download-text": "Sidd Dir sécher, datt Dir den Download vun {{ZIM}} ofbrieche wëllt?", "delete-book": "Buch läschen", "delete-book-text": "Sidd Dir sécher, datt Dir {{ZIM}} läsche wëllt?", "download-storage-error": "Späicherfeeler", "download-storage-error-text": "De System huet net genuch verfügbar Späicherplaz.", "open-book": "Buch opmaachen", "download-book": "Buch eroflueden", "pause-download": "Erofluede pauséieren", "resume-download": "Mam Erofluede virufueren", "open-folder": "Dossier opmaachen", "couldnt-open-location-text": "Kiwix kann den Dossier {{FOLDER}} net opmaachen", "perma-delete-files-text": "No dëser Aktioun ass de Fichier permanent geläscht.", "language-searcher-placeholder": "No Sprooch filteren", "category-searcher-placeholder": "No Kategorie filteren", "no-pictures": "Keng Biller", "no-videos": "Keng Videoen", "file-not-found-title": "ZIM-Fichier net fonnt", "file-not-found-text": "De ZIM-Fichier gëtt et net oder e kann net gelies ginn", "zim-id": "ZIM-ID", "zim-name": "ZIM-Numm", "bad-zim-file-error-page-title": "Ongültege ZIM-Fichier", "export-reading-list": "Lieslëscht exportéieren", "export-reading-list-error": "Beim Exportéiere vun der Lieslëscht ass ee Feeler geschitt.", "import-reading-list": "Lieslëscht importéieren", "import-reading-list-error": "Beim Importéiere vun der Lieslëscht ass ee Feeler geschitt.", "kiwix-search": "Kiwix-Sich", "search-options": "Sichoptiounen", "read-article": "Artikel virliesen", "read-text": "Ausgewielten Text virliesen", "read-stop": "Ophale mat virliesen", "stop": "Ophalen", "voice": "Stëmm", "select-read-voice": "Stëmm fir virzeliesen eraussichen", "select-read-language": "Sprooch fir virzeliesen eraussichen", "save-or-open": "Fichier späicheren oder opmaachen", "save-or-open-text": "Wat soll Kiwix mam Fichier maachen?" } kiwix-desktop-2.4.1/resources/i18n/mk.json000066400000000000000000000322371473106011000204130ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Bjankuloski06" ] }, "name": "македонски", "error-title": "Грешка", "error-downloader-window-title": "Не можам да го создадам преземачот", "error-downloader-launch-message": "Не можам да го пуштам преземачот. Кивикс за сметач ќе се пушти, нема да работи ниедна од можностите за преземање!", "error-launch-server-message": "Се појави грешка!", "error-archive": "Не можам да го добијам архивот", "error-opening-file": "Се јави грешка при отворањето на податотеката.", "open-zim": "Отвори ZIM-податотека", "local-kiwix-server": "Месен опслужувач на Кивикс", "random-article": "Случајна статија", "random-article-error": "Не успеав да отворам случајна статија.", "home-page": "Почетна страница", "main-menu": "Главно мени", "print": "Печати", "print-page-error": "Се појави грешка при печатењето.", "new-tab": "Ново јазиче", "close-tab": "Затвори јазиче", "close": "Затвори", "reopen-closed-tab": "Преотвори затворено јазиче", "browse-library": "Прелистај библиотека", "open-file": "Отвори податотека", "save-file": "Зачувај податотека", "open-recent": "Отвори скорешни", "search-article": "Пребарај статија", "search-in-library": "Пребарај во библиотеката", "find-in-page": "Најди на страницата", "set-fullscreen": "Дај цел екран", "quit-fullscreen": "Излези од цел екран", "table-of-content": "Содржина", "add-bookmark": "Стави во список за читање", "remove-bookmark": "Отстрани од список за читање", "reading-list": "Список за читање", "zoom-in": "Приближи", "zoom-out": "Оддалечи", "zoom-reset": "Врати размер", "help": "Помош", "feedback": "Мислења", "report-a-bug": "Пријави грешка", "request-a-feature": "Побарајте можност", "about-kiwix": "За Кивикс", "donate-to-support-kiwix": "Дарувајте на Кивикс", "exit": "Излези", "save-file-as-window-title": "Зачувај како", "download-finished": "Преземањето заврши", "download-finished-message": "Документот е преземен.", "file": "Податотека", "edit": "Уреди", "view": "Преглед", "tools": "Алатки", "window-title": "Библиотека — Кивикс", "search": "Пребарај", "browse-directory": "Пребарај папки", "settings": "Нагодувања", "back": "Назад", "forward": "Напред", "search-files": "Пребарај податотеки", "title": "Наслов", "size": "Големина", "date": "Датум", "content-type": "Вид содржина", "reset-sort": "врати подреденост", "open": "Отворени", "delete": "Избриши", "download": "Преземи", "resume": "Продолжи", "pause": "Запри", "cancel": "Откажи", "apply": "Примени", "port-for-local-kiwix-server-setting": "Порта на месниот опслужувач на Кивикс", "zoom-level-setting": "Приближеност", "download-directory-setting": "Папка за преземање", "monitor-directory-setting": "Надзорна папка", "reset": "Одново", "clear": "Исчисти", "browse": "Прелистај", "about-kiwix-desktop-title": "Кивикс за сметач", "about-kiwix-desktop-description": "Кивикс ви овозможува да ја имате цела Википедија во рака, каде и да сте! Било да сте на чамец, некаде во пустелија или во затвор, Кивикс ви дава пристап до сето знаење на човештвото. Не ви треба врска со семрежјето, бидејќи сето е складирано на вашиот сметач.", "about-learn-more-about-kiwix": "Дознајте повеќе за Кивикс", "about-release-title": "Издание", "about-source-code": "Оваа програма е објавена под условите на ГНУ-овата општа јавна лиценца, верзија 3. Изворниот код ќе го најдете на Github.", "about-version": "Верзија: {{VERSION}}", "about-reporting-problem-title": "Пријавување на проблеми", "about-report-issue": "За да направите пријава на проблем, појдете на Следачот на проблеми за Кивикс за сметач и направете страница во која ќе го опишете проблемот.", "about-report-issue-2": "Спомнете ја верзијата во проблемот.", "about-libraries-title": "Библиотеки", "kiwix-server-running-message": "Опслужувачот на Кивикс работи и може да му се пристапи во месната мрежа на:", "kiwix-server-description": "Отпочнувањето на опслужувачот им овозможува на другите сметачи во месната мрежа да имаат пристап кон библиотеката на Кивикс со стандарден семрежен прелистувач.", "fullscreen-notification": "Сега сте во целоекрански режим. Стиснете на Esc за да излезете!", "online-files": "Семрежни податотеки", "local-files": "Месни податотеки", "category": "Категорија", "language": "Јазик", "hide": "Скриј", "open-in-browser": "Отвори во прелистувач", "start-kiwix-server": "Пушти го опслужувачот на Кивикс", "stop-kiwix-server": "Запри го опслужувачот на Кивикс", "all": "Сè", "all_ips": "Сите — Режим на двоен пласт", "ipv4": "Режим на само IPv4", "ipv6": "Режим на само IPv6", "fulltext-search": "Пребарување по цел текст", "pictures": "Слики", "videos": "Видеа", "ftindex": "Целотекстен индекс", "details": "Целосна статија", "yes": "да", "no": "не", "ok": "ок", "no-filter": "без филтер", "open-link-in-web-browser": "Отвори ја врската во прелистувач", "open-link-new-tab": "Отвори ја врската во ново јазиче", "download-dir-dialog-title": "Дали сигурно сакате да ја смените папката за преземање?", "download-dir-dialog-msg": "Новата папка за преземање ќе биде:\n{{DIRECTORY}}", "invalid-port": "Неважечка порта", "zim-open-fail-title": "Неважечка податотека", "zim-open-fail-text": "ZIM-податотеката {{ZIM}} не се отвора како што треба. Ќе ја остранам од вашата библиотека.", "monitor-dir-dialog-title": "Дали сигурно сакате да ја смените надзорната папка?", "monitor-dir-dialog-msg": "Патеката на новата надзорна папка ќе биде:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Дали сигурно сакате да ја чистистите надзорната папка?", "path-was-copied": "Патеката е ископирана", "monitor-clear-dir-dialog-msg": "Со ова повеќе нема да се проеврува дали во надзорната папка има нови ZIM-податотеки.", "monitor-directory-tooltip": "Сите ZIM-податотеки во оваа папка автоматски ќе се додаваат во библиотеката.", "next-tab": "Прејди на следното јазиче", "previous-tab": "Прејди на претходното јазиче", "cancel-download": "Откажи преземање", "cancel-download-text": "Дали сигурно сакате да го откажете преземањето на {{ZIM}}?", "delete-book": "Избриши книга", "delete-book-text": "Дали сигурно сакате да го избришете {{ZIM}}?", "download-storage-error": "Грешка во складирањето", "download-storage-error-text": "Системот нема доволно складиштен простор.", "download-exceeds-max-file-size": "Големината на преземеното ја надминува границата поддржана од целниот податочен систем.", "download-dir-missing": "Папката за преземања не постои.", "download-dir-not-writable": "Папката за преземања е незапислива.", "download-unavailable": "Преземањето е недостапно", "download-unavailable-text": "Ова преземање е недостапно.", "open-book": "Отвори книга", "download-book": "Преземи книга", "pause-download": "Запри го преземањето", "resume-download": "Продолжи преземање", "open-folder": "Отвори папка", "couldnt-open-location": "Не можам да го отворам местото", "couldnt-open-location-text": "Кивикс не може да ја отвори папката {{FOLDER}}", "move-files-to-trash": "Премести ги избришаните податотеки во корпа", "move-files-to-trash-text": "Ова дејство ќе ја премести податотеката во корпа.", "perma-delete-files-text": "Ова дејство трајно ќе ја избрише податотеката.", "clear-filter": "Исчистете ги тековно поставените филтри", "language-searcher-placeholder": "Филтрирај по јазик", "category-searcher-placeholder": "Филтрирај по категорија", "content-type-searcher-placeholder": "Филтрирај по вид на содржина", "no-details": "Само вовед", "no-pictures": "Нема слики", "no-videos": "Нема видеа", "open-previous-tabs-at-startup": "Отвори го претходното јазиче при пуштање", "preview-book-in-web-browser": "Преглед на книгата во прелистувач", "file-not-found-title": "ZIM-податотеката не е пронајдена", "file-not-found-text": "ZIM-подадотеката не постои или е нечитлива", "zim-id": "ZIM-назнака", "zim-name": "ZIM-име", "zim-path": "Патека на ZIM-податотеката", "bad-zim-file-error-page-title": "Неважечка ZIM-податотека", "bad-zim-file-error-page-text": "ZIM-податотеката е неважечка или оштетена.", "zim-entry-path": "Патека на ZIM-влезот", "export-reading-list": "Извези список за читање", "export-reading-list-error": "Се јави грешка при извозот на списокот за читање.", "import-reading-list": "Увези список за читање", "import-reading-list-error": "Се јави грешка при увозот на списокот за читање.", "disable-sandbox": "Кивикс беше пуштен од мрежен двигател. Ова знае да прави проблеми со складноста при прелистување. Поради тоа, песочникот ќе биде оневозможен. Дали сакате да продолжите?", "save-page-as": "Зачувај како...", "portable-disabled-tooltip": "Функцијата е оневозможена во пренослив режим", "scroll-next-tab": "Пролизгајте кон следното јазиче", "scroll-previous-tab": "Пролизгајте кон претходното јазиче", "kiwix-search": "Пребарување по Кивикс", "search-options": "Нагодувања за пребарување", "read-article": "Прочитај ја статијата", "read-text": "Прочитај го избраниот текст", "read-stop": "Престани со читање", "stop": "Престани", "voice": "Глас", "select-read-voice": "Изберете глас на читање", "select-read-language": "Изберете јазик на читање", "save-or-open": "Зачувај или Отвори податотека", "save-or-open-text": "Што да прави Кивикс со податотекава?" } kiwix-desktop-2.4.1/resources/i18n/ms.json000066400000000000000000000024621473106011000204200ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Hakimi97", "Tofeiku", "Ultron90" ] }, "name": "Bahasa Melayu", "error-title": "Ralat", "error-downloader-window-title": "Tidak dapat mencipta pemuat turun", "random-article": "Rencana Rawak", "main-menu": "Menu utama", "print": "Cetak", "close": "Tutup", "open-file": "Buka fail", "search-article": "Cari rencana", "table-of-content": "Jadual isi kandungan", "reading-list": "Senarai bacaan", "help": "Bantuan", "feedback": "Maklum balas", "report-a-bug": "Laporkan pepijat", "about-kiwix": "Tentang Kiwix", "donate-to-support-kiwix": "Derma untuk menyokong Kiwix", "exit": "Keluar", "save-file-as-window-title": "Simpan Fail sebagai", "download-finished-message": "Dokumen telah dimuat turun.", "file": "Fail", "edit": "Sunting", "view": "Lihat", "tools": "Peralatan", "search": "Cari", "settings": "Tetapan", "back": "Kembali", "title": "Tajuk", "size": "Saiz", "date": "Tarikh", "content-type": "Jenis kandungan", "open": "Buka", "delete": "Hapuskan", "download": "Muat turun", "cancel": "Batalkan", "about-libraries-title": "Perpustakaan", "local-files": "Fail Tempatan", "hide": "Sorokkan", "all": "Semua", "pictures": "Gambar", "videos": "Video", "details": "Rencana penuh", "yes": "ya", "no": "tidak", "no-filter": "tiada penapis" } kiwix-desktop-2.4.1/resources/i18n/my.json000066400000000000000000000063031473106011000204240ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Dr Lotus Black", "McDutchie" ] }, "name": "မြန်မာဘာသာ", "error-title": "အမှား", "error-launch-server-message": "အမှားတစ်ခု ဖြစ်ပွားခဲ့ပါသည်", "random-article": "ကျပန်း ဆောင်းပါး", "home-page": "ပင်မစာမျက်နှာ", "main-menu": "ပင်မ မီနူး", "print": "ပရင့်ထုတ်", "new-tab": "tab အသစ်", "close-tab": "tab ပိတ်ရန်", "close": "ပိတ်ရန်", "open-file": "ဖိုင်ဖွင့်", "search-article": "ဆောင်းပါးရှာဖွေရန်", "search-in-library": "စာကြည့်တိုက်တွင်ရှာဖွေရန်", "find-in-page": "စာမျက်နှာတွင် ရှာဖွေရန်", "set-fullscreen": "ဆခရင်အပြည့်ထားရန်", "quit-fullscreen": "ဆခရင်အပြည့်မှထွက်ရန်", "table-of-content": "မာတိကာ", "reading-list": "ဖတ်ရှုစာရင်း", "zoom-in": "အကျယ်ချဲ့ရန်", "zoom-out": "မြင်ကွင်း ချုံ့ရန်", "help": "အကူအညီ", "feedback": "အကြံပေးရန်", "report-a-bug": "အခက်အခဲများ သတင်းပို့ရန်", "exit": "ထွက်ရန်", "file": "ဖိုင်", "edit": "ပြင်ဆင်ရန်", "view": "ကြည့်ရန်", "tools": "ကိရိယာများ", "search": "ရှာဖွေရန်", "settings": "အပြင်အဆင်များ", "back": "နောက်သို့", "forward": "ရှေ့သို့", "search-files": "ဖိုင်များကို ရှာရန်", "title": "ခေါင်းစဉ်", "size": "အရွယ်အစား", "date": "နေ့စွဲ", "open": "ဖွင့်ရန်", "delete": "ဖျက်ရန်", "download": "ဒေါင်းလုဒ်", "resume": "ခေတ္တရပ်နားရာမှ ပြန်လုပ်ရန်", "pause": "ခေတ္တရပ်", "cancel": "မလုပ်တော့ပါ", "apply": "သက်ရောက်စေရန်", "reset": "ပြန်စရန်", "browse": "ရှာဖွေလှန်လှောရန်", "about-release-title": "ထုတ်ပြန်", "about-version": "ဗားရှင်း : {{VERSION}}", "about-reporting-problem-title": "အခက်အခဲ တင်ပြခြင်း", "about-libraries-title": "စာကြည့်တိုက်များ", "local-files": "ဒေသတွင်းဖိုင်များ", "hide": "ဝှက်ရန်", "open-in-browser": "ဘရောက်ဆာတွင် ဖွင့်ရန်", "all": "အားလုံး", "pictures": "ရုပ်ပုံများ", "videos": "ဗီဒီယိုများ", "details": "ဆောင်းပါးအပြည့်စုံ", "yes": "ဟုတ်ပါသည်", "no": "မလုပ်ပါ", "no-filter": "စစ်ထုတ်မှုမရှိ" } kiwix-desktop-2.4.1/resources/i18n/nb.json000066400000000000000000000066351473106011000204060ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Event", "Johshh" ] }, "error-title": "Feil", "new-tab": "Ny fane", "close-tab": "Lukk fane", "close": "Lukk", "reopen-closed-tab": "Åpne lukket fane igjen", "browse-library": "Bla gjennom biblioteket", "open-file": "Åpne fil", "open-recent": "Åpne nylig", "search-article": "Søk i artikkelen", "search-in-library": "Søk i biblioteket", "find-in-page": "Finn på siden", "set-fullscreen": "Aktiver fullskjerm", "quit-fullscreen": "Avslutt fullskjerm", "table-of-content": "Innholdsfortegnelse", "reading-list": "Leseliste", "zoom-in": "Zoom inn", "zoom-out": "Zoom ut", "help": "Hjelp", "feedback": "Tilbakemelding", "report-a-bug": "Rapporter en feil", "request-a-feature": "Be om en funksjon", "about-kiwix": "Om Kiwix", "donate-to-support-kiwix": "Doner for å støtte Kiwix", "exit": "Avslutt", "save-file-as-window-title": "Lagre fil som", "download-finished-message": "Dokumentet er lastet ned.", "file": "Fil", "edit": "Rediger", "view": "Vis", "tools": "Verktøy", "window-title": "Bibliotek - Kiwix", "search": "Søk", "browse-directory": "Bla gjennom katalogen", "settings": "Innstillinger", "back": "Tilbake", "forward": "Fremover", "search-files": "Søk etter filer", "title": "Tittel", "size": "Størrelse", "date": "Dato", "content-type": "Innholdstype", "reset-sort": "tilbakestill sortering", "open": "Åpen", "delete": "Slett", "pause": "Pause", "cancel": "Avbryt", "apply": "Bruk", "port-for-local-kiwix-server-setting": "Port for lokal Kiwix-tjener", "zoom-level-setting": "Standard zoomnivå", "download-directory-setting": "Last ned mappe", "monitor-directory-setting": "Overvåk mappe", "reset": "Nullstill", "clear": "Tøm", "browse": "Bla gjennom", "about-kiwix-desktop-title": "Kiwix Desktop", "about-learn-more-about-kiwix": "Lær mer om Kiwix", "about-release-title": "Utgave", "about-source-code": "Denne programvaren er utgitt under vilkårene i GNU General Public License versjon 3. Se kildekoden på Github.", "about-version": "Versjon: {{VERSION}}", "about-report-issue": "For å åpne et problem, gå til Kiwix-desktop issue tracker og åpne et problem som beskriver problemet ditt.", "about-libraries-title": "Biblioteker", "kiwix-server-running-message": "Kiwix-tjeneren kjører og kan nås i det lokale nettverket på:", "kiwix-server-description": "Å starte en tjener lar andre datamaskiner i det lokale nettverket få tilgang til Kiwix-biblioteket med en standard nettleser.", "fullscreen-notification": "Du er nå i fullskjermmodus. Trykk ESC for å avslutte!", "online-files": "Online-filer", "local-files": "Lokale filer", "hide": "Skjul", "open-in-browser": "Åpne i nettleser", "start-kiwix-server": "Start Kiwix-tjener", "stop-kiwix-server": "Stopp Kiwix-tjener", "all": "Alle", "fulltext-search": "Fulltekstsøk", "pictures": "Bilder", "videos": "Videoer", "ftindex": "Fulltekstindeks", "yes": "ja", "no": "nei", "open-link-in-web-browser": "Åpne lenken i nettleseren", "download-dir-dialog-title": "Er du sikker på at du vil endre nedlastingsmappen?", "invalid-port": "Ugyldig port", "zim-open-fail-title": "Ugyldig fil", "move-files-to-trash": "Flytt slettede filer til papirkurven", "move-files-to-trash-text": "Denne handlingen vil flytte filen til papirkurven.", "perma-delete-files-text": "Denne handlingen vil slette filen uopprettelig." } kiwix-desktop-2.4.1/resources/i18n/nl.json000066400000000000000000000220011473106011000204010ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Dutchy45", "HanV", "Mainframe98", "McDutchie", "SPQRobin" ] }, "name": "Nederlands", "error-title": "Fout", "error-downloader-window-title": "Kan downloader niet aanmaken", "error-downloader-launch-message": "Het is onmogelijk om de downloader te starten. Kiwix-desktop start wel, maar de downloadfuncties werken niet!", "error-launch-server-message": "Er is een fout opgetreden!", "error-archive": "Kan het archief niet ophalen", "open-zim": "ZIM-bestand openen", "local-kiwix-server": "Lokale Kiwix-server", "random-article": "Willekeurig artikel", "random-article-error": "Fout bij openen willekeurig artikel.", "home-page": "Startpagina", "main-menu": "Hoofdmenu", "print": "Afdrukken", "print-page-error": "Er is een fout opgetreden tijdens het afdrukken.", "new-tab": "Nieuw tabblad", "close-tab": "Tabblad sluiten", "close": "Sluiten", "reopen-closed-tab": "Gesloten tabblad heropenen", "browse-library": "Bibliotheek verkennen", "open-file": "Bestand openen", "open-recent": "Recentelijk geopend", "search-article": "Artikel zoeken", "search-in-library": "In bibliotheek zoeken", "find-in-page": "In pagina zoeken", "set-fullscreen": "Volledig scherm activeren", "quit-fullscreen": "Volledig scherm verlaten", "table-of-content": "Inhoudsopgave", "add-bookmark": "Aan de leeslijst toevoegen", "remove-bookmark": "Uit de leeslijst verwijderen", "reading-list": "Leeslijst", "zoom-in": "Inzoomen", "zoom-out": "Uitzoomen", "zoom-reset": "Tekstgrootte terugzetten", "help": "Hulp", "feedback": "Terugkoppeling", "report-a-bug": "Probleem melden", "request-a-feature": "Een functie aanvragen", "about-kiwix": "Over Kiwix", "donate-to-support-kiwix": "Doneer om Kiwix te steunen", "exit": "Afsluiten", "save-file-as-window-title": "Bestand opslaan als", "download-finished-message": "Het document is gedownload.", "file": "Bestand", "edit": "Bewerken", "view": "Beeld", "tools": "Hulpmiddelen", "window-title": "Bibliotheek - Kiwix", "search": "Zoeken", "browse-directory": "Door map bladeren", "settings": "Instellingen", "back": "Terug", "forward": "Volgende", "search-files": "Bestanden zoeken", "title": "Titel", "size": "Grootte", "date": "Datum", "content-type": "Inhoudstype", "reset-sort": "sortering opnieuw instellen", "open": "Openen", "delete": "Verwijderen", "download": "Downloaden", "resume": "Hervatten", "pause": "Pauzeren", "cancel": "Annuleren", "apply": "Toepassen", "port-for-local-kiwix-server-setting": "Poort voor lokale Kiwix-server", "zoom-level-setting": "Standaard zoomniveau", "download-directory-setting": "Downloaddirectory", "monitor-directory-setting": "Te volgen directory", "reset": "Opnieuw instellen", "clear": "Wissen", "browse": "Bladeren", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Met Kiwix hebt u de hele Wikipedia bij de hand, waar u ook gaat! Op een boot, in niemandsland, of in de gevangenis: Kiwix geeft u toegang tot alle menselijke kennis. U hebt geen internet nodig, want alles wordt op uw computer opgeslagen.", "about-learn-more-about-kiwix": "Meer informatie over Kiwix", "about-release-title": "Uitgave", "about-source-code": "Deze software is uitgebracht onder de voorwaarden van de GNU General Public License versie 3. Bekijk de broncode op Github .", "about-version": "Versie: {{VERSION}}", "about-reporting-problem-title": "Problemen melden", "about-report-issue": "Om een probleem te melden, gaat u naar Kiwix-desktop issue tracker en opent u een melding met een beschrijving uw probleem.", "about-report-issue-2": "Vermeld ook de versie in de melding.", "about-libraries-title": "Bibliotheken", "kiwix-server-running-message": "De Kiwix-server is actief en kan op het lokale netwerk worden benaderd via:", "kiwix-server-description": "Door een server te starten, kunnen andere computers in het lokale netwerk met een standaard webbrowser toegang krijgen tot uw Kiwix-bibliotheek.", "fullscreen-notification": "U bevindt zich nu in de modus Volledig scherm. Druk op ESC om te stoppen!", "online-files": "Online-bestanden", "local-files": "Lokale bestanden", "category": "Categorie", "language": "Taal", "hide": "Verbergen", "open-in-browser": "In browser openen", "start-kiwix-server": "Kiwix-server starten", "stop-kiwix-server": "Kiwix-server stoppen", "all": "Alle", "all_ips": "Beide (Dual Stack-modus)", "ipv4": "Alleen IPv4", "ipv6": "Alleen IPv6", "fulltext-search": "In volledige tekst zoeken", "pictures": "Afbeeldingen", "videos": "Video’s", "ftindex": "Index volledige tekst", "details": "Volledig artikel", "yes": "ja", "no": "nee", "ok": "OK", "no-filter": "geen filter", "open-link-in-web-browser": "Koppeling openen in webbrowser", "open-link-new-tab": "Koppeling openen in nieuwe tab", "download-dir-dialog-title": "Weet u zeker dat u de downloaddirectory wilt wijzigen?", "download-dir-dialog-msg": "Het pad naar de nieuwe downloaddirectory wordt:\n{{DIRECTORY}}", "invalid-port": "Ongeldige poort", "zim-open-fail-title": "Ongeldig bestand", "zim-open-fail-text": "Het ZIM-bestand {{ZIM}} kan niet correct worden geopend. Het wordt uit uw bibliotheek verwijderd.", "monitor-dir-dialog-title": "Weet u zeker dat u de te volgen directory wilt wijzigen?", "monitor-dir-dialog-msg": "Het pad naar de nieuwe te volgen directory wordt:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Weet u zeker dat u de te volgen directory wilt wissen?", "path-was-copied": "Pad is gekopieerd", "monitor-clear-dir-dialog-msg": "Hierdoor stopt het controleren van de te volgen directory op nieuwe ZIM-bestanden.", "monitor-directory-tooltip": "Alle ZIM-bestanden in deze directory worden automatisch aan de bibliotheek toegevoegd.", "next-tab": "Naar het volgende tabblad", "previous-tab": "Naar het vorige tabblad", "cancel-download": "Downloaden annuleren", "cancel-download-text": "Weet u zeker dat u het downloaden van {{ZIM}} wilt annuleren?", "delete-book": "Boek verwijderen", "delete-book-text": "Weet u zeker dat u {{ZIM}} wilt verwijderen?", "download-storage-error": "Opslagfout", "download-storage-error-text": "Het systeem heeft niet voldoende opslagruimte beschikbaar.", "download-exceeds-max-file-size": "De downloadgrootte overschrijdt de maximale bestandsgrootte die het doelbestandssysteem aankan.", "download-dir-missing": "De downloaddirectory bestaat niet.", "download-dir-not-writable": "De downloaddirectory is niet beschrijfbaar.", "download-unavailable": "Download niet beschikbaar", "download-unavailable-text": "Deze download is niet beschikbaar.", "open-book": "Boek openen", "download-book": "Boek downloaden", "pause-download": "Downloaden pauzeren", "resume-download": "Downloaden hervatten", "open-folder": "Map openen", "couldnt-open-location": "Kan locatie niet openen", "couldnt-open-location-text": "Kiwix kan map {{FOLDER}} niet openen", "move-files-to-trash": "Verwijderde bestanden naar de prullenbak verplaatsen", "move-files-to-trash-text": "Met deze handeling wordt het bestand naar de prullenbak verplaatst.", "perma-delete-files-text": "Met deze handeling wordt het bestand definitief verwijderd.", "clear-filter": "De momenteel ingestelde filters wissen", "language-searcher-placeholder": "Filteren op taal", "category-searcher-placeholder": "Filteren op categorie", "content-type-searcher-placeholder": "Filteren op inhoudstype", "no-details": "Alleen introductie", "no-pictures": "Geen afbeeldingen", "no-videos": "Geen video’s", "open-previous-tabs-at-startup": "Vorige tabbladen openen bij het opstarten", "preview-book-in-web-browser": "Voorvertoning boek in webbrowser", "file-not-found-title": "ZIM-bestand niet gevonden", "file-not-found-text": "Het ZIM-bestand bestaat niet of is niet leesbaar", "zim-id": "ZIM-ID", "zim-name": "ZIM-naam", "zim-path": "ZIM-bestandspad", "bad-zim-file-error-page-title": "Onjuist ZIM-bestand", "bad-zim-file-error-page-text": "Het ZIM-bestand is foutief of beschadigd.", "zim-entry-path": "ZIM-toegangspad", "export-reading-list": "Leeslijst exporteren", "export-reading-list-error": "Er is een fout opgetreden tijdens het exporteren van de leeslijst.", "import-reading-list": "Leeslijst importeren", "import-reading-list-error": "Er is een fout opgetreden tijdens het importeren van de leeslijst.", "disable-sandbox": "Kiwix is gestart vanaf een netwerkstation. Dit gaat niet samen met de veiligheidsafzondering (sandbox) van de browser. Daarom wordt de sandbox uitgeschakeld. Wilt u doorgaan?", "save-page-as": "Opslaan als…", "portable-disabled-tooltip": "Functie uitgeschakeld in draagbare modus", "scroll-next-tab": "Naar het volgende tabblad scrollen", "scroll-previous-tab": "Naar het vorige tabblad scrollen", "kiwix-search": "Kiwix-zoekopdracht", "search-options": "Zoekopties", "read-article": "Artikel lezen", "read-text": "Geselecteerde tekst lezen", "read-stop": "Stoppen met lezen", "stop": "Stoppen", "voice": "Stem", "select-read-voice": "Kies leesstem", "select-read-language": "Kies leestaal" } kiwix-desktop-2.4.1/resources/i18n/nqo.json000066400000000000000000000204711473106011000205760ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Aboubacar.banamoridou.toure", "Lancine.kounfantoh.fofana", "ߒߓߋ߫ ߝߏߝߣߊ߫" ] }, "name": "ߒߞߏ", "error-title": "ߝߎ߬ߕߎ߲߬ߕߌ", "error-downloader-window-title": "ߟߊ߬ߖߌ߰ߒ߬ߞߎ߲߬ߠߌ߲ ߕߍ߫ ߛߐ߲߬ ߛߌ߲ߘߌ߫ ߟߊ߫", "error-downloader-launch-message": "ߟߊ߬ߖߌ߰ߒ߬ߞߎ߲߬ߠߌ߲ ߡߊ߫ ߛߐ߲߬ ߟߊߥߟߌ߬ ߟߊ߫߸ ߕߟߋ߬ߓߊ߮-ߞߥߌߞߛ ߘߌ߫ ߣߊ߬ ߘߊߡߌ߬ߣߊ߬ ߞߏ߬ߣߌ߲߫ ߟߊ߬ߖߌ߰ߒ߬ߞߎ߲߬ߠߌ߲ ߗߋߘߊ ߟߋ߬ ߡߎ߰ߡߍ ߕߍߣߊ߬ ߓߊ߯ߙߊ߫ ߟߊ߫߹", "error-launch-server-message": "ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߓߘߊ߫ ߓߌ߬ߟߵߊ߬ ߘߐ߫", "error-archive": "ߛߓߍߞߘߐ ߕߍ߫ ߛߐ߲߬ ߡߊߛߐ߬ߘߐ߲߫ ߠߊ߫", "open-zim": "ߖ߭ߌߡ ߞߐߕߐ߮ ߘߊߦߟߍ߬", "local-kiwix-server": "ߘߌ߲߬ߞߌߙߊ ߞߥߌߞߛ ߡߊߛߐߟߊ߲", "random-article": "ߓߍ߲߬ߛߋ߲߬ߡߊ߫ ߞߎߡߘߊ", "random-article-error": "ߓߍ߲߬ߛߋ߲߬ߡߊ߬ ߞߎߡߘߊ ߘߊߦߟߍߟߌ ߓߘߊ߫ ߗߌߙߏ߲߫.", "home-page": "ߓߏ߬ߟߏ߲߬ߘߊ ߞߐߜߍ", "main-menu": "ߓߏ߬ߟߏ߲߬ߘߊ ߛߙߍߘߍ", "print": "ߜߌ߬ߙߌ߲߬ߘߌ߬ߟߌ", "print-page-error": "ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߓߘߊ߫ ߓߌ߬ߟߴߊ߬ ߘߐ߫ ߞߊ߬ ߜߌ߬ߙߌ߲߬ߘߌ߬ߟߌ ߕߴߌ ߘߐ߫.", "new-tab": "ߝߢߐߘߊ߫ ߞߎߘߊ", "close-tab": "ߝߢߐߘߊ ߘߊߕߎ߲߯", "close": "ߊ߬ ߘߊߕߎ߲߯", "reopen-closed-tab": "ߘߊߞߎ߲߫ ߘߊߕߎ߲߯ߣߍ߲ ߘߊߦߟߍ߬ ߞߎߘߊ߫ ߘߌ߫", "browse-library": "ߛߓߍߘߊ ߛߏ߲߯ߓߊ߫", "open-file": "ߞߐߕߐ߮ ߘߊߦߟߍ߬", "open-recent": "ߞߐ߯ߟߊ߫ ߘߊߦߟߍߣߍ߲", "search-article": "ߞߎߡߘߊ ߢߌߣߌ߲߫", "search-in-library": "ߕߌߙߌ߲ߠߌ߲ ߞߍ߫ ߛߓߍߘߊ ߞߣߐ߫", "find-in-page": "ߊ߬ ߢߌߣߌ߲߫ ߞߐߜߍ ߘߐ߫", "set-fullscreen": "ߘߊ߬ߣߊ߲߬ߥߟߊ ߘߝߊߣߍ߲ ߞߍߗߏ߮", "quit-fullscreen": "ߓߐ߫ ߘߊ߬ߣߊ߲߬ߥߟߊ ߘߝߊߣߍ߲ ߘߐ߫", "table-of-content": "ߞߣߐߘߐ ߟߎ߬ ߥߟߊ߬ߟߋ߲", "reading-list": "ߘߐ߬ߞߊ߬ߙߊ߲߬ߠߌ߲߬ ߛߙߍߘߍ", "zoom-in": "ߊ߬ ߡߊߛߊ߬ߡߊ߲߫", "zoom-out": "ߊ߬ ߡߊߓߐ߫", "zoom-reset": "ߖ߭ߎߡ ߢߡߊߛߊ߬ߦߌ", "help": "ߘߍ߬ߡߍ߲߬ߠߌ߲", "feedback": "ߞߙߐ߬ߛߌ߬ߕߊ", "report-a-bug": "ߝߍ߭ ߘߏ߫ ߟߊߞߏߝߐ߫", "request-a-feature": "ߗߋߘߊ ߘߏ߫ ߡߊߢߌ߬ߣߌ߲߬ߞߊ߫", "about-kiwix": "ߞߊ߬ ߓߍ߲߬ ߞߥߌߞߛ ߡߊ߬", "donate-to-support-kiwix": "ߣߌ߬ߟߌ ߞߍ߫ ߞߊ߬ ߞߥߌߞߛ ߞߐߡߊߓߌ߲ߓߌ߲߫", "exit": "ߓߐ߫", "save-file-as-window-title": "ߞߐߕߐ߮ ߟߊߞߎ߲߬ߘߎ߬ ߦߏ߫", "download-finished-message": "ߘߐ߬ߛߙߋ ߓߘߊ߫ ߓߊ߲߫ ߟߊߖߌ߰ ߟߴߌ ߞߎ߲߬.", "file": "ߞߐߕߐ߮", "edit": "ߊ߬ ߡߊߦߟߍ߬ߡߊ߲߫", "view": "ߊ߬ ߦߋ߫", "tools": "ߖߐ߯ߙߊ߲ ߠߎ߬", "window-title": "ߞߥߌߞߛ – ߛߓߍߘߊ", "search": "ߢߌߣߌ߲ߠߌ߲", "browse-directory": "ߘߐ߬ߛߙߋ ߘߏ߫ ߓߍ߬ߙߍ߲߬ߓߍߙߍ߲߫", "settings": "ߟߊ߬ߓߍ߲߬ߢߐ߲߰ߡߦߊ߬ߘߊ ߟߎ߬", "back": "ߌ ߞߐߛߊ߬ߦߌ߬", "forward": "ߢߍߝߍ߬", "search-files": "ߞߐߕߐ߮ ߟߎ߬ ߢߌߣߌ߲߫", "title": "ߞߎ߲߬ߕߐ߮", "size": "ߢߊ߲ߞߊ߲", "date": "ߕߎ߬ߡߊ߬ߘߊ", "content-type": "ߞߣߐߘߐ߫ ߛߎ߯ߦߊ", "reset-sort": "ߢߣߊߕߐߡߐ߲ߠߌ߲ ߘߊߡߌ߬ߣߊ߬ ߞߎߘߊ߫ ߘߌ߫", "open": "ߊ߬ ߟߊߞߊ߬", "delete": "ߊ߬ ߖߏ߬ߛߌ߬", "download": "ߟߊ߬ߖߌ߰ߒ߬ߞߎ߲߬ߠߌ߲", "resume": "ߊ߬ ߘߊߡߌ߬ߣߊ߬", "pause": "ߊ߬ ߟߊߟߐ߬", "cancel": "ߊ߬ ߘߐߛߊ߬", "apply": "ߊ߬ ߟߥߊߟߌ߫", "port-for-local-kiwix-server-setting": "ߘߌ߲߬ߞߌߙߊ ߞߥߌߞߛ ߡߊߛߐߟߊ߲ ߘߏ߲߬ߘߊ", "zoom-level-setting": "ߓߐߛߎ߲ ߡߛߊ߬ߡߊ߲߬ߠߌ߲ ߞߊߓߋ", "download-directory-setting": "ߟߊߖߌ߰ߒ߬ߞߎ߲߬ߣߍ߲ ߠߎ߫ ߘߐ߬ߛߙߋ", "monitor-directory-setting": "ߘߏ߲߬ߖߟߎ߬ߡߊ߬ߟߌ ߦߌ߬ߘߊ߬ߥߟߊ", "reset": "ߊ߬ ߡߊߛߊ߬ߦߌ߬", "clear": "ߊ߬ ߖߏ߰ߛߌ߬", "browse": "ߊ߬ ߓߍ߬ߙߍ߲߬ߓߙߍ߲߫", "about-kiwix-desktop-title": "ߕߟߋ߬ߓߊ߮ ߞߥߌߞߛ", "about-kiwix-desktop-description": "ߞߥߌߞߛ ߦߴߊ߬ ߕߏ߫ ߟߊ߫ ߌ ߦߋ߫ ߛߋ߫ ߥߞߌߔߋߘߌߦߊ ߡߎ߰ߡߍ ߛߐ߬ߘߐ߲߬ ߠߊ߫ ߌ ߕߍ߮ ߘߐ߫߸ ߌ ߞߍ߫ ߘߊ߫ ߝߊ߲߬ ߛߌ߫߹ ߞߎߟߎ߲ ߞߣߐ߫߸ ߦߙߐ߫ ߟߊߞߏߟߏ߲ ߠߎ߬ ߕߍߡߊ߬ ߥߟߊ߫ ߥߛߎ (ߞߊ߬ߛߏ) ߟߊ߫߸ ߞߥߌߞߛ ߦߋ߫ ߝߙߍ߬ ߘߌ߫ ߟߴߌ ߡߊ߬ ߞߊ߬ ߡߐ߰ߣߍ߲߬ߝߌ߲ ߟߐ߲ߕߊ ߡߎ߰ߡߍ ߟߊߛߐ߬ߘߐ߲߬. ߌ ߡߊ߬ߞߏ߬ ߕߍ߫ ߓߟߐߟߐ߫ ߟߊ߫߸ ߊ߬ ߓߍ߯ ߟߊߡߙߊ߬ߣߍ߲߫ ߦߴߌ ߟߊ߫ ߕߟߋ߬ߓߊ߮ ߟߋ߬ ߞߣߐ߫.", "about-learn-more-about-kiwix": "ߛߌߦߊߡߊ߲߫ ߘߐߞߊ߬ߙߊ߲߫ ߞߊ߬ ߓߍ߲߬ ߞߥߌߞߛ ߡߊ߬", "about-release-title": "ߟߊ߬ߥߊ߲߬ߞߊ߬ߟߌ", "about-source-code": "ߛߎ߲ߝߘߍ ߣߌ߲߬ ߠߊߥߊ߲߬ߞߊ߲߬ߣߍ߲߫ ߦߋ߫ GNU ߝߘߏ߬ߓߊ߬ ߕߦߊ ߟߊߞߊ߬ߝߏ߬ߣߍ߲ ߦߌߟߡߊ߫ ߃. (General Public Licence version 3.) ߟߋ߬ ߓߟߏ߫ ߞߘߐ߫. ߊ߬ ߓߐߖߎ ߘߏߝߙߍߕߍ ߦߋ߫ {{GITHUB_URL}} ߘߐ߫.", "about-version": "ߦߌߟߡߊ {{VERSION}}", "about-reporting-problem-title": "ߝߙߋߞߋ ߟߊߞߏߝߐ߫", "about-report-issue": "ߖߐ߲߬ߛߊ߫ ߞߊ߬ ߝߙߋߞߋ ߘߏ߫ ߢߊߦߌ߬ߘߊ߬߸ ߥߊ߫ ߓߐ߫ {{TRACKER_URL}}ߞߥߌߞߛ-ߕߟߋ߬ߓߊ߮ ߝߙߋߞߋ ߢߊߦߌߘߊߟߊ߲ ߏ߬ ߞߐ߫ ߞߊ߬ ߓߐ߲ߘߊ ߘߏ߫ ߘߊߦߟߍ߬ ߞߵߌ ߟߊ߫ ߝߙߋߞߋ ߛߓߍ߫.", "about-report-issue-2": "ߞߥߌߞߛ ߦߌߟߡߊ ߞߏߝߐ߫ ߌ ߟߊ߫ ߞߐ߯ߡߌ߲ߠߌ߲ ߘߐ߫ ߖߊ߰ߣߌ߲߫.", "about-libraries-title": "ߛߓߍߘߊ", "kiwix-server-running-message": "ߞߥߌߞߛ ߡߊߛߐߟߊ߲ ߦߋ߫ ߥߊ ߞߊ߲߬ ߊ߬ ߣߴߊ߬ ߘߌ߫ ߛߋ߫ ߟߊߛߐ߬ߘߐ߲߬ ߠߊ߫ ߘߌ߲߬ߞߌߙߊ ߓߟߐߟߐ ߟߊ߫:", "kiwix-server-description": "ߡߊ߬ߛߐ߬ߟߊ߲ ߘߊߡߌߣߊߟߌ ߦߋ߫ ߕߟߋ߬ߓߊ߮ ߕߐ߭ ߟߎ߬ ߟߊߘߌ߬ߢߍ߬ ߟߊ߫ ߘߌ߲߬ߞߌߙߊ ߞߙߏ߬ߝߏ ߟߊ߫ ߞߵߌ ߟߊ߫ ߞߥߌߞߛ ߛߓߍߘߊ ߟߊߛߐ߬ߘߐ߲߬ ߛߎߡߊ߲ߘߊ߲ߕߊ ߓߟߐߟߐ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫.", "fullscreen-notification": "ߌ ߦߋ߫ ߘߊ߬ߣߊ߲߬ߥߟߊ߬ ߘߝߊߣߍ߲ ߞߍߗߏ߮ ߟߋ߬ ߘߐ߫ ߡߎ߬ߕߎ߲߫. ߊ߬ ߞߘߐߞߊ߬ ߛߐ߲߬ߞߌ߲߫ ߞߊ߬ ߓߐ߫߹", "local-files": "ߘߌ߲߬ߞߌߙߊ ߞߐߕߐ߮ ߟߎ߬", "hide": "ߊ߬ ߢߡߊߘߏ߲߰", "open-in-browser": "ߊ߬ ߟߊߞߊ߬ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫", "start-kiwix-server": "ߞߥߌߞߛ ߡߊߛߐߟߊ߲ ߘߊߡߌ߬ߣߊ߬", "stop-kiwix-server": "ߞߥߌߞߛ ߡߊߛߐߟߊ߲ ߟߊߟߐ߬", "all": "ߊ߬ ߓߍ߯", "fulltext-search": "ߞߟߏߜߍ߫ ߘߝߊߣߍ߲ ߢߌߣߌ߲ߠߌ߲", "pictures": "ߖߌ߬ߦߊ߬ߓߍ ߟߎ߬", "videos": "ߖߌ߬ߦߊ߬ߖߟߎ ߟߎ߬", "ftindex": "ߛߓߍߟߌ߫ ߘߝߊߣߍ߲ ߡߊ߬ߛߙߋ", "details": "ߞߎߡߘߊ߫ ߘߝߊߣߍ߲", "yes": "ߐ߲߬ߐ߲ߐ߲߫", "no": "ߊ߬ߦߌ߫", "no-filter": "ߛߍ߲ߛߍ߲ߟߊ߲ ߕߴߦߋ߲߬", "open-link-in-web-browser": "ߛߘߌ߬ߜߋ߲ ߘߊߦߟߍ߬ ߓߟߐߟߐ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫", "download-dir-dialog-title": "ߊ߬ ߝߐ߫ ߌ ߘߍ߲߬ߞߣߍ߬ߦߊ߬ߣߍ߲߫ ߦߋ߫ ߞߴߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߘߏ߲߬ߖߟߎ߬ߡߊ߬ߟߌ ߦߌ߬ߘߊ߬ߥߟߊ ߡߊߝߊ߬ߟߋ߲߫؟", "download-dir-dialog-msg": "ߟߊ߬ߖߌ߰ߒ߬ߞߎ߲߬ߠߌ߲ ߦߌ߬ߘߊ߬ߥߟߊ ߛߌߟߊ ߞߎߘߊ ߘߌߣߊ߬ ߞߍ߫: {{DIRECTORY}}", "invalid-port": "ߘߏ߲߬ߘߊ߫ ߓߍ߲߬ߓߊߟߌ", "zim-open-fail-title": "ߞߎ߲߬ߕߐ߮ ߓߍ߲߬ߓߊߟߌ", "zim-open-fail-text": "ߖ߭ߌߡ ߞߐߕߐ߮ {{ZIM}} ߕߍߣߊ߬ ߛߐ߲߬ ߠߊ߫ ߟߊߞߊ߬ ߟߴߊ߬ ߢߊߓߘߍ ߡߊ߬. ߊ߬ ߘߌߣߊ߬ ߖߏ߰ߛߌ߫ ߌ ߟߊ߫ ߛߓߍߘߊ ߘߐ߫.", "monitor-dir-dialog-title": "ߊ߬ ߝߐ߫ ߌ ߘߍ߲߬ߞߣߍ߬ߦߊ߬ߣߍ߲߫ ߦߋ߫ ߞߴߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߘߏ߲߬ߖߟߎ߬ߡߊ߬ߟߌ ߦߌ߬ߘߊ߬ߥߟߊ ߡߊߝߊ߬ߟߋ߲߫؟", "monitor-dir-dialog-msg": "ߦߌ߬ߘߊ߬ߟߌ ߦߌ߬ߘߊ߬ߥߟߊ ߛߌߟߊ߫ ߞߎߘߊ ߘߌߣߊ߬ ߞߍ߫: {{DIRECTORY}}", "monitor-clear-dir-dialog-title": "ߊ߬ ߝߐ߫ ߌ ߘߍ߲߬ߞߣߍ߬ߦߊ߬ߣߍ߲߫ ߦߋ߫ ߞߴߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߦߌ߬ߘߊ߬ߟߌ߬ߟߊ߲ ߦߌ߬ߘߊ߬ߥߟߊ ߡߊߝߊ߬ߟߋ߲߫؟", "monitor-clear-dir-dialog-msg": "ߏ߬ ߘߌߣߊ߬ ߦߌ߬ߘߊ߬ߟߌ߬ߟߊ߲ ߦߌ߬ߘߊ߬ߥߟߊ ߜߋ߬ߟߎ߲߬ߠߌ߲ ߠߊߟߐ߬ ߖ߭ߌߡ ߞߐߕߐ߯ ߞߎߘߊ ߟߎ߬ ߢߍ߫.", "monitor-directory-tooltip": "ߖ߭ߌߡ ߞߐߕߐ߮ ߛߎ߯-ߎ-ߛߎ߫ ߦߋ߫ ߦߌ߬ߘߊ߬ߥߟߊ ߣߌ߲߬ ߘߐ߫߸ ߏ߬ ߟߎ߬ ߘߌߣߊ߬ ߓߌ߬ߟߊ߬ ߛߓߍߘߊ ߞߣߐ߫ ߞߍߒߖߘߍߦߋߓߟߏߡߊ߬.", "next-tab": "ߕߊ߯ ߘߊߞߎ߲ ߢߍߕߍ ߘߐ߫", "previous-tab": "ߕߊ߯ ߘߊߞߎ߲ ߕߊ߬ߡߌ߲߬ߣߍ߲ ߘߐ߫" } kiwix-desktop-2.4.1/resources/i18n/or.json000066400000000000000000000317621473106011000204260ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Gouri" ] }, "name": "ଓଡି଼ଆ", "error-title": "ତ୍ରୁଟି", "error-downloader-window-title": "ଡାଉନଲୋଡର ସୃଷ୍ଟି କରିପାରିବେ ନାହିଁ", "error-downloader-launch-message": "ଡାଉନଲୋଡର ଆରମ୍ଭ କରିବା ଅସମ୍ଭବ - କିୱିକ୍ସ - ଡେସ୍କଟପ ଆରମ୍ଭ ହେବ କିନ୍ତୁ ସମସ୍ତ ଡାଉନଲୋଡ୍ କାର୍ଯ୍ଯ଼ କାମ କରିବ ନାହିଁ", "error-launch-server-message": "ଗୋଟିଏ ତ୍ରୁଟି ଘଟିଛି", "error-archive": "ଅଭିଲେଖକୁ ପାଇପାରିଲା ନାହିଁ", "open-zim": "ZIM ଫାଇଲକୁ ଖୋଲନ୍ତୁ", "local-kiwix-server": "ସ୍ଥାନୀୟ କିୱିକ୍ସ ସର୍ଭର", "random-article": "ଅନିୟମିତ ପ୍ରବନ୍ଧ", "random-article-error": "ଏକ ଅନିୟମିତ ପ୍ରବନ୍ଧ ଖୋଲିବାରେ ବିଫଳ", "home-page": "ମୂଳପୃଷ୍ଠା", "main-menu": "ମୁଖ୍ୟ ମେନୁ", "print": "ମୁଦ୍ରଣ କରନ୍ତୁ", "print-page-error": "ମୁଦ୍ରଣ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ଘଟିଛି", "new-tab": "ନୂଆ ଟ୍ୟାବ୍", "close-tab": "ଟ୍ୟାବ୍ ବନ୍ଦ କରନ୍ତୁ |", "close": "ବନ୍ଦ କରନ୍ତୁ", "reopen-closed-tab": "ବନ୍ଦ ଟ୍ୟାବ୍ ଖୋଲନ୍ତୁ", "browse-library": "ଲାଇବ୍ରେରୀ ବ୍ରାଉଜ୍ କରନ୍ତୁ", "open-file": "ଫାଇଲ୍ ଖୋଲନ୍ତୁ", "open-recent": "ସମ୍ପ୍ରତି ଖୋଲନ୍ତୁ", "search-article": "ପ୍ରବନ୍ଧ ଖୋଜ", "search-in-library": "ଲାଇବ୍ରେରୀରେ ଖୋଜ", "find-in-page": "ପୃଷ୍ଠାରେ ଖୋଜନ୍ତୁ", "set-fullscreen": "ଫୁଲ୍ ସ୍କ୍ରିନ୍ ସେଟ୍ କରନ୍ତୁ", "quit-fullscreen": "ଫୁଲ୍ ସ୍କ୍ରିନ୍ ଛାଡନ୍ତୁ", "table-of-content": "ବିଷଯ଼ବସ୍ତୁ ସାରଣୀ", "reading-list": "ପଠନ ତାଲିକା", "zoom-in": "ବଡ଼ କରନ୍ତୁ", "zoom-out": "ଛୋଟ କରନ୍ତୁ", "zoom-reset": "ଜୁମ୍ ପୁନଃସ୍ଥାପନ", "help": "ସାହାଯ୍ୟ", "feedback": "ମତାମତ", "report-a-bug": "ଏକ ତ୍ରୁଟି ରିପୋର୍ଟ କରନ୍ତୁ", "request-a-feature": "ଏକ ବିଶେଷତା ପାଇଁ ଅନୁରୋଧ କରନ୍ତୁ", "about-kiwix": "କିୱିକ୍ସ ବିଷଯ଼ରେ", "donate-to-support-kiwix": "କିୱିକ୍ସକୁ ସମର୍ଥନ କରିବା ପାଇଁ ଦାନ କରନ୍ତୁ", "exit": "ପ୍ରସ୍ଥାନ", "save-file-as-window-title": "ଫାଇଲକୁ ଏହିପରି ସଂରକ୍ଷଣ କରନ୍ତୁ", "download-finished-message": "ଡକ୍ଯ଼ୁମେଣ୍ଟଟି ଡାଉନଲୋଡ୍ ହୋଇଛି ।", "file": "ଫାଇଲ", "edit": "ସମ୍ପାଦନ କରନ୍ତୁ", "view": "ଦେଖନ୍ତୁ", "tools": "ଉପକରଣ", "window-title": "ଲାଇବ୍ରେରୀ - କିୱିକ୍ସ", "search": "ଖୋଜନ୍ତୁ", "browse-directory": "ଡିରେକ୍ଟୋରୀ ବ୍ରାଉଜ୍ କରନ୍ତୁ", "settings": "ସେଟିଂସମୂହ", "back": "ପଛକୁ", "forward": "ଆଗକୁ ବଢ଼ନ୍ତୁ", "search-files": "ଫାଇଲଗୁଡିକ ସନ୍ଧାନ କରନ୍ତୁ", "title": "ଶୀର୍ଷକ", "size": "ଆକାର", "date": "ତାରିଖ", "content-type": "ସୂଚୀପତ୍ର", "reset-sort": "ପୁନଃନିର୍ଦ୍ଧାରଣ କ୍ରମ", "open": "ଖୋଲନ୍ତ", "delete": "ଲିଭାନ୍ତୁ", "download": "ଡାଉନଲୋଡ଼", "resume": "ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ", "pause": "ବିରାମ", "cancel": "ବାତିଲ", "apply": "ଆବେଦନ କରନ୍ତୁ", "port-for-local-kiwix-server-setting": "ସ୍ଥାନୀଯ଼ କିୱିକ୍ସ ସର୍ଭର ପାଇଁ ପୋର୍ଟ", "zoom-level-setting": "ଡିଫଲ୍ଟ ଜୁମ୍ ସ୍ତର", "download-directory-setting": "ଡିରେକ୍ଟୋରୀ ଡାଉନଲୋଡ୍ କରନ୍ତୁ", "monitor-directory-setting": "ଡିରେକ୍ଟୋରୀକୁ ମନିଟର୍ କରନ୍ତୁ", "reset": "ପୁନଃସ୍ଥାପନ କରନ୍ତୁ", "clear": "ଲିଭାନ୍ତୁ", "browse": "ଖୋଜିବା", "about-kiwix-desktop-title": "କିୱିକ୍ସ ଡେସ୍କଟପ", "about-kiwix-desktop-description": "ଆପଣ ଯେଉଁଠିକି ଯାଆନ୍ତୁ , କିୱିକ୍ସ ଆପଣଙ୍କୁ ସମ୍ପୂର୍ଣ୍ଣ ୱିକିପିଡିଆ ହାତରେ ରଖିବାକୁ ଅନୁମତି ଦେଇଥାଏ । କୌଣସି ସ୍ଥାନର ମଝିରେ କିମ୍ବା ଜେଲ୍ରେ ଥିବା ଏକ ଡଙ୍ଗାରେ , କିୱିକ୍ସ ଆପଣଙ୍କୁ ସମସ୍ତ ମାନବ ଜ୍ଞାନକୁ ପ୍ରବେଶ ଦେଇଥାଏ । ଆପଣଙ୍କୁ ଇଣ୍ଟରନେଟ୍ର ଆବଶ୍ଯ଼କତା ନାହିଁ , କାରଣ ସବୁକିଛି ଆପଣଙ୍କ କମ୍ପ୍ଯ଼ୁଟରରେ ଗଚ୍ଛିତ ଅଛି ।", "about-learn-more-about-kiwix": "କିୱିକ୍ସ ବିଷୟରେ ଅଧିକ ଜାଣନ୍ତୁ", "about-release-title": "ରିଲିଜ୍", "about-source-code": "ଏହି ସଫ୍ଟୱେର୍ GNU ଜେନେରାଲ୍ ପବ୍ଲିକ୍ ଲାଇସେନ୍ସ ସଂସ୍କରଣ 3 ଅନୁଯାୟୀ ପ୍ରକାଶିତ ହୋଇଛି | Github ରେ ଉତ୍ସ କୋଡ୍ ଦେଖନ୍ତୁ |", "about-version": "ସଂସ୍କରଣ: {{VERSION}}", "about-reporting-problem-title": "ରିପୋର୍ଟ ସମସ୍ୟା", "about-report-issue": "ଏକ ସମସ୍ୟା ଖୋଲିବାକୁ, କିୱିକ୍ସ-ଡେସ୍କଟପ୍ ଇସ୍ୟୁ ଟ୍ରାକର୍ ପରିଦର୍ଶନ କରନ୍ତୁ ଏବଂ ଆପଣଙ୍କର ସମସ୍ୟା ବର୍ଣ୍ଣନା କରୁଥିବା ଏକ ସମସ୍ୟା ଖୋଲନ୍ତୁ |", "about-report-issue-2": "ଦଯ଼ାକରି ପ୍ରସଙ୍ଗଟିର ସଂସ୍କରଣ ବିଷଯ଼ରେ ଉଲ୍ଲେଖ କରନ୍ତୁ ।", "about-libraries-title": "ପାଠାଗାର", "kiwix-server-running-message": "କିୱିକ୍ସ ସର୍ଭର ଚାଲୁଛି ଏବଂ ସ୍ଥାନୀଯ଼ ନେଟୱର୍କରେ ଏଠାରେ ପ୍ରବେଶ କରାଯାଇପାରିବ:", "kiwix-server-description": "ଏକ ସର୍ଭର ଆରମ୍ଭ କରିବା ସ୍ଥାନୀୟ ନେଟୱାର୍କରେ ଥିବା ଅନ୍ୟ କମ୍ପ୍ୟୁଟରଗୁଡ଼ିକୁ ଏକ ଷ୍ଟାଣ୍ଡାର୍ଡ ୱେବ୍ ବ୍ରାଉଜର୍ ସହିତ ଆପଣଙ୍କର କିୱିକ୍ସ ଲାଇବ୍ରେରୀକୁ ପ୍ରବେଶ କରିବାକୁ ଅନୁମତି ଦିଏ |", "fullscreen-notification": "ଆପଣ ବର୍ତ୍ତମାନ ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ମୋଡ୍ ରେ ଅଛନ୍ତି | ଛାଡିବାକୁ ESC ଦବାନ୍ତୁ!", "online-files": "ଅନଲାଇନ୍ ଫାଇଲ୍ |", "local-files": "ସ୍ଥାନୀୟ ଫାଇଲ୍ |", "category": "ବର୍ଗ", "language": "ଭାଷା", "hide": "ଲୁଚାନ୍ତୁ |", "open-in-browser": "ବ୍ରାଉଜରରେ ଖୋଲନ୍ତୁ |", "start-kiwix-server": "କିୱିକ୍ସ ସର୍ଭର ଆରମ୍ଭ କରନ୍ତୁ", "stop-kiwix-server": "କିୱିକ୍ସ ସର୍ଭରକୁ ବନ୍ଦ କରନ୍ତୁ", "all": "ସମସ୍ତ", "fulltext-search": "ପୂର୍ଣ୍ଣ ପାଠ ସନ୍ଧାନ", "pictures": "ଛବିଗୁଡିକ", "videos": "ଭିଡିଓଗୁଡିକ", "ftindex": "ଫୁଲ୍ ଟେକ୍ସଟ୍ ଇଣ୍ଡେକ୍ସ", "details": "ପୂର୍ଣ୍ଣ ପ୍ରବନ୍ଧ", "yes": "ହଁ", "no": "ନାହିଁ", "ok": "ଠିକ୍ ଅଛି", "no-filter": "ଅଛଣା", "open-link-in-web-browser": "ୱେବ୍ ବ୍ରାଉଜରରେ ଲିଙ୍କ୍ ଖୋଲନ୍ତୁ", "download-dir-dialog-title": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଡାଉନଲୋଡ୍ ଡିରେକ୍ଟୋରୀ ପରିବର୍ତ୍ତନ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?", "download-dir-dialog-msg": "ନୂତନ ଡାଉନଲୋଡ୍ ଡିରେକ୍ଟୋରୀ ପଥ ହେବ: ${{DIRECTORY}}", "invalid-port": "ଅବୈଧ ପୋର୍ଟ", "zim-open-fail-title": "ଅବୈଧ ଫାଇଲ", "zim-open-fail-text": "ZIM ଫାଇଲ୍ ${{ZIM}} properly ସଠିକ୍ ଭାବରେ ଖୋଲାଯାଇପାରିବ ନାହିଁ | ଏହା ଆପଣଙ୍କ ଲାଇବ୍ରେରୀରୁ ଅପସାରିତ ହେବ |", "monitor-dir-dialog-title": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ମନିଟର ଡିରେକ୍ଟୋରୀକୁ ପରିବର୍ତ୍ତନ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?", "monitor-dir-dialog-msg": "ନୂତନ ମନିଟର ଡିରେକ୍ଟୋରୀ ପଥ ହେb: ${{DIRECTORY}}", "monitor-clear-dir-dialog-title": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ମନିଟର ଡିରେକ୍ଟୋରୀକୁ ସଫା କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?", "monitor-clear-dir-dialog-msg": "ଏହା ନୂତନ ZIM ଫାଇଲଗୁଡ଼ିକ ପାଇଁ ମନିଟର ଡିରେକ୍ଟୋରୀ ଯାଞ୍ଚ କରିବା ବନ୍ଦ କରିବ |", "monitor-directory-tooltip": "ଏହି ଡିରେକ୍ଟୋରୀରେ ଥିବା ସମସ୍ତ ZIM ଫାଇଲଗୁଡ଼ିକ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ଲାଇବ୍ରେରୀରେ ଯୋଡାଯିବ |", "next-tab": "ପରବର୍ତ୍ତୀ ଟ୍ୟାବକୁ ଯାଆନ୍ତୁ", "previous-tab": "ପୂର୍ବ ଟ୍ୟାବକୁ ଯାଆନ୍ତୁ |", "cancel-download": "ଡାଉନଲୋଡ୍ ବାତିଲ୍ କରନ୍ତୁ |", "cancel-download-text": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ${{ZIM}} of ର ଡାଉନଲୋଡ୍ ବାତିଲ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?", "delete-book": "ବହି ବିଲୋପ କରନ୍ତୁ |", "delete-book-text": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ {{ZIM}} ବିଲୋପ କରିବାକୁ ଚାହୁଁଛନ୍ତି?", "download-storage-error": "ସଂରକ୍ଷଣ ତ୍ରୁଟି", "download-storage-error-text": "ସିଷ୍ଟମରେ ପର୍ଯ୍ୟାପ୍ତ ଷ୍ଟୋରେଜ୍ ଉପଲବ୍ଧ ନାହିଁ |", "download-unavailable": "ଡାଉନଲୋଡ୍ ଉପଲବ୍ଧ ନାହିଁ |", "download-unavailable-text": "ଏହି ଡାଉନଲୋଡ୍ ଉପଲବ୍ଧ ନାହିଁ |", "open-book": "ଖୋଲା ପୁସ୍ତକ |", "download-book": "ବହି ଡାଉନଲୋଡ୍ କରନ୍ତୁ |", "pause-download": "ଡାଉନଲୋଡ୍ ବିରତି କରନ୍ତୁ |", "resume-download": "ଡାଉନଲୋଡ୍ ଆରମ୍ଭ କରନ୍ତୁ |", "open-folder": "ଫୋଲ୍ଡର ଖୋଲନ୍ତୁ", "couldnt-open-location": "ଅବସ୍ଥାନ ଖୋଲିପାରିଲା ନାହିଁ |", "couldnt-open-location-text": "କିୱିକ୍ସ ଫୋଲଡରକୁ ଖୋଲିବାରେ ସକ୍ଷମ ନୁହେଁ {{FOLDER}}", "move-files-to-trash": "ଅପସାରିତ ଫାଇଲଗୁଡ଼ିକୁ ଆବର୍ଜନା ଭଣ୍ଡାରକୁ ସ୍ଥାନାନ୍ତର କରନ୍ତୁ", "move-files-to-trash-text": "ଏହି କାର୍ଯ୍ଯ଼ ଫାଇଲଟିକୁ ଆବର୍ଜନା ପାତ୍ରକୁ ସ୍ଥାନାନ୍ତର କରିବ ।", "perma-delete-files-text": "ଏହି କ୍ରିୟା ଫାଇଲ୍ କୁ ସବୁଦିନ ପାଇଁ ଡିଲିଟ୍ କରିବ", "clear-filter": "ବର୍ତ୍ତମାନ ସେଟ ହୋଇଥିବା ଫିଲ୍ଟର୍ଗୁଡ଼ିକୁ ସଫା କରନ୍ତୁ", "language-searcher-placeholder": "ଭାଷା ଫିଲ୍ଟର୍ କରନ୍ତୁ", "category-searcher-placeholder": "ଫିଲ୍ଟର୍ ବର୍ଗ", "content-type-searcher-placeholder": "ବିଷୟବସ୍ତୁ ପ୍ରକାର ଫିଲ୍ଟର୍ କରନ୍ତୁ |", "no-details": "କେବଳ ପରିଚୟ", "no-pictures": "କୌଣସି ଚିତ୍ର ନାହିଁ", "no-videos": "କୌଣସି ଭିଡିଓ ନାହିଁ" } kiwix-desktop-2.4.1/resources/i18n/pl.json000066400000000000000000000144261473106011000204170ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "Pietrasagh", "Rail", "Rainbow P", "SRakestraw", "Strebski", "WaldiSt" ] }, "name": "Polski", "error-title": "Błąd", "error-downloader-window-title": "Nie można utworzyć pobierania", "error-downloader-launch-message": "Nie można uruchomić pobierania, uruchomi się Kiwix-desktop, ale wszystkie funkcje pobierania nie będą działać!", "error-launch-server-message": "Wystąpił błąd!", "open-zim": "Otwórz plik ZIM", "local-kiwix-server": "Lokalny serwer Kiwix", "random-article": "Losowy artykuł", "random-article-error": "Nie udało się otworzyć losowego artykułu.", "home-page": "Strona główna", "main-menu": "Menu główne", "print": "Drukuj", "print-page-error": "Wystąpił błąd podczas drukowania.", "new-tab": "Nowa zakładka", "close-tab": "Zamknij kartę", "close": "Zamknij", "reopen-closed-tab": "Otwórz zamknięta kartę ponownie", "browse-library": "Przeglądaj bibliotekę", "open-file": "Otwórz plik", "open-recent": "Otwórz ostatni", "search-article": "Wyszukaj artykuł", "search-in-library": "Szukaj w bibliotece", "find-in-page": "Znajdź na stronie", "set-fullscreen": "Ustaw pełny ekran", "quit-fullscreen": "Wyjdź z trybu pełnoekranowego", "table-of-content": "Spis treści", "reading-list": "Lista do przeczytania", "zoom-in": "Powiększ", "zoom-out": "Pomniejsz", "zoom-reset": "Resetowanie powiększenia", "help": "Pomoc", "feedback": "Opinie", "report-a-bug": "Zgłoś błąd", "request-a-feature": "Zaproponuj funkcję", "about-kiwix": "O Kiwix", "donate-to-support-kiwix": "Wspomóż rozwój Kiwix", "exit": "Wyjdź", "save-file-as-window-title": "Zapisz plik jako", "download-finished-message": "Dokument został pobrany", "file": "Plik", "edit": "Edytuj", "view": "Podgląd", "tools": "Narzędzia", "window-title": "Biblioteka - Kiwix", "search": "Szukaj", "browse-directory": "Przeglądaj katalog", "settings": "Ustawienia", "back": "Wstecz", "forward": "Dalej", "search-files": "Szukaj plików", "title": "Tytuł", "size": "Rozmiar", "date": "Data", "content-type": "Typ treści", "reset-sort": "resetowanie sortowania", "open": "Otwórz", "delete": "Usuń", "download": "Pobierz", "resume": "Ponów", "pause": "Pauza", "cancel": "Anuluj", "apply": "Zastosuj", "port-for-local-kiwix-server-setting": "Port dla lokalnego serwera Kiwix", "zoom-level-setting": "Domyślny poziom powiększenia", "download-directory-setting": "Pobierz katalog", "monitor-directory-setting": "Katalog monitorowany", "reset": "Resetuj", "clear": "Wyczyść", "browse": "Przeglądaj", "about-kiwix-desktop-title": "Pulpit Kiwix", "about-kiwix-desktop-description": "Kiwix pozwala mieć pod ręką całą Wikipedię, gdziekolwiek jesteś! Na łodzi, w szczerym polu lub w więzieniu, Kiwix daje ci dostęp do całej ludzkiej wiedzy. Nie potrzebujesz Internetu, wszystko jest przechowywane na Twoim komputerze.", "about-learn-more-about-kiwix": "Dowiedz się więcej o Kiwix", "about-release-title": "Wydanie", "about-source-code": "To oprogramowanie jest wydawane na warunkach Powszechnej Licencji Publicznej GNU w wersji 3. Zobacz kod źródłowy na Github.", "about-version": "Wersja: {{VERSION}}", "about-reporting-problem-title": "Zgłaszanie błędów", "about-report-issue": "Aby zgłosić problem odwiedź system śledzenia błędów w aplikacji Kiwix na komputery i stwórz nowy wpis opisujący Twój problem.", "about-report-issue-2": "Wspomnij proszę używaną przez Ciebie wersję we wpisie.", "about-libraries-title": "Biblioteki", "kiwix-server-running-message": "Serwer Kiwix jest uruchomiony i można uzyskać do niego dostęp w sieci lokalnej pod adresem:", "kiwix-server-description": "Uruchomienie serwera umożliwia innym komputerom w sieci lokalnej dostęp do biblioteki Kiwix za pomocą standardowej przeglądarki internetowej.", "fullscreen-notification": "Znajdujesz się w trybie pełnoekranowym. Naciśnij ESC aby z niego wyjść!", "local-files": "Pliki lokalne", "category": "Kategoria", "language": "Język", "hide": "Ukryj", "open-in-browser": "Otwórz w przeglądarce", "start-kiwix-server": "Uruchom serwer Kiwix", "stop-kiwix-server": "Zatrzymaj serwer Kiwix", "all": "Wszystkie", "fulltext-search": "Wyszukiwanie pełnotekstowe", "pictures": "Zdjęcia", "videos": "Filmy", "ftindex": "Indeks pełnotekstowy", "details": "Cały artykuł", "yes": "tak", "no": "nie", "ok": "ok", "no-filter": "brak filtra", "open-link-in-web-browser": "Otwórz link w przeglądarce", "open-link-new-tab": "Otwórz link w nowej karcie", "download-dir-dialog-title": "Czy na pewno chcesz zmienić katalog pobierania?", "download-dir-dialog-msg": "Nową ścieżką katalogu pobieranych plików będzie:\n{{DIRECTORY}}", "invalid-port": "Nieprawidłowy port", "zim-open-fail-title": "Niepoprawny plik", "zim-open-fail-text": "Nie można poprawnie otworzyć pliku ZIM {{ZIM}}. Zostanie usunięty z Twojej biblioteki.", "monitor-dir-dialog-title": "Czy na pewno chcesz zmienić katalog monitorowany?", "monitor-dir-dialog-msg": "Nową ścieżką katalogu monitorowanego będzie:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Czy na pewno chcesz wyczyścić katalog monitorowany?", "monitor-clear-dir-dialog-msg": "Spowoduje to zatrzymanie sprawdzania katalogu monitora w poszukiwaniu nowych plików ZIM.", "monitor-directory-tooltip": "Wszystkie pliki ZIM w tym katalogu zostaną automatycznie dodane do biblioteki.", "next-tab": "Przejdź do następnej karty", "previous-tab": "Przejdź do poprzedniej karty", "cancel-download": "Anuluj pobieranie", "cancel-download-text": "Czy na pewno chcesz anulować pobieranie {{ZIM}}?", "delete-book": "Usuń książkę", "delete-book-text": "Czy na pewno chcesz usunąć {{ZIM}}?", "download-book": "Pobierz książkę", "pause-download": "Wstrzymaj pobieranie", "resume-download": "Wznów pobieranie", "open-folder": "Otwórz folder", "couldnt-open-location": "Nie udało się otworzyć lokalizacji", "couldnt-open-location-text": "Kiwix nie może otworzyć folderu {{FOLDER}}", "move-files-to-trash": "Przenieś usunięte pliki do kosza", "move-files-to-trash-text": "Ta czynność spowoduje przeniesienie pliku do kosza.", "no-videos": "Brak filmów" } kiwix-desktop-2.4.1/resources/i18n/pt-br.json000066400000000000000000000212461473106011000210260ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Eduardo Addad de Oliveira", "Eduardoaddad", "Klgor1803", "McDutchie", "Obiru", "Saturnow", "YoReaper" ] }, "name": "Português do Brasil", "error-title": "Erro", "error-downloader-window-title": "Não é possível criar o downloader", "error-downloader-launch-message": "Impossível iniciar o downloader, o Kiwix-desktop será iniciado, mas todas as funções de download não funcionarão!", "error-launch-server-message": "Ocorreu um erro!", "error-archive": "Falha ao obter o arquivo", "open-zim": "Abrir Arquivo ZIM", "local-kiwix-server": "Servidor Kiwix local", "random-article": "Artigo aleatório", "random-article-error": "Falha ao abrir um artigo aleatório.", "home-page": "Página principal", "main-menu": "Menu principal", "print": "Imprimir", "print-page-error": "Ocorreu um erro durante a impressão.", "new-tab": "Nova guia", "close-tab": "Fechar guia", "close": "Fechar", "reopen-closed-tab": "Reabrir guia fechada", "browse-library": "Navegar na biblioteca", "open-file": "Abrir arquivo", "open-recent": "Aberto recentemente", "search-article": "Pesquisar artigo", "search-in-library": "Pesquisar na biblioteca", "find-in-page": "Encontrar na página", "set-fullscreen": "Definir tela cheia", "quit-fullscreen": "Sair da tela cheia", "table-of-content": "Tabela de conteúdo", "add-bookmark": "Adicionar na lista de leitura", "remove-bookmark": "Remover da lista lista de leitura", "reading-list": "Lista de leitura", "zoom-in": "Aumentar o zoom", "zoom-out": "Diminuir o zoom", "zoom-reset": "Redefinição de zoom", "help": "Ajuda", "feedback": "Comentário", "report-a-bug": "Relatar um erro", "request-a-feature": "Solicitar um recurso", "about-kiwix": "Sobre Kiwix", "donate-to-support-kiwix": "Doar para apoiar o Kiwix", "exit": "Sair", "save-file-as-window-title": "Salvar arquivo como", "download-finished-message": "O documento foi baixado.", "file": "Arquivo", "edit": "Editar", "view": "Visualizar", "tools": "Ferramentas", "window-title": "Biblioteca - Kiwix", "search": "Pesquisar", "browse-directory": "Procurar diretório", "settings": "Configurações", "back": "Voltar", "forward": "Encaminhar", "search-files": "Pesquisar arquivos", "title": "Título", "size": "Tamanho", "date": "Data", "content-type": "Tipo de conteúdo", "reset-sort": "redefinir classificação", "open": "Abrir", "delete": "Excluir", "download": "Baixar", "resume": "Retomar", "pause": "Pausar", "cancel": "Cancelar", "apply": "Aplicar", "port-for-local-kiwix-server-setting": "Porta para o servidor local Kiwix", "zoom-level-setting": "Nível padrão de zoom", "download-directory-setting": "Diretório de download", "monitor-directory-setting": "Diretório de monitoramento", "reset": "Redefinir", "clear": "Limpar", "browse": "Explorar", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "O Kiwix permite que você tenha toda a Wikipédia em mãos, onde quer que você vá! Em um barco, no meio do nada ou na cadeia, o Kiwix fornece acesso a todo o conhecimento humano. Você não precisa da Internet, tudo está armazenado no seu computador.", "about-learn-more-about-kiwix": "Saiba mais sobre o Kiwix", "about-release-title": "Lançamento", "about-source-code": "Este software é lançado sob os termos da GNU General Public License version 3. Veja o código fonte em Github.", "about-version": "Versão : {{VERSION}}", "about-reporting-problem-title": "Reportando problema(s)", "about-report-issue": "Para abrir um problema, visite Kiwix-desktop issue tracker e abra um problema descrevendo o seu problema.", "about-report-issue-2": "Por favor mencione a versão na edição.", "about-libraries-title": "Bibliotecas", "kiwix-server-running-message": "O servidor Kiwix está em execução e pode ser acessado na rede local em:", "kiwix-server-description": "Iniciar um servidor permite que outros computadores na rede local acessem sua biblioteca Kiwix com um navegador da Web padrão.", "fullscreen-notification": "Agora você está no modo de tela cheia. Pressione ESC para sair!", "online-files": "Arquivos Online", "local-files": "Arquivos locais", "category": "Categoria", "language": "Idioma", "hide": "Ocultar", "open-in-browser": "Abrir no navegador", "start-kiwix-server": "Inicie o servidor Kiwix", "stop-kiwix-server": "Parar o servidor Kiwix", "all": "Todos", "fulltext-search": "Pesquisa de texto completo", "pictures": "Fotografias", "videos": "Vídeos", "ftindex": "Índice de texto completo", "details": "Artigo completo", "yes": "sim", "no": "não", "ok": "ok", "no-filter": "sem filtro", "open-link-in-web-browser": "Abrir link no navegador da web", "open-link-new-tab": "Abrir o link em uma nova guia", "download-dir-dialog-title": "Tem certeza de que deseja alterar o diretório de download?", "download-dir-dialog-msg": "O novo caminho do diretório de download será:\n{{DIRECTORY}}", "invalid-port": "Porta inválida", "zim-open-fail-title": "Arquivo inválido", "zim-open-fail-text": "O arquivo ZIM {{ZIM}} não pôde ser aberto corretamente. Ele será removido da sua biblioteca.", "monitor-dir-dialog-title": "Tem certeza de que deseja alterar o diretório de monitoramento?", "monitor-dir-dialog-msg": "O novo caminho do diretório de monitoramento será:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Tem certeza de que deseja apagar o diretório de monitoramento?", "path-was-copied": "Caminho foi copiado", "monitor-clear-dir-dialog-msg": "Os arquivos pararão de serem checados no diretório de monitoramento para novos arquivos ZIM.", "monitor-directory-tooltip": "Todos os arquivos ZIM nesse diretório serão adicionados na biblioteca automaticamente.", "next-tab": "Mover para próxima guia", "previous-tab": "Mover para guia anterior", "cancel-download": "Cancelar download", "cancel-download-text": "Tem certeza de que deseja cancelar o download de {{ZIM}}?", "delete-book": "Apagar livro", "delete-book-text": "Tem certeza de que deseja apagar {{ZIM}}?", "download-storage-error": "Erro de Armazenamento", "download-storage-error-text": "O sistema não tem armazenamento suficiente.", "download-exceeds-max-file-size": "O tamanho do download excede o tamanho máximo do arquivo suportado pelo sistema.", "download-dir-missing": "O diretório de download não existe.", "download-dir-not-writable": "O diretório Download não pode ser escrito.", "download-unavailable": "Download Indisponível", "download-unavailable-text": "Esse download está indisponível", "open-book": "Abrir livro", "download-book": "Baixar livro", "pause-download": "Pausar download", "resume-download": "Continuar download", "open-folder": "Abrir pasta", "couldnt-open-location": "Não foi possível abrir o destino", "couldnt-open-location-text": "Kiwix não possui permissão para abrir a pasta {{FOLDER}}", "move-files-to-trash": "Mover arquivos apagados para lixeira", "move-files-to-trash-text": "Essa ação irá mover o arquivo para lixeira.", "perma-delete-files-text": "Essa ação irá apagar o arquivo permanentemente.", "clear-filter": "Limpar as configurações de filtros atuais", "language-searcher-placeholder": "Filtrar por idioma", "category-searcher-placeholder": "Filtrar por categoria", "content-type-searcher-placeholder": "Filtrar por tipo de conteúdo", "no-details": "Apenas introdução", "no-pictures": "Sem Imagens", "no-videos": "Sem Vídeos", "open-previous-tabs-at-startup": "Abrir guias anteriores ao iniciar", "preview-book-in-web-browser": "Pré-visualizar livro no navegador", "file-not-found-title": "Arquivo ZIM não encontrado", "file-not-found-text": "O arquivo ZIM não existe ou não pode ser lido", "zim-id": "Id do ZIM", "zim-name": "Nome do ZIM", "zim-path": "Caminho do arquivo ZIM", "bad-zim-file-error-page-title": "Arquivo ZIM inválido", "bad-zim-file-error-page-text": "O arquivo ZIM é inválido ou está corrompido.", "zim-entry-path": "Caminho de entrada do ZIM", "export-reading-list": "Exportar a lista de leitura", "export-reading-list-error": "Ocorreu um erro ao exportar a lista de leitura.", "import-reading-list": "Importar a lista de leitura", "import-reading-list-error": "Ocorreu um erro ao importar a lista de leitura.", "disable-sandbox": "O Kiwix foi aberto por um drive na rede. Isso é conhecido por causar problemas de compatibilidade ao navegar na sandbox. Como resultado, a sandbox vai ser desativada. Você quer prosseguir?", "save-page-as": "Salvar como...", "portable-disabled-tooltip": "Função desativada no modo portátil", "scroll-next-tab": "Rolar para a próxima aba", "scroll-previous-tab": "Mover para a aba anterior" } kiwix-desktop-2.4.1/resources/i18n/pt.json000066400000000000000000000027751473106011000204330ustar00rootroot00000000000000{ "@metadata": { "authors": [ "B3rnas", "Unamane" ] }, "name": "português", "open-zim": "Abrir Zim", "local-kiwix-server": "Servidor Kiwix local", "random-article": "Artigo aleatório", "home-page": "Página principal", "main-menu": "Menu principal", "print": "Imprimir", "browse-library": "Navegar na biblioteca", "open-file": "Abrir ficheiro", "open-recent": "Abrir recente", "search-article": "Pesquisar artigo", "search-in-library": "Pesquisar na biblioteca", "find-in-page": "Procura na página", "set-fullscreen": "Ver em ecrã completo", "quit-fullscreen": "Sair do ecrã completo", "table-of-content": "Índice", "add-bookmark": "Adicionar à lista de leitura", "remove-bookmark": "Remover da lista de leitura", "reading-list": "Lista de leitura", "zoom-in": "Ampliar", "zoom-out": "Reduzir", "help": "Ajuda", "feedback": "Comentários", "report-a-bug": "Reportar um erro", "request-a-feature": "Solicitar uma funcionalidade", "about-kiwix": "Sobre o Kiwix", "donate-to-support-kiwix": "Doar para apoiar o Kiwix", "exit": "Sair", "save-file-as-window-title": "Guardar ficheiro como", "download-finished-message": "O documento foi descarregado.", "file": "Ficheiro", "edit": "Editar", "view": "Ver", "tools": "Ferramentas", "window-title": "Biblioteca - Kiwix", "search": "Pesquisar", "date": "Data", "content-type": "Tipo de conteúdo", "open": "Abrir", "delete": "Eliminar", "download": "Descarregar", "resume": "Continuar", "pause": "Pausar", "cancel": "Cancelar" } kiwix-desktop-2.4.1/resources/i18n/qqq.json000066400000000000000000000401141473106011000205770ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Abijeet Patro", "Ajeje Brazorf", "Amire80", "Eihel", "Kuldeepburjbhalaike", "McDutchie", "Robby", "Verdy p" ] }, "name": "{{Doc-important|Don't write \"English\" in your language!}}\n\n'''Write the name of ''your'' language in its native script.'''\n\nCurrent language to which the string is being translated to.\n\nFor example, write \"français\" when translating to French, or \"Deutsch\" when translating to German.\n\n'''Important:''' Do not use your language’s word for “English”. Use the word that your language uses to refer to itself. If you translate this message to mean “English” in your language, your change will be reverted.", "error-title": "{{Identical|Error}}", "error-downloader-window-title": "Error text displayed when the ZIM file downloader failed to start on the local system.", "error-downloader-launch-message": "Error text displayed to elaborate on the effect of the downloader failure.", "error-launch-server-message": "Error text displayed when Kiwix server failed to launch.", "error-archive": "Error text displayed when the retrieving the archive of a ZIM file failed.", "error-opening-file": "Error text displayed when opening a downloaded file with an external application fails.", "open-zim": "Caption text for file explorer window used to choose a ZIM file.", "local-kiwix-server": "Describes a server hosted locally that contains the local kiwix library.", "random-article": "A randomly chosen article in a ZIM file.", "random-article-error": "Error text displayed when opening a random article in a ZIM file failed.", "home-page": "Return to the home or landing page of the ZIM file.", "main-menu": "Describes the menu that contains all user actions.", "print": "{{identical|Print}}", "print-page-error": "Error text displayed when printing the current web page into a file.", "new-tab": "Represents the action of opening a new, blank tab on the tab bar.", "close-tab": "Represents the action of closing a tab on the tab bar.", "close": "Represents the action of closing a displayed window.", "reopen-closed-tab": "Represents the action of reopen a tab that has just been closed.", "browse-library": "Represents the action of browsing the local kiwix library.", "open-file": "Represents the action of opening a file from the local file system.", "save-file": "Represents the action of saving a file to the local file system.", "open-recent": "Represents the action of choosing to open a file from those recently opened.", "search-article": "Represents the action of Searching for a article in the current ZIM file.", "search-in-library": "Represents the action of Searching for a text in the local Kiwix library.", "find-in-page": "Represents the action of searching for a text in the current article/page.", "set-fullscreen": "Represents the action of setting this desktop application to fill the entire computer screen.", "quit-fullscreen": "Represents the action of setting this desktop application back to its original, non-fullscreen dimensions.", "table-of-content": "Describes the table of content of an article.", "add-bookmark": "Represents the action of adding a page as a bookmark", "remove-bookmark": "Represents the action of removing a page from the bookmarks", "reading-list": "Describes a list of bookmarked articles.", "zoom-in": "Represents the action of zooming into the article, making the article content appear larger.", "zoom-out": "Represents the action of zooming out of the article, making the article content appear smaller.", "zoom-reset": "Represents the action of resetting the article zoom, changing the article content size back to default", "help": "{{identical|Help}}", "feedback": "{{identical|Feedback}}", "report-a-bug": "Represents the action of reporting a bug in this desktop application.", "request-a-feature": "Represents the action of requesting a new feature in this desktop application.", "about-kiwix": "Describes the about page of Kiwix, containing information of the organization.", "donate-to-support-kiwix": "Represents the action of donating to support the Kiwix Organization.", "exit": "Represents the action of exiting the desktop application", "save-file-as-window-title": "Title text of the window prompting user to save as a new file.", "download-finished": "Title of the message box announcing the completion of a download", "download-finished-message": "Text displayed when the download action has been completed", "file": "{{Identical|File}}", "edit": "{{Identical|Edit}}", "view": "{{Identical|View}}", "tools": "{{Identical|Tools}}", "window-title": "The title text displayed when the library browser is present", "search": "{{identical|Search}}", "browse-directory": "Represents the action of browsing the local file system for a directory.", "settings": "{{Identical|Settings}}", "back": "{{identical|Back}}", "forward": "{{Identical|Forward}}", "search-files": "Represents the action of searching online or locally for ZIM files.", "title": "{{identical|title}}", "size": "{{identical|size}}", "date": "{{identical|Date}}", "content-type": "Describes the type of contents available on a ZIM file, for example, text or pictures.", "reset-sort": "Represents the action of resetting the sorting of the items to default order.", "open": "{{Identical|Open}}", "delete": "{{identical|Delete}}", "download": "{{Identical|Download}}", "resume": "\"Resume\" here refers to continuing a task.", "pause": "{{identical|Pause}}", "cancel": "{{identical|Cancel}}", "apply": "{{identical|apply}}", "port-for-local-kiwix-server-setting": "Refers to the network port number on which the local Kiwix server will run.", "zoom-level-setting": "Describes the default zoom level of articles displayed on this desktop application.", "download-directory-setting": "Describes the directory in the file system where ZIM files will be downloaded to.", "monitor-directory-setting": "Describes the directory in the file system where we will monitor for ZIM file changes.", "reset": "{{Identical|reset}}", "clear": "\"Clear\" here refers to emptying something.", "browse": "{{Identical|Browse}}", "about-kiwix-desktop-title": "Describes the title of this desktop application", "about-kiwix-desktop-description": "Brief description of this desktop application.", "about-learn-more-about-kiwix": "Hyperlink text directing to more details about Kiwix.", "about-release-title": "Title text for the section on the release stages of this desktop application.", "about-source-code": "Describes the licensing of the source code used for this desktop application.", "about-version": "Describes the release version of this desktop application.", "about-reporting-problem-title": "Title text for the section for how to report a problem for this desktop applciation.", "about-report-issue": "Description of instructions on how to report an issue.", "about-report-issue-2": "Description of instructions on how to report an issue.", "about-libraries-title": "Title text for the section on what libraries are used in this desktop application.", "kiwix-server-running-message": "Text displayed when kiwix server has started running.", "kiwix-server-description": "Description text about capabilities of Kiwix server", "fullscreen-notification": "Notification Text displayed when the desktop application is set to fullscreen.", "online-files": "The ZIM files that can be found online.", "local-files": "The ZIM files that are stored locally.", "category": "{{Identical|Category}}", "language": "{{Identical|Language}}", "hide": "{{Identical|Hide}}", "open-in-browser": "Represents the action of opening a link in the native browser.", "start-kiwix-server": "Represents the action of starting the kiwix server.", "stop-kiwix-server": "Represents the action of stopping the running kiwix server.", "all": "{{Identical|All}}", "all_ips": "Indicates using all ips - dual stack mode on local server. \"Stack\" refers to the networking protocol standard to use: in this case, both IPv4 and IPv6.", "ipv4": "Indicates IPv4 mode on local server.", "ipv6": "Indicates IPv6 mode on local server", "fulltext-search": "Represents the action of searching the text appearances in all the articles in a ZIM file.", "pictures": "{{identical|Picture}}", "videos": "{{identical|Video}}", "ftindex": "Text indicating that fulltext search is supported", "details": "A content type for ZIM files representing it has more than just an introduction.", "yes": "{{identical|yes}}", "no": "{{identical|no}}", "ok": "{{Identical|Ok}}", "no-filter": "No filter selected for searches.", "open-link-in-web-browser": "Ouvrir le lien dans le navigateur", "open-link-new-tab": "Represents the action of opening a hyperlink in an article in a new tab.", "download-dir-dialog-title": "A question to confirm the action to change the download directory.", "download-dir-dialog-msg": "Please note that {{DIRECTORY}} should be placed on a newline.", "invalid-port": "Error text displayed when the port selected is invalid in the local system.", "zim-open-fail-title": "Error title text for the situation when opening a file as a ZIM file failed.", "zim-open-fail-text": "Error description text for when opening a file as a ZIM file failed.", "monitor-dir-dialog-title": "\"Monitor\" means \"watch\" in this context. The monitor directory is monitored/watched for new ZIM files.", "monitor-dir-dialog-msg": "\"Monitor\" means \"watch\" in this context. The monitor directory is monitored/watched for new ZIM files.", "monitor-clear-dir-dialog-title": "\"Monitor\" means \"watch\" in this context. The monitor directory is monitored/watched for new ZIM files.", "path-was-copied": "Tooltip confirming that the download path from settings was copied.", "monitor-clear-dir-dialog-msg": "\"Monitor\" means \"watch\" in this context. The monitor directory is monitored/watched for new ZIM files.", "monitor-directory-tooltip": "Description text on what the monitor directory does.", "next-tab": "Represents the action of switching to the next tab with respect to the current tab.", "previous-tab": "Represents the action of switching to the previous tab with respect to the current tab.", "cancel-download": "Represents the action of cancelling an on-going download of a ZIM file.", "cancel-download-text": "A question to confirm the action to cancel the download of a ZIM file.", "delete-book": "Represents the action of deleting an existing ZIM file.", "delete-book-text": "A question to confirm the action to delete an existing ZIM file.", "download-storage-error": "Error title text displayed when something is wrong with the directory of storage for ZIM files", "download-storage-error-text": "Error description text for when something is wrong with the directory of storage for ZIM files.", "download-exceeds-max-file-size": "Error text for the case when the download size exceeds the maximum files size of the filesystem where the download is going to be saved. Reported before the download is started.", "download-dir-missing": "Error text displayed when it turns out that the download directory doesn't exist.", "download-dir-not-writable": "Error text displayed when files cannot be created/saved in the download directory due to permissions", "download-unavailable": "Error title text displayed when the downloading functionality is not available.", "download-unavailable-text": "Error description text displayed when the downloading functionality is not available.", "open-book": "\"Open\" is a imperative, not an adjective.", "download-book": "Represents the action of downloading a ZIM file book.", "pause-download": "Represents the action of pausing an on-going download of a ZIM file.", "resume-download": "Represents the action of resuming a paused download of a ZIM file.", "open-folder": "Represents the action of opening a folder in the file system.", "couldnt-open-location": "Error title text displayed when opening a folder in the file system failed.", "couldnt-open-location-text": "Error description text for when opening a folder in the file system failed.", "move-files-to-trash": "Represents the action of moving ZIM files to trash, similar to deleting them.", "move-files-to-trash-text": "Description text for the action of moving ZIM files to trash, similar to deleting them.", "perma-delete-files-text": "Description text for the action of permanently deleting ZIM files.", "clear-filter": "Represents the action of clearing the filters selected for a filter type.", "language-searcher-placeholder": "Placeholder text displayed to indicate the ZIM file searcher will filter by language", "category-searcher-placeholder": "Placeholder text displayed to indicate the ZIM file searcher will filter by category", "content-type-searcher-placeholder": "Placeholder text displayed to indicate the ZIM file searcher will filter by content type", "no-details": "A content type for ZIM files representing it only has an introduction.", "no-pictures": "A content type for ZIM files that does not contain pictures.", "no-videos": "A content type for ZIM files that does not contain videos.", "open-previous-tabs-at-startup": "The tabs that were open when the user closed the application is opened again when the application is restarted.", "preview-book-in-web-browser": "Preview this book by opening the link to its preview website in the native web browser", "file-not-found-title": "Error title text displayed when the desktop application cannot find the ZIM file needed to display the web page.", "file-not-found-text": "Error description text for when the desktop application cannot find the ZIM file needed to display the web page.", "zim-id": "The term for the unique identifier of a ZIM file.", "zim-name": "The term for the name of a ZIM file", "zim-path": "The term for the path of a ZIM file", "bad-zim-file-error-page-title": "Error title text displayed when the ZIM file appears to be invalid or corrupted", "bad-zim-file-error-page-text": "Error description text displayed when the ZIM file appears to be invalid or corrupted", "zim-entry-path": "The term for the path of an entry inside a ZIM file", "export-reading-list": "Represents the action of exporting the reading list to a file.", "export-reading-list-error": "Error description text for when exporting the reading list to a file failed.", "import-reading-list": "Represents the action of importing a reading list from a file.", "import-reading-list-error": "Error description text for when importing a reading list from a file failed.", "disable-sandbox": "Question description text for when disabling the sandbox feature (Windows network drive), asking the user if he wants to proceed.", "save-page-as": "Represents the action of saving the current tab content to a file chosen by the user.", "portable-disabled-tooltip": "Tooltip used to explain disabled components in the portable version.", "scroll-next-tab": "Represents the action of scrolling to the next tab of the current tab which toward the end of the tab bar.", "scroll-previous-tab": "Represents the action of scrolling to the previous tab of the current tab which toward the start of the tab bar.", "kiwix-search": "Title text for a list of search results, which notes to the user those are from Kiwix's Search Engine", "search-options": "The term for a collection of additional search filtering options to help users narrow down search results.", "read-article": "Represents the action of letting the computer read aloud all the text in the current article.", "read-text": "Represents the action of letting the computer read out the selected text on the article.", "read-stop": "Represents the action of stopping the on-going reading.", "stop": "{{Identical|Stop}}", "voice": "{{Identical|Voice}}", "select-read-voice": "Represents the action of opening the voice selection for text-to-speech.", "select-read-language": "Represents the action of opening the language selection for text-to-speech.", "save-or-open": "Title of the message box allowing to choose whether a remote resource should be saved to disk or opened with a respective application", "save-or-open-text": "Text of the message box allowing to choose whether a remote resource should be saved to disk or opened with a respective application" } kiwix-desktop-2.4.1/resources/i18n/ro.json000066400000000000000000000111141473106011000204130ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Andreyyshore", "MSClaudiu", "Trotinel Iftode" ] }, "name": "Română", "error-title": "Eroare", "error-downloader-window-title": "Nu se poate lansa sistemul de descărcare", "error-downloader-launch-message": "Imposibil de lansat programul de descărcare, Kiwix-desktop va începe, dar toate funcțiile de descărcare nu vor funcționa !", "error-launch-server-message": "A apărut o eroare !", "open-zim": "Deschide Zim", "local-kiwix-server": "Server Kiwix Local", "random-article": "Articol Aleatoriu", "home-page": "Pagina principală", "main-menu": "Meniu principal", "print": "Imprimă", "new-tab": "Filă nouă", "close-tab": "Închide fila", "close": "Închide", "reopen-closed-tab": "Redeschideți fila închisă", "browse-library": "Căutați în bibliotecă", "open-file": "Deschide fișierul", "open-recent": "Deschideți recent", "search-article": "Caută articol", "search-in-library": "Căutați în bibliotecă", "find-in-page": "Găsește în pagină", "set-fullscreen": "Setează ecran complet", "quit-fullscreen": "Ieșire ecran complet", "table-of-content": "Cuprins", "reading-list": "Listă de citit", "zoom-in": "Mărește", "zoom-out": "Micșorează", "zoom-reset": "Reset zoom", "help": "Ajutor", "feedback": "Părere", "report-a-bug": "Raportează un bug", "request-a-feature": "Solicitați o caracteristică", "about-kiwix": "Despre Kiwix", "donate-to-support-kiwix": "Donează pentru a sprijini Kiwix", "exit": "Ieșire", "save-file-as-window-title": "Salvați fișierul ca", "download-finished-message": "Documentul a fost descărcat.", "file": "Fișier", "edit": "Modifică", "view": "Vezi", "tools": "Unelte", "window-title": "Biblioteca - Kiwix", "search": "Caută", "browse-directory": "Căutați în Director", "settings": "Setări", "back": "Înapoi", "forward": "Înainte", "search-files": "Caută fișiere", "title": "Titlu", "size": "Mărime", "date": "Data", "content-type": "Tipul de conținut", "reset-sort": "resetare sort", "open": "Deschis", "delete": "Șterge", "download": "Descarcă", "resume": "Reia", "pause": "Pauză", "cancel": "Anulare", "apply": "Aplică", "port-for-local-kiwix-server-setting": "Port pentru serverul local Kiwix:", "zoom-level-setting": "Nivel Zoom :", "download-directory-setting": "Director de descărcare :", "reset": "Resetează", "browse": "Caută", "about-kiwix-desktop-title": "Kiwix pentru PC", "about-kiwix-desktop-description": "Kiwix vă permite să aveți toată Wikipedia la îndemână oriunde mergeți! Pe o barcă, în mijlocul la pustietății sau în închisoare, Kiwix vă oferă acces la toată cunoașterea umană. Nu aveți nevoie de internet, totul este descărcat în computerul dumneavoastră.", "about-learn-more-about-kiwix": "Aflați mai multe despre Kiwix", "about-release-title": "Lansat", "about-source-code": "Acest software este lansat în conformitate cu licența GNU General Public versiunea 3. Vizualizați codul sursă pe Github .", "about-version": "Versiunea : {{VERSION}}", "about-reporting-problem-title": "Semnalare problemă", "about-report-issue": "Pentru a transmite o problemă, vizitează Kiwix-urmărește probleme computer și deschide o discuție care descrie problema ta.", "about-report-issue-2": "Vă rugăm să menționați versiunea în problemă.", "about-libraries-title": "Biblioteci", "kiwix-server-running-message": "Serverul Kiwix rulează și poate fi accesat în rețeaua locală la:", "kiwix-server-description": "Pornirea unui server permite altor computere din rețeaua locală să acceseze biblioteca dvs. Kiwix cu un browser web standard.", "fullscreen-notification": "Acum sunteți în modul ecran complet. Apăsați ESC pentru a renunța!", "local-files": "Fișiere Locale", "hide": "Ascunde", "open-in-browser": "Deschide în browser", "start-kiwix-server": "Porniți Serverul Kiwix", "stop-kiwix-server": "Oprește Serverul Kiwix", "all": "Toate", "fulltext-search": "Caută text întreg", "pictures": "Fotografii", "videos": "Videouri", "ftindex": "Index complet", "details": "Articol complet", "yes": "da", "no": "nu", "no-filter": "fără filtru", "open-link-in-web-browser": "Deschide legătura în browserul web", "download-dir-dialog-title": "Sunteți sigur(ă) că vreți să schimbați folderul de descărcare?", "download-dir-dialog-msg": "Noua cale pentru folderul de descărcare va fi: {{DIRECTORY}}", "invalid-port": "Port invalid", "read-text": "Citiți textul selectat", "select-read-voice": "Selectați vocea de citire" } kiwix-desktop-2.4.1/resources/i18n/roa-tara.json000066400000000000000000000032461473106011000215100ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Joetaras", "McDutchie" ] }, "name": "Tarandíne", "open-zim": "Iapre fail Zim", "local-kiwix-server": "Server locale de Kiwix", "home-page": "Pàgena prengepàle", "print": "Stambe", "new-tab": "Scheda nove", "close-tab": "Achiude 'a schede", "browse-library": "Sfogghie 'a libbrerie", "open-file": "Iapre 'u file", "open-recent": "Iapre le urteme", "search-article": "Cirche 'a vôsce", "set-fullscreen": "Tràse jndr'à 'u scherme indere", "quit-fullscreen": "Isse da 'u scherme indere", "zoom-in": "Cchiù granne", "zoom-out": "Cchiù peccinne", "zoom-reset": "Azzere 'u zoom", "help": "Aijute", "feedback": "Segnalazione", "report-a-bug": "Segnale 'n'errore", "about-kiwix": "Sus a Kiwix", "exit": "Isse", "file": "File", "edit": "Cange", "view": "'Ndruche", "tools": "Struminde", "search": "Cirche", "settings": "'Mbostaziune", "back": "Rrete", "forward": "Inoltre", "search-files": "Cirche le file", "title": "Titole", "size": "Dimenzione", "content-type": "Tipe de condenute", "reset-sort": "azzere l'ordenamende", "open": "Iapre", "delete": "Scangìlle", "resume": "Repigghie", "pause": "Pause", "cancel": "Annulle", "apply": "Appleche", "zoom-level-setting": "Levèlle de zoom predefinite", "download-directory-setting": "Cartelle de le scarecamiende", "reset": "Azzere", "browse": "Sfoglie", "about-version": "Versione : {{VERSION}}", "about-reporting-problem-title": "Segnale 'nu probbleme", "about-libraries-title": "Libbrerie", "local-files": "File locale", "hide": "Scunne", "open-in-browser": "Iapre jndr'à 'u browser", "all": "Tutte", "fulltext-search": "Recerche jdnr'à tutte 'u teste" } kiwix-desktop-2.4.1/resources/i18n/ru.json000066400000000000000000000276171473106011000204400ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Adam-Yourist", "DDPAT", "Diman Russkov", "Dirruw'o", "Firapinch", "Helpau", "Ice bulldog", "Kareyac", "Lutece398", "Okras", "Pacha Tchernof", "Razno0", "Rofiatmustapha12", "Smavrina", "StarryFairy", "Tanzun", "Артём 13327" ] }, "name": "русский", "error-title": "Ошибка", "error-downloader-window-title": "Невозможно создать загрузчик", "error-downloader-launch-message": "Невозможно запустить загрузчик, Kiwix для рабочего стола будет запущен, но все функции скачивания будут недоступны!", "error-launch-server-message": "Произошла ошибка!", "error-archive": "Не удалось получить архив", "open-zim": "Открыть Zim-файл", "local-kiwix-server": "Локальный сервер Kiwix", "random-article": "Случайная статья", "random-article-error": "Не удалось открыть случайную статью.", "home-page": "Домашняя страница", "main-menu": "Главное меню", "print": "Печать", "print-page-error": "Во время печати возникла ошибка.", "new-tab": "Новая вкладка", "close-tab": "Закрыть вкладку", "close": "Закрыть", "reopen-closed-tab": "Открыть закрытую вкладку снова", "browse-library": "Просмотр библиотеки", "open-file": "Открыть файл", "open-recent": "Открыть недавние", "search-article": "Искать статью", "search-in-library": "Поиск в библиотеке", "find-in-page": "Найти на странице", "set-fullscreen": "Установить полноэкранный режим", "quit-fullscreen": "Выйти из полноэкранного режима", "table-of-content": "Содержание", "add-bookmark": "Добавить список для чтения", "remove-bookmark": "Удалить из списка для чтения", "reading-list": "Список для чтения", "zoom-in": "Приблизить", "zoom-out": "Отдалить", "zoom-reset": "Сбросить масштаб", "help": "Справка", "feedback": "Обратная связь", "report-a-bug": "Сообщить об ошибке", "request-a-feature": "Предложить новую функцию", "about-kiwix": "О Kiwix", "donate-to-support-kiwix": "Поддержать Kiwix", "exit": "Выйти", "save-file-as-window-title": "Сохранить файл как", "download-finished-message": "Документ был загружен.", "file": "Файл", "edit": "Изменить", "view": "Посмотреть", "tools": "Инструменты", "window-title": "Библиотека - Kiwix", "search": "Поиск", "browse-directory": "Просмотр Папки", "settings": "Настройки", "back": "Назад", "forward": "Вперёд", "search-files": "Искать файлы", "title": "Заголовок", "size": "Размер", "date": "Дата", "content-type": "Тип контента", "reset-sort": "сбросить сортировку", "open": "Открыть", "delete": "Удалить", "download": "Скачать", "resume": "Продолжить", "pause": "Пауза", "cancel": "Отменить", "apply": "Применить", "port-for-local-kiwix-server-setting": "Порт для локального сервера Kiwix", "zoom-level-setting": "Уровень масштабирования по умолчанию", "download-directory-setting": "Папка для загрузок", "monitor-directory-setting": "Директория на дисплее", "reset": "Сбросить", "clear": "Очистить", "browse": "Обзор", "about-kiwix-desktop-title": "Kiwix для ПК", "about-kiwix-desktop-description": "С Kiwix вся Википедия у вас под рукой, куда бы вы не отправились! На корабле, в далёкой глуши или даже в тюрьме, с Kiwix вам доступны все знания человечества. Для доступа вам не понадобится интернет, всё сохранено на вашем компьютере.", "about-learn-more-about-kiwix": "Подробнее о Kiwix", "about-release-title": "Релиз", "about-source-code": "Это программное обеспечение выпущено под условиями GNU General Public License версии 3. Исходный код доступен по адресу Github.", "about-version": "Версия: {{VERSION}}", "about-reporting-problem-title": "Сообщить о проблемах", "about-report-issue": "Чтобы сообщить об ошибке, перейдите по адресу Kiwix-desktop issue tracker и создайте новое сообщение, описав вашу проблему.", "about-report-issue-2": "Пожалуйста, укажите версию в вашем сообщении.", "about-libraries-title": "Библиотеки", "kiwix-server-running-message": "Сервер Kiwix запущен и доступен в локальной сети как:", "kiwix-server-description": "Запуск сервера позволит другим компьютерам в локальной сети получить доступ к вашей библиотеке Kiwix через обычный веб-браузер.", "fullscreen-notification": "Вы находитесь в полноэкранном режиме. Нажмите ESC для выхода!", "online-files": "Онлайн-файлы", "local-files": "Локальный файлы", "category": "Категория", "language": "Язык", "hide": "Скрыть", "open-in-browser": "Открыть в браузере", "start-kiwix-server": "Запустить сервер Kiwix", "stop-kiwix-server": "Остановить сервер Kiwix", "all": "Все", "fulltext-search": "Полнотекстовый поиск", "pictures": "Изображения", "videos": "Видео", "ftindex": "Полнотекстовый индекс", "details": "Полная статья", "yes": "да", "no": "нет", "ok": "ок", "no-filter": "без фильтра", "open-link-in-web-browser": "Открыть ссылку в веб-браузере", "open-link-new-tab": "Открыть в новой вкладке", "download-dir-dialog-title": "Вы уверены, что хотите изменить папку для загрузок?", "download-dir-dialog-msg": "Путь к новой папке для загрузок:\n{{DIRECTORY}}", "invalid-port": "Некорректный порт", "zim-open-fail-title": "Недопустимый файл", "zim-open-fail-text": "Указанный ZIM-файл {{ZIM}} не может быть открыт корректно. Он будет удалён из вашей библиотеки.", "monitor-dir-dialog-title": "Вы действительно хотите изменить директорию монитора?", "monitor-dir-dialog-msg": "Путь к новой директории монитора: \n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Вы действительно хотите очистить директорию монитора?", "path-was-copied": "Путь скопирован", "monitor-clear-dir-dialog-msg": "Это остановит проверку директории монитора на наличие новых файлов в формате ZIM.", "monitor-directory-tooltip": "Все файлы ZIM в этой директории будут автоматически добавлены в библиотеку.", "next-tab": "Перейти к следующей вкладке", "previous-tab": "Перейти к предыдущей вкладке", "cancel-download": "Отменить загрузку", "cancel-download-text": "Вы уверены, что хотите отменить загрузку {{ZIM}}?", "delete-book": "Удалить книгу", "delete-book-text": "Вы уверены, что хотите удалить {{ZIM}}?", "download-storage-error": "Ошибка хранилища", "download-storage-error-text": "В системе недостаточно свободного места.", "download-exceeds-max-file-size": "Размер загружаемого файла превышает максимальный размер файла, поддерживаемый целевой файловой системой.", "download-dir-missing": "Каталог загрузки не существует.", "download-dir-not-writable": "Каталог загрузки недоступен для записи.", "download-unavailable": "Загрузка недоступна", "download-unavailable-text": "Эта загрузка недоступна.", "open-book": "Открыть книгу", "download-book": "Скачать книгу", "pause-download": "Приостановить загрузку", "resume-download": "Возобновить загрузку", "open-folder": "Открыть папку", "couldnt-open-location": "Не удалось открыть местоположение", "couldnt-open-location-text": "Kiwix не может открыть папку {{FOLDER}}", "move-files-to-trash": "Переместить удаленные файлы в корзину", "move-files-to-trash-text": "Это действие переместит файл в корзину.", "perma-delete-files-text": "Это действие навсегда удалит файл.", "clear-filter": "Очистить текущие установленные фильтры", "language-searcher-placeholder": "Фильтр по языку", "category-searcher-placeholder": "Фильтр по категории", "content-type-searcher-placeholder": "Фильтр по типу контента", "no-details": "Только введение", "no-pictures": "Без картинок", "no-videos": "Без видео", "open-previous-tabs-at-startup": "Открыть предыдущие вкладки при запуске", "preview-book-in-web-browser": "Предварительный просмотр книги в веб-браузере", "file-not-found-title": "Файл ZIM не найден", "file-not-found-text": "ZIM-файл не существует или не может быть прочитан", "zim-id": "ZIM-идентификатор", "zim-name": "Имя ZIM-файла", "zim-path": "Путь к ZIM-файлу", "bad-zim-file-error-page-title": "Недействительный ZIM-файл", "bad-zim-file-error-page-text": "ZIM-файл недействителен или поврежден.", "zim-entry-path": "Путь входа ZIM", "export-reading-list": "Экспортировать список чтения", "export-reading-list-error": "Ошибка при экспорте списка чтения.", "import-reading-list": "Импортировать список чтения", "import-reading-list-error": "Ошибка при импорте списка чтения.", "disable-sandbox": "Приложение было запущено с сетевого диска. Известно, что это может вызвать проблемы с совместимостью из-за песочницы. Хотите ли вы рискнуть и отключить его?", "save-page-as": "Сохранить как...", "portable-disabled-tooltip": "В портативном режиме функция отключена", "scroll-next-tab": "Перейти к следующей вкладке" } kiwix-desktop-2.4.1/resources/i18n/sc.json000066400000000000000000000166251473106011000204140ustar00rootroot00000000000000{ "@metadata": { "authors": [ "L2212" ] }, "name": "Sardu", "error-title": "Faddina", "error-downloader-window-title": "Impossìbile creare s'iscarrigadore", "error-downloader-launch-message": "Impossìbile carrigare s'iscarrigadore, Kiwix-desktop s'at a abèrrere ma totu sas funtzionalidades de iscarrigamentu no ant a funtzionare!", "error-launch-server-message": "B'at àpidu una faddina|", "error-archive": "No at fatu a otènnere s'archìviu", "open-zim": "Aberi un'archìviu Zim", "local-kiwix-server": "Serbidore Kiwix locale", "random-article": "Artìculu a sa tzurpa", "random-article-error": "Abertura de un'artìculu a casu fallida.", "home-page": "Pàgina printzipale", "main-menu": "Menù printzipale", "print": "Imprenta", "print-page-error": "B'at àpidu un'errore imprentende.", "new-tab": "Ischeda noa", "close-tab": "Serra s'ischeda", "close": "Serra", "reopen-closed-tab": "Torra a abèrrere s'ischeda serrada", "browse-library": "Esplora sa biblioteca", "open-file": "Aberi unu documentu", "open-recent": "Aberi documentos reghentes", "search-article": "Chirca un'artìculu", "search-in-library": "Chirca in sa biblioteca", "find-in-page": "Agata in sa pàgina", "set-fullscreen": "Imposta a ischermu intreu", "quit-fullscreen": "Essi dae s'ischermu intreu", "table-of-content": "Summàriu", "reading-list": "Lista de leghidura", "zoom-in": "Ismànnia", "zoom-out": "Mìnima", "zoom-reset": "Reimposta s'ismanniamentu", "help": "Agiudu", "feedback": "Cummentos", "report-a-bug": "Sinnala un'errore", "request-a-feature": "Pedi una funtzionalidade", "about-kiwix": "In subra de Kiwix", "donate-to-support-kiwix": "Dona pro sustentare Kiwix", "exit": "Essi", "save-file-as-window-title": "Sarva su documentu comente", "download-finished-message": "Su documentu est istadu iscarrigadu.", "file": "Documentu", "edit": "Modìfica", "view": "Ammustra", "tools": "Ainas", "window-title": "Biblioteca - Kiwix", "search": "Chirca", "browse-directory": "Esplora una cartella", "settings": "Impostatziones", "back": "In segus", "forward": "In antis", "search-files": "Chirca documentos", "title": "Tìtulu", "size": "Mannària", "date": "Data", "content-type": "Casta de cuntenutu", "reset-sort": "reimposta s'ordinamentu", "open": "Aberi", "delete": "Iscantzella", "download": "Iscàrriga", "resume": "Sighi", "pause": "Pàusa", "cancel": "Annulla", "apply": "Àplica", "port-for-local-kiwix-server-setting": "Ghenna pro su serbidore locale de Kiwix", "zoom-level-setting": "Livellu de ismanniamentu predefinidu", "download-directory-setting": "Cartella de iscarrigamentu", "monitor-directory-setting": "Cartella de compidada", "reset": "Reseta", "clear": "Isbòida", "browse": "Esplora", "about-kiwix-desktop-title": "Kiwix pro iscrivania", "about-kiwix-desktop-description": "Kiwix ti permitit de tènnere sa Wikipedia intrea a portada de manu in cale si siat logu tue ue as a andare! In una barca, in mesu a su nudda o in presone, Kiwix ti dat atzessu a totu sa connoschèntzia umana. Non bisòngias de ìnternet, totu est sarvadu in s'elaboradore tuo.", "about-learn-more-about-kiwix": "Impara de prus subra de Kiwix", "about-release-title": "Intregada", "about-source-code": "Custu programma benit intregadu sighende sos tèrmines de sa litzèntzia GNU General Public License versione 3. Pòmpia·ti su còdighe de orìgine in Github.", "about-version": "Versione: {{VERSION}}", "about-reporting-problem-title": "Sinnalare problemas", "about-report-issue": "Pro abèrrere una sinnalatzione, bìsita s'arrastadore pro Kiwix pro elaboradores de iscrivania (Kiwix-desktop) e aberi una sinnalatzione in ue descries su problema tuo.", "about-report-issue-2": "Pro praghere mentova sa versione in sa sinnalatzione.", "about-libraries-title": "Librerias", "kiwix-server-running-message": "Su serbidore de Kiwix est in funtzione e bi podes atzèdere in sa retza locale dae:", "kiwix-server-description": "Aviare unu serbidore permitit a sos àteros eleboradores in sa retza locale de tènnere atzessu a sa biblioteca locale de Kiwix tua cun unu navigadore (browser) istandard.", "fullscreen-notification": "Como ses in modalidade a ischermu intreu. Incarca ESC pro essire!", "online-files": "Documentos in lìnia", "local-files": "Documentos locales", "category": "Categoria", "language": "Limba", "hide": "Cua", "open-in-browser": "Aberi in su navigadore (browser)", "start-kiwix-server": "Avia su serbidore de Kiwix", "stop-kiwix-server": "Firma su serbidore de Kiwix", "all": "Totu", "fulltext-search": "Chirca in su testu intreu", "pictures": "Immàgines", "videos": "Vìdeos", "ftindex": "Ìnditze in testu intreu", "details": "Artìculu intreu", "yes": "eja", "no": "nono", "ok": "ab", "no-filter": "perunu filtru", "open-link-in-web-browser": "Aberi su ligàmene in su navigadore web", "download-dir-dialog-title": "Ses seguru de chèrrere mudare sa cartella de iscarrigamentu?", "download-dir-dialog-msg": "S'àndala pro sa cartella de iscarrigamentu noa at a èssere:\n{{DIRECTORY}}", "invalid-port": "Ghenna non bàlida", "zim-open-fail-title": "Documentu non bàlidu", "zim-open-fail-text": "Su documentu ZIM {{ZIM}} non si podet abèrrere comente si tocat. S'at a bogare dae sa biblioteca tua.", "monitor-dir-dialog-title": "Ses seguru de chèrrere mudare sa cartella de compidada?", "monitor-dir-dialog-msg": "S'àndala pro sa cartella de compidada noa at a èssere:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ses seguru de chèrrere isboidare sa cartella de compidada?", "monitor-clear-dir-dialog-msg": "Custu at a firmare sa chirca de archìvios ZIM noos in sa cartella de compidada.", "monitor-directory-tooltip": "Totu sos archìvios ZIM in custa cartella s'ant a annànghere in automàticu a sa biblioteca.", "next-tab": "Cola a s'ischeda imbeniente", "previous-tab": "Cola a s'ischeda anteposta", "cancel-download": "Annulla s'iscarrigamentu", "cancel-download-text": "Ses seguru de chèrrere annullare s'iscarrigamentu de {{ZIM}}?", "delete-book": "Iscantzella su libru", "delete-book-text": "Ses seguru de chèrrere iscantzellare {{ZIM}}?", "download-storage-error": "Errore de archiviatzione", "download-storage-error-text": "Su sistema non tenet memòria bastante a disponimentu.", "download-unavailable": "Iscarrigamentu no a disponimentu", "download-unavailable-text": "Custu iscarrigamentu no est a disponimentu.", "open-book": "Aberi su libru", "download-book": "Iscàrriga su libru", "pause-download": "Pone in pàusa s'iscarrigamentu", "resume-download": "Faghe torrare a incumintzare s'iscarrigamentu", "open-folder": "Aberi sa cartella", "couldnt-open-location": "Non faghiat a abèrrere sa positzione", "couldnt-open-location-text": "Kiwix no est in gradu de abèrrere sa cartella {{FOLDER}}", "move-files-to-trash": "Move sos documentos iscarrigados a s'arga", "move-files-to-trash-text": "Cussta atzione at a mòvere su documentos a su boto de s'arga.", "perma-delete-files-text": "Custa atzione at a iscantzellare in manera permanente su documentu.", "clear-filter": "Isbòida sos filtros impostados atuales", "language-searcher-placeholder": "Filtra pro limba", "category-searcher-placeholder": "Filtra pro categoria", "content-type-searcher-placeholder": "Filtra pro casta de cuntenutu", "no-details": "Introdutzione ebbia", "no-pictures": "Peruna immàgine", "no-videos": "Perunu vìdeu" } kiwix-desktop-2.4.1/resources/i18n/scn.json000066400000000000000000000012601473106011000205570ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Ajeje Brazorf", "GianAntonucci", "Gmelfi" ] }, "name": "Sicilianu", "error-title": "Erruri", "home-page": "Pàggina principali", "main-menu": "Menu principali", "close": "Chiudi", "help": "Aiutu", "about-kiwix": "Nfurmazzioni supra Kiwix", "exit": "Nesci", "save-file-as-window-title": "Sarva file comu", "file": "File", "edit": "Cancia", "view": "Talìa", "tools": "Strummenta", "settings": "Mpustazzioni", "title": "Tìtulu", "delete": "Cancella", "cancel": "Annulla", "about-version": "Virsioni: {{VERSION}}", "hide": "Ammuccia", "all": "Tuttu", "yes": "sì", "no": "no", "zim-open-fail-title": "File nun vàlidu" } kiwix-desktop-2.4.1/resources/i18n/sdc.json000066400000000000000000000013221473106011000205440ustar00rootroot00000000000000{ "@metadata": { "authors": [ "F Samaritani" ] }, "name": "Sassaresu", "error-title": "Errori", "print": "Sthampa", "find-in-page": "Acciappà in pàgina", "help": "Aggiuddu", "feedback": "Feedback", "file": "File", "view": "Liggì", "tools": "Isthrumenti", "search": "Zercha", "settings": "Prifirènzi", "back": "Indareddu", "search-files": "Zirchà dati", "title": "Tìturu", "size": "Misuri in byte", "date": "Data", "content-type": "Pagina di cuntinuddu", "delete": "Canzella", "download": "Ischarriggà", "cancel": "Annullà", "clear": "Ibbiuddà", "browse": "Iffuglia", "hide": "Cuà", "videos": "Vìdeo", "yes": "eja", "no": "no", "zim-open-fail-title": "Tìturu nò vàriddu" } kiwix-desktop-2.4.1/resources/i18n/se.json000066400000000000000000000025501473106011000204060ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Kimberli Mäkäräinen (WMNO)", "Yupik" ] }, "name": "davvisámegillii", "error-title": "Meattáhus", "open-zim": "Raba ZIM-fiilla", "home-page": "Váldosiidu", "main-menu": "Váldofállu", "close-tab": "Gidde leavgga", "open-file": "Raba fiilla", "search-in-library": "Oza girjerájus", "find-in-page": "Oza siiddus", "add-bookmark": "Lasit lohkanlistui", "remove-bookmark": "Sihko lohkanlisttus", "reading-list": "Lohkanlistu", "help": "Rávvagat", "feedback": "Máhcahat", "about-kiwix": "Dieđut Kiwix birra", "save-file-as-window-title": "Vurke fiilla namain", "file": "Fiila", "edit": "Rievdat", "view": "Čájet", "tools": "Neavvut", "window-title": "Girjerádju - Kiwix", "search": "Oza", "settings": "Ásahusat", "back": "Ruovttoluotta", "search-files": "Oza fiillaid", "size": "Sturrodat", "date": "Beaivemearri", "open": "Raba", "delete": "Sihko", "download": "Viečča", "resume": "Joatkke", "cancel": "Gaskkalduhte", "apply": "Geavat", "download-directory-setting": "Viečča máhpa", "clear": "Gurre", "browse": "Bláđe", "about-learn-more-about-kiwix": "Lassedieđut Kiwix birra", "about-version": "Veršuvdna: {{VERSION}}", "about-libraries-title": "Girjerájut", "hide": "Čiega", "all": "Buot", "pictures": "Govat", "videos": "Videot", "zim-open-fail-title": "Gustohis fiila" } kiwix-desktop-2.4.1/resources/i18n/sk.json000066400000000000000000000123671473106011000204230ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "Yardom78" ] }, "name": "Slovenčina", "error-title": "Chyba", "error-downloader-window-title": "Nepodarilo za vytvoriť sťahovač", "error-downloader-launch-message": "Nie je možné spustiť sťahovač, Kiwix sa spustí, ale všetky funkcie sťahovania budú nefunkčné.", "error-launch-server-message": "Vyskytla sa chyba!", "error-archive": "Archív sa nedá získať", "open-zim": "Otvoriť Zim", "local-kiwix-server": "Lokálny Kiwix server", "random-article": "Náhodný článok", "random-article-error": "Nepodarilo sa otvoriť náhodný článok.", "home-page": "Domovská stránka", "main-menu": "Hlavné menu", "print": "Tlač", "print-page-error": "Počas tlači došlo k chybe.", "new-tab": "Nová karta", "close-tab": "Zavrieť kartu", "close": "Zavrieť", "reopen-closed-tab": "Znovu otvoriť zatvorenú kartu", "browse-library": "Prehliadať knižnicu", "open-file": "Otvoriť súbor", "open-recent": "Otvoriť nedávny", "search-article": "Hľadať článok", "search-in-library": "Hľadať v knižnici", "find-in-page": "Nájsť na stránke", "set-fullscreen": "Spustiť režim celej obrazovky", "quit-fullscreen": "Ukončiť režim celej obrazovky", "table-of-content": "Obsah", "reading-list": "Zoznamy na prečítanie", "zoom-in": "Priblížiť", "zoom-out": "Oddialiť", "zoom-reset": "Vynulovať zoom", "help": "Pomocník", "feedback": "Spätná väzba", "report-a-bug": "Nahlásiť chybu", "request-a-feature": "Požiadať o funkciu", "about-kiwix": "O Kiwixe", "donate-to-support-kiwix": "Podpore Kiwix darom", "exit": "Ukončiť", "save-file-as-window-title": "Uložiť súbor ako", "download-finished-message": "Dokument bol stiahnutý.", "file": "Súbor", "edit": "Upraviť", "view": "Zobrazenie", "tools": "Nástroje", "window-title": "Knižnica - Kiwix", "search": "Hľadať", "browse-directory": "Prehliadať adresár", "settings": "Nastavenia", "back": "Späť", "forward": "Dopredu", "search-files": "Hľadať súbory", "title": "Názov", "size": "Veľkosť", "date": "Dátum", "content-type": "Typ obsahu", "reset-sort": "Vynulovať triedenie", "open": "Otvoriť", "delete": "Vymazať", "download": "Stiahnuť", "resume": "Pokračovať", "pause": "Pozastaviť", "cancel": "Zrušiť", "apply": "Použiť", "port-for-local-kiwix-server-setting": "Port pre miestny Kiwix server", "zoom-level-setting": "Predvolená úroveň priblíženia", "download-directory-setting": "Adresár sťahovania", "monitor-directory-setting": "Adresár monitora", "reset": "Vynulovať", "clear": "Vyčistiť", "browse": "Prehliadať", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix Vám umožňuje mať Wikipédiu po ruke kamkoľvek idete! Na lodi, uprostred ničoho alebo vo väzení, Kiwix Vám poskytuje prístup k celému ľudskému poznaniu. Nepotrebujete internet, všetko máte uložené na Vašom počítači.", "about-learn-more-about-kiwix": "Dozvedieť sa o Kiwixe viac", "about-release-title": "Vydanie", "about-source-code": "Tento softvér je vydaný pod podmienkami GNU General Public License version 3. Zdrojová kód sa dá nájsť na Github.", "about-version": "Verzia: {{VERSION}}", "about-reporting-problem-title": "Nahlásenie problému", "about-report-issue": "Pre vytvorenie hlásenia navštívte sledovač problémov Kixiw a otvorte hlásenie a opíšte problém.", "about-report-issue-2": "Prosím uveďte aj verziu Kiwixu v opise problému.", "about-libraries-title": "Knižnice", "kiwix-server-running-message": "Server Kiwixu pracuje a dá sa naň vstúpiť na miestnej sieti cez:", "kiwix-server-description": "Spustenie serveru umožňuje ostatným počítačom v lokálnej sieti pristupovať do Vašej Kiwix knižnice pomocou štandardného webového prehliadača.", "fullscreen-notification": "Ste v režime celej obrazovky. Pre ukončenie stlačte ESC!", "local-files": "Lokálne súbory", "hide": "Skryť", "open-in-browser": "Otvoriť v prehliadači", "start-kiwix-server": "Spustiť Kiwix server", "stop-kiwix-server": "Zastaviť Kiwix server", "all": "Všetko", "fulltext-search": "Hľadanie celého textu", "pictures": "Obrázky", "videos": "Videá", "ftindex": "Index celého textu", "details": "Celý článok", "yes": "áno", "no": "nie", "no-filter": "žiaden filter", "open-link-in-web-browser": "Otvoriť odkaz vo webovom prehliadači", "download-dir-dialog-title": "Ste si istý/á, že chcete zmeniť adresár pre sťahovanie?", "download-dir-dialog-msg": "Nová cesta k adresáru pre sťahovanie bude: {{DIRECTORY}}", "invalid-port": "Neplatný port", "zim-open-fail-title": "Neplatný súbor", "zim-open-fail-text": "Súbor ZIM {{ZIM}}sa nedá správne otvoriť. Bude v vašej knižnice odstránený.", "monitor-dir-dialog-title": "Ste si istý/á, že chcete zmeniť adresár monitora?", "monitor-dir-dialog-msg": "Nová cesta do adresára bude: {{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ste si istý/á, že chcete adresár vyčistiť?", "monitor-clear-dir-dialog-msg": "Toto zastaví kontrolu adresára pre nové súbory ZIM.", "monitor-directory-tooltip": "Všetky súbory ZIM budú automaticky pridané do knižnice." } kiwix-desktop-2.4.1/resources/i18n/skr-arab.json000066400000000000000000000047571473106011000215140ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Saraiki" ] }, "name": "سرائیکی", "error-title": "نقص", "error-launch-server-message": "خرابی تھی ڳئی ہے!", "random-article": "پوکھواں مضمون", "home-page": "گھر ورقہ", "main-menu": "اصل مینیو", "print": "چھاپو", "new-tab": "نویں ٹیب", "close-tab": "ٹیب بند کرو", "close": "بند کرو", "browse-library": "لائبریری براؤز کرو", "open-file": "فائل کھولو", "open-recent": "حالیہ کھولو", "search-article": "مضمون ڳولو", "search-in-library": "لائبریری وچ ڳولو", "find-in-page": "ورقے وچ لبھو", "quit-fullscreen": "پوری سکرین توں نکلو", "table-of-content": "تندیر", "reading-list": "مطالعہ تندیر", "zoom-in": "وݙا کرو", "zoom-out": "چھوٹا کرو", "help": "مدد", "feedback": "فیڈ بیک", "report-a-bug": "بگ رپورٹ کرو", "exit": "نکلو", "file": "فائل", "edit": "لکھو", "view": "ݙیکھو", "tools": "اوزار", "search": "ڳولو", "settings": "ترتیباں", "back": "پچھوں", "forward": "اڳوں تے بھیڄو", "search-files": "فائلاں ڳولو", "title": "عنوان", "size": "سائز", "date": "تریخ", "content-type": "مواد قسم", "open": "کھولو", "delete": "مٹاؤ", "download": "ڈاؤن لوڈ", "resume": "ولدا شروع کرو", "pause": "اجھکو", "cancel": "منسوخ", "apply": "اطلاق", "reset": "ولدا ٹھیک کرو", "clear": "صاف", "browse": "براؤز", "about-release-title": "ریلیز", "about-version": "ورژن: {{VERSION}}", "about-libraries-title": "لائبریریاں", "online-files": "آن لائن فائلاں", "local-files": "مقامی فائلاں", "category": "ونکی", "language": "زبان", "hide": "لُکاؤ", "open-in-browser": "براؤزر وچ کھولو", "all": "یکے", "pictures": "تصویراں", "videos": "وڈیو", "yes": "جیا", "no": "کو", "ok": "ٹھیک ہے", "invalid-port": "غلط پورٹ", "zim-open-fail-title": "غلط فائل", "delete-book": "کتاب مٹاؤ", "open-book": "کتاب کھولو", "open-folder": "فولڈر کھولو", "no-videos": "ویڈیو کائنی", "zim-id": "ZIM آئی ڈی", "zim-name": "Zim ناں", "scroll-next-tab": "اڳلی ٹیب تے سکرول کرو", "scroll-previous-tab": "پچھلی ٹیب تے سکرول کرو", "stop": "اختتام" } kiwix-desktop-2.4.1/resources/i18n/sl.json000066400000000000000000000156111473106011000204170ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Eleassar" ] }, "name": "slovenščina", "error-title": "Napaka", "error-downloader-window-title": "Prenašalnika ni mogoče ustvariti", "error-downloader-launch-message": "Prenašalnika ni mogoče zagnati. Zagnal se bo Kiwix-desktop, vendar vse funkcije prenosa ne bodo delovale!", "error-launch-server-message": "Prišlo je do napake!", "error-archive": "Arhiva ni mogoče pridobiti", "open-zim": "Odpri datoteko ZIM", "local-kiwix-server": "Lokalni strežnik Kiwix", "random-article": "Naključni članek", "random-article-error": "Odpiranje naključnega članka ni uspelo.", "home-page": "Domača stran", "main-menu": "Glavni meni", "print": "Natisni", "print-page-error": "Pri tiskanju je prišlo do napake.", "new-tab": "Nov zavihek", "close-tab": "Zapri zavihek", "close": "Zapri", "reopen-closed-tab": "Znova odpri zaprti zavihek", "browse-library": "Brskanje po knjižnici", "open-file": "Odpri datoteko", "open-recent": "Odpri nedavno", "search-article": "Poišči članek", "search-in-library": "Poišči v knjižnici", "find-in-page": "Poišči na strani", "set-fullscreen": "Nastavi celozaslonski način", "quit-fullscreen": "Izhod iz celozaslonskega načina", "table-of-content": "Kazalo vsebine", "reading-list": "Bralni seznam", "zoom-in": "Povečaj", "zoom-out": "Pomanjšaj", "zoom-reset": "Ponastavitev povečave", "help": "Pomoč", "feedback": "Povratne informacije", "report-a-bug": "Sporoči hrošča", "request-a-feature": "Predlagaj možnost", "about-kiwix": "O Kiwixu", "donate-to-support-kiwix": "Donirajte za podporo Kiwixu", "exit": "Izhod", "save-file-as-window-title": "Shrani datoteko kot", "download-finished-message": "Dokument je prenesen.", "file": "Datoteka", "edit": "Uredi", "view": "Ogled", "tools": "Orodja", "window-title": "Knjižnica – Kiwix", "search": "Poišči", "browse-directory": "Brskanje po imeniku", "settings": "Nastavitve", "back": "Nazaj", "forward": "Naprej", "search-files": "Poišči opombo", "title": "Naslov", "size": "Velikost", "date": "Datum", "content-type": "Vrata vsebine", "reset-sort": "ponastavi razvrščanje", "open": "Odpri", "delete": "Odstrani", "download": "Prenesi", "resume": "Nadaljuj", "pause": "Premor", "cancel": "Prekliči", "apply": "Uporabi", "port-for-local-kiwix-server-setting": "Vrata za lokalni strežnik Kiwix", "zoom-level-setting": "Privzeta stopnja povečave", "download-directory-setting": "Imenik za prenose", "monitor-directory-setting": "Nadzorni imenik", "reset": "Ponastavi", "clear": "Počisti", "browse": "Prebrskaj", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix vam zagotavlja, da imate pri roki vso Wikipedijo ne glede na to, kje ste! Na čolnu, sredi ničesar ali v zaporu vam Kiwix omogoča dostop do vsega človeškega znanja. Ne potrebujete interneta, vse je shranjeno na vašem računalniku.", "about-learn-more-about-kiwix": "Več o Kiwixu", "about-release-title": "Izdaja", "about-source-code": "Ta program je izdan pod pogoji licence GNU Geneeal Public License različice 3. Izvorno kodo si lahko ogledate v Githubu .", "about-version": "Različica: {{VERSION}}", "about-reporting-problem-title": "Sporočanje težav", "about-report-issue": "Če želite sporočiti težavo, obiščite sledilnik težav Kiwix-desktop in tam ustvarite temo z opisom vaše težave.", "about-report-issue-2": "Pri tem navedite različico s težavo.", "about-libraries-title": "Knjižnice", "kiwix-server-running-message": "Strežnik Kiwix deluje in je dostopen v lokalnem omrežju na:", "kiwix-server-description": "Zagon strežnika omogoča drugim računalnikom v lokalnem omrežju dostop do vaše knjižnice Kiwix z običajnim spletnim brskalnikom.", "fullscreen-notification": "Zdaj ste v celozaslonskem načinu. Pritisnite ESC za izhod!", "online-files": "Spletne datoteke", "local-files": "Lokalne datoteke", "category": "Kategorija", "language": "Jezik", "hide": "Skrij", "open-in-browser": "Odpri v brskalniku", "start-kiwix-server": "Zaženi strežnik Kiwix", "stop-kiwix-server": "Ustavi strežnik Kiwix", "all": "Vse", "fulltext-search": "Iskanje po celotnem besedilu", "pictures": "Slike", "videos": "Videi", "ftindex": "Kazalo celotnega besedila", "details": "Celotni članek", "yes": "da", "no": "ne", "ok": "v redu", "no-filter": "brez filtra", "open-link-in-web-browser": "Odpri povezavo v spletnem brskalniku", "open-link-new-tab": "Odpri povezavo na novem zavihku", "download-dir-dialog-title": "Ali res želite spremeniti imenik za prenose?", "download-dir-dialog-msg": "Pot novega imenika za prenose bo:\n{{DIRECTORY}}", "invalid-port": "Neveljavna vrata", "zim-open-fail-title": "Neveljavna datoteka", "zim-open-fail-text": "Datoteke ZIM {{ZIM}} ni mogoče pravilno odpreti. Iz vaše knjižnice bo odstranjena.", "monitor-dir-dialog-title": "Ali res želite spremeniti nadzorni imenik?", "monitor-dir-dialog-msg": "Pot novega nadzornega imenika bo:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ali res želite počistiti nadzorni imenik?", "monitor-clear-dir-dialog-msg": "S tem boste ustavili preverjanje nadzornega imenika za nove datoteke ZIM.", "monitor-directory-tooltip": "Vse datoteke ZIM v tem imeniku bodo samodejno dodane v knjižnico.", "next-tab": "Pojdi na naslednji zavihek", "previous-tab": "Pojdi na prejšnji zavihek", "cancel-download": "Prekliči prenos", "cancel-download-text": "Ste prepričani, da želite preklicati prenos {{ZIM}}?", "delete-book": "Izbriši knjigo", "delete-book-text": "Ste prepričani, da želite izbrisati {{ZIM}}?", "download-storage-error": "Napaka pri shranjevanju", "download-storage-error-text": "Sistem nima na voljo dovolj prostora za shranjevanje.", "download-unavailable": "Prenos ni na voljo", "download-unavailable-text": "Ta prenos ni na voljo.", "open-book": "Odpri knjigo", "download-book": "Prenesi knjigo", "pause-download": "Premor prenosa", "resume-download": "Nadaljuj prenos", "open-folder": "Odpri mapo", "couldnt-open-location": "Lokacije ni bilo mogoče odpreti", "couldnt-open-location-text": "Kiwix ne more odpreti mape {{FOLDER}}", "move-files-to-trash": "Prestavi izbrisane datoteke v koš", "move-files-to-trash-text": "To dejanje bo datoteko prestavilo v koš.", "perma-delete-files-text": "To dejanje bo datoteko trajno izbrisalo.", "clear-filter": "Počistite trenutno nastavljene filtre", "language-searcher-placeholder": "Filtriranje jezika", "category-searcher-placeholder": "Filtriranje kategorije", "content-type-searcher-placeholder": "Filtriranje vrste vsebine", "no-details": "Samo uvod", "no-pictures": "Ni slik", "no-videos": "Ni videoposnetkov", "disable-sandbox": "Kiwix je bil zagnan z omrežnega pogona. Znano je, da to povzroča težave z združljivostjo s peskovnikom za brskanje. Peskovnik bo zato onemogočen. Želite nadaljevati?" } kiwix-desktop-2.4.1/resources/i18n/sms.json000066400000000000000000000034271473106011000206050ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Yupik" ] }, "name": "sääʹmǩiõll", "error-title": "Vââʹǩǩ", "error-archive": "Arkiiv viǯǯmõš ij oʹnnstam", "open-zim": "Ääʹved ZIM-teâttõõzz", "random-article": "Håʹt mii artikkel", "home-page": "Ouddseidd", "main-menu": "Väʹlddvaʹlljõk", "print": "Printtâd", "new-tab": "Ođđ kõskklõstt", "close-tab": "Piij kõskklõõst ǩidd", "browse-library": "Ǩiõčč ǩeʹrjjpõõrt", "open-file": "Ääʹved teâttõõzz", "search-article": "Ooʒʒ artikkeeʹl", "search-in-library": "Ooʒʒ ǩeʹrjjpõõrtâst", "find-in-page": "Ooʒʒ seeidast", "table-of-content": "Siiskâžlooǥǥtõs", "add-bookmark": "Lââʹzzet lookkâmliʹstte", "remove-bookmark": "Jaukkâd lookkâmliistâst", "reading-list": "Lookkâmlistt", "help": "Vuäʹpstõõzz", "feedback": "Maacctõs", "report-a-bug": "Iʹlmmet čuõlmâst", "about-kiwix": "Teâđ Kiwix pirr", "save-file-as-window-title": "Ruõkk teâttõõzz nõõmin", "file": "Teâttõs", "edit": "Muuʹtt", "view": "Čuäʹjet", "tools": "Neävv", "window-title": "Ǩeʹrjjpõrtt - Kiwix", "search": "Ooʒʒ", "settings": "Asetõõzz", "search-files": "Ooʒʒ teâttõõzzid", "size": "Šorradvuõtt", "date": "Peiʹvvmieʹrr", "open": "Ääʹved", "delete": "Jaukkâd", "download": "Laadd", "cancel": "Jõõsk", "clear": "Kuârad", "browse": "Ǩiõčč", "about-learn-more-about-kiwix": "Lââʹssteâđ Kiwix pirr", "about-version": "Versio: {{VERSION}}", "local-files": "Pääiklaž teâttõõzz", "hide": "Čiõǥǥ", "open-in-browser": "Ääʹved neʹttlookkjest", "all": "Puk", "pictures": "Kaart da snimldõõǥǥ", "videos": "Video", "open-link-new-tab": "Ääʹved liiŋk ođđ kõskklõʹstte", "zim-open-fail-title": "Vââǥǥlaž teâttõs" } kiwix-desktop-2.4.1/resources/i18n/sq.json000066400000000000000000000216161473106011000204260ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Besnik b", "McDutchie" ] }, "name": "Shqip", "error-title": "Gabim", "error-downloader-window-title": "S’krijohet dot shkarkuesi", "error-downloader-launch-message": "E pamundur të niset shkarkuesi, Kiwix-desktop do të niset, por s’do të punojnë krejt funksionet e shkarkimit!", "error-launch-server-message": "Ndodhi një gabim!", "error-archive": "S’merret dor arkivi", "open-zim": "Hap Kartelë Zim", "local-kiwix-server": "Shërbyes Kiwix Vendor", "random-article": "Artikull Kuturu", "random-article-error": "S’u arrit të hapet një artikull kuturu.", "home-page": "Faqe hyrëse", "main-menu": "Menuja kryesore", "print": "Shtype", "print-page-error": "Ndodhi një gabim gjatë shtypjes.", "new-tab": "Skedë e re", "close-tab": "Mbylle skedën", "close": "Mbylle", "reopen-closed-tab": "Rihape skedën e mbyllyr", "browse-library": "Shfletoni bibliotekën", "open-file": "Hapni kartelë", "open-recent": "Hap së fundi", "search-article": "Kërkoni artikull", "search-in-library": "Kërkoni në bibliotekë", "find-in-page": "Gjej në faqe", "set-fullscreen": "Vëre sa krejt ekrani", "quit-fullscreen": "Dil nga “Sa krejt ekrani”", "table-of-content": "Tryezë e lëndës", "add-bookmark": "Shtoje te lista e leximeve", "remove-bookmark": "Hiqe nga lista e leximeve", "reading-list": "Listë leximesh", "zoom-in": "Zmadhoje", "zoom-out": "Zvogëloje", "zoom-reset": "Zerim Zoom-i", "help": "Ndihmë", "feedback": "Përshtypje", "report-a-bug": "Njoftoni një të metë", "request-a-feature": "Kërkoni një veçori", "about-kiwix": "Mbi Kiwix-in", "donate-to-support-kiwix": "Dhuroni që të përkrahni Kiwix-in", "exit": "Dalje", "save-file-as-window-title": "Ruaje Kartelën si", "download-finished-message": "Dokumenti u shkarkua.", "file": "Kartelë", "edit": "Përpunoni", "view": "Shiheni", "tools": "Mjete", "window-title": "Bibliotekë - Kiwix", "search": "Kërko", "browse-directory": "Shfletoni Drejtorinë", "settings": "Rregullime", "back": "Mbrapsht", "forward": "Përpara", "search-files": "Kërkoni kartela", "title": "Titull", "size": "Madhësi", "date": "Datë", "content-type": "Lloj lënde", "reset-sort": "zeroni renditjen", "open": "Hape", "delete": "Fshije", "download": "Shkarkoje", "resume": "Rimerre", "pause": "Ndalesë", "cancel": "Anuloje", "apply": "Zbatoje", "port-for-local-kiwix-server-setting": "Portë për shërbyes Kiwix vendor", "zoom-level-setting": "Shkallë parazgjedhje për zoom-in", "download-directory-setting": "Drejtori shkarkimesh", "monitor-directory-setting": "Drejtori mbikëqyrjesh", "reset": "Riktheje te parazgjedhja", "clear": "Spastroje", "browse": "Shfletoni", "about-kiwix-desktop-title": "Desktopi Kiwix", "about-kiwix-desktop-description": "Kiwix-i ju lejon të keni në pëllëmbë të dorës krejt Wikipedia-n, kudo që shkoni! Në një barkë, në mes të asgjëkundit apo në burg, Kiwix ju lejon të hyni në krejt dijen njerëzore. S’keni nevojë për Internet, gjithçka depozitohet në kompjuterin tuaj.", "about-learn-more-about-kiwix": "Mësoni më tepër mbi Kiwix-in", "about-release-title": "Hedhje në qarkullim", "about-source-code": "Ky program hidhet në qarkullim sipas termave të licencës GNU General Public License version 3. Shihini kodin burim te Github.", "about-version": "Version: {{VERSION}}", "about-reporting-problem-title": "Njoftim problemesh", "about-report-issue": "Që të hapni një çështje, vizitoni ndjekësin e çështjeve të desktopit Kiwix dhe hapni një çështje që përshkruan problemin tuaj.", "about-report-issue-2": "Ju lutemi, te çështja përmendni versionin.", "about-libraries-title": "Biblioteka", "kiwix-server-running-message": "Shërbyesi Kiwix Server është në punë dhe mund të përdoret te rrjeti vendor në:", "kiwix-server-description": "Nisja e një shërbyesi u lejon kompjuterave të tjerë në rrjetin vendor të përdorin bibliotekën tuaj Kiwix përmes një shfletuesi standard.", "fullscreen-notification": "Gjendeni nën mënyrën “sa krejt ekrani”. Që të dilni, shtypni tastin ESC!", "online-files": "Kartela Në Linjë", "local-files": "Kartela Vendore", "category": "Kategori", "language": "Gjuhë", "hide": "Fshihe", "open-in-browser": "Hape në shfletues", "start-kiwix-server": "Nis Shërbyesin Kiwix", "stop-kiwix-server": "Ndale Shërbyesin Kiwix", "all": "Krejt", "all_ips": "Krejt - Mënyra “Kapicë Duale”", "ipv4": "Mënyra Vetëm IPv4", "ipv6": "Mënyra Vetëm IPv6", "fulltext-search": "Kërkim në krejt tekstin", "pictures": "Foto", "videos": "Video", "ftindex": "Tregues “fulltext”", "details": "Artikull i plotë", "yes": "po", "no": "jo", "ok": "ok", "no-filter": "pa filtër", "open-link-in-web-browser": "Hape lidhjen në shfletues", "open-link-new-tab": "Hape lidhjen në skedë të re", "download-dir-dialog-title": "Jeni i sigurt se doni të ndryshoni drejtorinë e shkarkimeve?", "download-dir-dialog-msg": "Shtegu i drejtorisë së re do të jetë:\n{{DIRECTORY}}", "invalid-port": "Portë e pavlefshme", "zim-open-fail-title": "Kartelë e pavlefshme", "zim-open-fail-text": "Kartela ZIM {{ZIM}} s’mund të hapet si duhet. Do të hiqet nga biblioteka juaj.", "monitor-dir-dialog-title": "Jeni i sigurt se doni të ndryshohet drejtoria e mbikëqyrjeve?", "monitor-dir-dialog-msg": "Shtegu i drejtorisë së re të mbikëqyrjeve do të jetë :\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Jeni i sigurt se doni të spastrohet drejtoria e mbikëqyrjeve?", "path-was-copied": "Shtegu u kopjua", "monitor-clear-dir-dialog-msg": "Kjo do të ndalë kontrollimin e drejtorisë së mbikëqyrjeve për kartela të reja ZIM.", "monitor-directory-tooltip": "Krejt kartelat ZIM në këtë drejtori do të shtohen automatikisht te biblioteka.", "next-tab": "Kalo te skeda pasuese", "previous-tab": "Kalo te skeda e mëparshme", "cancel-download": "Anuloje shkarkimin", "cancel-download-text": "Jeni i sigurt se doni të anulohet shkarkimi i {{ZIM}}?", "delete-book": "Fshije librin", "delete-book-text": "Jeni i sigurt se doni të fshihet {{ZIM}}?", "download-storage-error": "Gabim Depozitimi", "download-storage-error-text": "Sistemi s’ka hapësirë të lirë të mjaftueshme.", "download-exceeds-max-file-size": "Madhësia e shkarkimit tejkalon madhësinë maksimum të kartelave që mbulohet nga sistemi i synuar i kartelave.", "download-dir-missing": "Drejtoria e shkarkimeve s’ekziston.", "download-dir-not-writable": "Drejtoria e shkarkimeve s’është e shkrueshme.", "download-unavailable": "Shkarkim Jo i Passhëm", "download-unavailable-text": "Ky shkarkim s’është gati.", "open-book": "Hapni libër", "download-book": "Shkarkoni libër", "pause-download": "Pauzë shkarkimi", "resume-download": "Rimerre shkarkimin", "open-folder": "Hap dosje", "couldnt-open-location": "S’u hap dot vendndodhje", "couldnt-open-location-text": "Kiwix-i s’është në gjendje të hapë dosjen {{FOLDER}}", "move-files-to-trash": "Shpjeri kartelat e fshira te hedhurinat", "move-files-to-trash-text": "Ky veprim do ta shpjerë kartelën te hedhurinat.", "perma-delete-files-text": "Ky veprim do ta fshijë përgjithmonë kartelën.", "clear-filter": "Spastro filtrat e ujdisur aktualisht", "language-searcher-placeholder": "Filtroji sipas gjuhësh", "category-searcher-placeholder": "Filtroji sipas kategorish", "content-type-searcher-placeholder": "Filtroji sipas llojesh lënde", "no-details": "Vetëm hyrje", "no-pictures": "Pa Foto", "no-videos": "Pa Video", "open-previous-tabs-at-startup": "Gjatë nisjes, hap skedat e mëparshme", "preview-book-in-web-browser": "Bëjini librit paraparje në shfletues", "file-not-found-title": "S’u Gjet Kartelë ZIM", "file-not-found-text": "Kartela ZIM s’ekziston, ose s’është e lexueshme", "zim-id": "ID ZIM", "zim-name": "Emër ZIM", "zim-path": "Shteg Kartele ZIM", "bad-zim-file-error-page-title": "Kartelë ZIM e Pavlefshme", "bad-zim-file-error-page-text": "Kartela ZIM është e pavlefshme, ose e dëmtuar.", "zim-entry-path": "Shteg Zëri ZIM", "export-reading-list": "Eksporto listë leximesh", "export-reading-list-error": "Ndodhi një gabim gjatë eksportimit të listës së leximeve.", "import-reading-list": "Importo listë leximesh", "import-reading-list-error": "Ndodhi një gabim gjatë importimit të listës së leximeve.", "disable-sandbox": "Kiwix-i është nisur që nga një disk rrjeti. Kjo dihet se shkakton probleme përputhjeje me shfletimin që nga bankëprovë. Për pasojë, bankëprova është çaktivizuar. Doni të vazhdohet?", "save-page-as": "Ruajeni Si…", "portable-disabled-tooltip": "Funksion i çaktivizuar për mënyrën e bartshme", "scroll-next-tab": "Rrëshqit te skeda pasuese", "scroll-previous-tab": "Rrëshqit te skeda e mëparshme", "kiwix-search": "Kërkim Kiwix", "search-options": "Mundësi Kërkimi" } kiwix-desktop-2.4.1/resources/i18n/sr-ec.json000066400000000000000000000050041473106011000210050ustar00rootroot00000000000000{ "@metadata": { "authors": [ "BadDog", "Kizule", "Milicevic01" ] }, "name": "српски", "random-article": "Насумичан чланак", "home-page": "Почетна странциа", "print": "Штампање", "new-tab": "Нова картица", "close-tab": "Затвори картицу", "open-file": "Отвори датотеку", "search-article": "Претражите чланак", "find-in-page": "Пронађи на страници", "quit-fullscreen": "Изађи из целог екрана", "table-of-content": "Садржај", "reading-list": "Листа за читање", "zoom-in": "Увећај", "zoom-out": "Умањи", "help": "Помоћ", "feedback": "Повратне информације", "report-a-bug": "Пријавите грешку", "request-a-feature": "Затражите функцију", "about-kiwix": "О Kiwix-у", "donate-to-support-kiwix": "Донирајте Kiwix-у", "exit": "Изађи", "download-finished-message": "Документ је преузет.", "file": "Датотека", "edit": "Уреди", "view": "Прикажи", "tools": "Алатке", "window-title": "Библиотека: Kiwix", "search": "Претражи", "browse-directory": "Прегледајте директоријум", "settings": "Подешавања", "back": "Назад", "search-files": "Претрага датотека", "title": "Наслов", "size": "Величина", "date": "Датум", "content-type": "Тип садржаја", "open": "Отвори", "delete": "Избриши", "download": "Преузми", "resume": "Настави", "pause": "Паузирај", "cancel": "Откажи", "apply": "Примени", "zoom-level-setting": "Подразумевани ниво зумирања:", "reset": "Ресетуј", "browse": "Прегледај", "about-learn-more-about-kiwix": "Детаљније о Kiwix-у", "about-version": "Верзија: {{VERSION}}", "about-reporting-problem-title": "Пријављивање проблема", "about-libraries-title": "Библиотеке", "fullscreen-notification": "Сада сте у режиму целог екрана. Притисните Esc да бисте изашли.", "local-files": "Локалне датотеке", "hide": "Сакриј", "open-in-browser": "Отвори у прегледачу", "stop-kiwix-server": "Заустави Kiwix сервер", "all": "Све", "fulltext-search": "Претражи цео текст" } kiwix-desktop-2.4.1/resources/i18n/sro.json000066400000000000000000000012251473106011000206000ustar00rootroot00000000000000{ "@metadata": { "authors": [ "F Samaritani" ] }, "name": "Sardu campidanesu", "new-tab": "Sceda noa", "search-article": "Cumpartzi sa boxi", "find-in-page": "Agata in sa pàgina", "table-of-content": "Ìndixi", "reading-list": "Listas de ligidura", "help": "Agiudu", "feedback": "Feedback", "exit": "Muda", "file": "File", "edit": "Muda", "view": "Càstia", "tools": "Ainas", "search": "Circa", "settings": "Impostatzionis", "back": "Acoa", "forward": "Ainnantis", "open": "Aberi", "cancel": "Annudda", "browse": "Browser", "hide": "Cua", "all": "Totu", "pictures": "màginis", "videos": "Videos", "yes": "eja", "no": "no" } kiwix-desktop-2.4.1/resources/i18n/sv.json000066400000000000000000000164761473106011000204430ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Jopparn", "Marcusjehrlander", "Sabelöga", "Susann Schweden", "WikiPhoenix" ] }, "name": "Svenska", "error-title": "Fel", "error-downloader-window-title": "Kan inte skapa nedladdare", "error-downloader-launch-message": "Omöjligt att starta nedladdare, Kiwix-desktop kommer starta men alla nedladdningsfunktioner kommer inte fungera!", "error-launch-server-message": "Ett fel har uppstått!", "error-archive": "Kan inte hämta arkivet", "open-zim": "Öppna ZIM-fil", "local-kiwix-server": "Lokal Kiwix-server", "random-article": "Slumpartikel", "random-article-error": "Misslyckades att öppna en slumpartikel.", "home-page": "Hemsida", "main-menu": "Huvudmeny", "print": "Skriv ut", "print-page-error": "Ett fel uppstod under utskrift.", "new-tab": "Ny flik", "close-tab": "Stäng flik", "close": "Stäng", "reopen-closed-tab": "Öppna stängd flik igen", "browse-library": "Bläddra i bibliotek", "open-file": "Öppna fil", "open-recent": "Öppna senaste", "search-article": "Sök efter artikel", "search-in-library": "Sök i bibliotek", "find-in-page": "Hitta på sida", "set-fullscreen": "Aktivera helskärm", "quit-fullscreen": "Stäng helskärm", "table-of-content": "Innehållsförteckning", "add-bookmark": "Lägg till i läslistan", "remove-bookmark": "Ta bort från läslistan", "reading-list": "Läslista", "zoom-in": "Zooma in", "zoom-out": "Zooma ut", "zoom-reset": "Återställ zoom", "help": "Hjälp", "feedback": "Återkoppling", "report-a-bug": "Rapportera en bugg", "request-a-feature": "Begär en funktion", "about-kiwix": "Om Kiwix", "donate-to-support-kiwix": "Donera för att stödja Kiwix", "exit": "Avsluta", "save-file-as-window-title": "Spara fil som", "download-finished-message": "Dokumentet laddades ned.", "file": "Fil", "edit": "Redigera", "view": "Visa", "tools": "Verktyg", "window-title": "Bibliotek - Kiwix", "search": "Sök", "browse-directory": "Bläddra i katalogen", "settings": "Inställningar", "back": "Tillbaka", "forward": "Fram", "search-files": "Sök efter filer", "title": "Titel", "size": "Storlek", "date": "Datum", "content-type": "Innehållstyp", "reset-sort": "återställ sortering", "open": "Öppna", "delete": "Radera", "download": "Ladda ned", "resume": "Återuppta", "pause": "Pausa", "cancel": "Avbryt", "apply": "Verkställ", "port-for-local-kiwix-server-setting": "Port för den lokala Kiwix-servern", "zoom-level-setting": "Zoomnivå som standard", "download-directory-setting": "Katalog för nedladdningar", "monitor-directory-setting": "Övervaka katalogen", "reset": "Återställ", "clear": "Rensa", "browse": "Bläddra", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix gör det möjligt för dig att ha hela Wikipedia till hands var du än är! På en båt, mitt i ingenstans eller i fängelse, Kiwix ger dig tillgång till mänsklighetens samlade kunskap. Du behöver inget internet, allt sparas i din dator.", "about-learn-more-about-kiwix": "Lär dig mer om Kiwix", "about-release-title": "Utgåva", "about-source-code": "Mjukvaran släpps under GNU General Public License version 3. Läs källkoden på Github.", "about-version": "Version: {{VERSION}}", "about-reporting-problem-title": "Rapportera problem", "about-report-issue": "För att rapportera ett problem, besök Kiwix-desktop issue tracker och öppna ett ärende som beskriver ditt problem.", "about-report-issue-2": "Vänligen nämn versionen problemet uppstod i.", "about-libraries-title": "Bibliotek", "kiwix-server-running-message": "Kiwix-servern fungerar och kan nås i det lokala nätverket via:", "kiwix-server-description": "Att starta en server låter andra datorer i det lokala nätverket att få tillgång till ditt Kiwix-bibliotek med en vanlig webbläsare.", "fullscreen-notification": "Du har aktiverat fullskärmsläge. Tryck ESC för att avsluta!", "online-files": "Online-filer", "local-files": "Lokala filer", "category": "Kategori", "language": "Språk", "hide": "Dölj", "open-in-browser": "Öppna i webbläsare", "start-kiwix-server": "Starta Kiwix-server", "stop-kiwix-server": "Stoppa Kiwix-server", "all": "Alla", "fulltext-search": "Fulltextsökning", "pictures": "Bilder", "videos": "Videor", "ftindex": "Fulltextindex", "details": "Fullständig artikel", "yes": "ja", "no": "nej", "ok": "ok", "no-filter": "inget filter", "open-link-in-web-browser": "Öppna länk i webbläsaren", "open-link-new-tab": "Öppna länk i ny flik", "download-dir-dialog-title": "Är du säker på att du vill byta nedladdningskatalog?", "download-dir-dialog-msg": "Den nya sökvägen till nedladdningskatalogen kommer bli:\n{{DIRECTORY}}", "invalid-port": "Ogiltig port", "zim-open-fail-title": "Ogiltig fil", "zim-open-fail-text": "ZIM-filen {{ZIM}} kan inte öppnas ordentligt. Den kommer att tas bort från ditt bibliotek.", "monitor-dir-dialog-title": "Är du säker på att du vill byta övervakningskatalog?", "monitor-dir-dialog-msg": "Den nya katalogsökvägen kommer vara:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Är du säker på att du vill rensa övervakningskatalogen?", "path-was-copied": "Vägen kopierades", "monitor-clear-dir-dialog-msg": "Detta kommer sluta kontrollera övervakningskatalogen efter nya ZIM-filer.", "monitor-directory-tooltip": "Alla ZIM-filer i denna katalog kommer automatiskt läggas till i biblioteket.", "next-tab": "Flytta till nästa flik", "previous-tab": "Flytta till föregående flik", "cancel-download": "Avbryt nedladdning", "cancel-download-text": "Är du säker på att du vill avbryta nedladdningen av {{ZIM}}?", "delete-book": "Radera bok", "delete-book-text": "Är du säker på att du vill radera {{ZIM}}?", "download-storage-error": "Lagringsfel", "download-storage-error-text": "Systemet har inte tillräckligt med lagringsutrymme.", "download-dir-missing": "Nedladdningskatalogen finns inte.", "download-dir-not-writable": "Nedladdningskatalogen är inte skrivbar.", "download-unavailable": "Nedladdning ej tillgänglig", "download-unavailable-text": "Nedladdningen är inte tillgänglig.", "open-book": "Öppna bok", "download-book": "Ladda ner bok", "pause-download": "Pausa nedladdning", "resume-download": "Återuppta nedladdning", "open-folder": "Öppna mapp", "couldnt-open-location": "Kunde inte öppna plats", "couldnt-open-location-text": "Kiwix kunde inte öppna mappen {{FOLDER}}", "move-files-to-trash": "Flytta raderade filer till papperskorgen", "move-files-to-trash-text": "Denna åtgärd flyttar filen till papperskorgen.", "perma-delete-files-text": "Denna åtgärd raderar filen permanent.", "clear-filter": "Rensa aktuella filter", "language-searcher-placeholder": "Filtrera efter språk", "category-searcher-placeholder": "Filtrera efter kategori", "content-type-searcher-placeholder": "Filtrera efter innehållstyp", "no-details": "Endast introduktion", "no-pictures": "Inga bilder", "no-videos": "Inga videor", "open-previous-tabs-at-startup": "Öppna tidigare flikar vid start", "preview-book-in-web-browser": "Förhandsgranska i webbläsare", "file-not-found-title": "ZIM-fil hittades inte", "file-not-found-text": "ZIM-filen finns inte eller kan inte läsas", "zim-id": "Zim-id", "zim-name": "Zim-namn", "zim-path": "Zim-filväg" } kiwix-desktop-2.4.1/resources/i18n/sw.json000066400000000000000000000151011473106011000204240ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Peggy", "Stephane" ] }, "name": "Kiswahili", "error-title": "Hitilafu", "error-downloader-window-title": "Haiwezi kuunda kipakuzi", "error-downloader-launch-message": "Haiwezekani kuzindua upakuaji, Kiwix-desktop itaanza lakini vitendaji vyote vya upakuaji havitafanya kazi!", "error-launch-server-message": "Hitilafu imetokea!", "error-archive": "Haiwezi kupata kumbukumbu", "open-zim": "Fungua faili ZIM", "local-kiwix-server": "Seva ya Kiwix ya ndani", "random-article": "Ukurasa wa bahati", "random-article-error": "Imeshindwa kufungua makala nasibu.", "home-page": "Ukurasa wa Nyumbani", "main-menu": "Menyu kuu", "print": "Chapisha", "print-page-error": "Hitilafu imetokea wakati wa uchapishaji.", "new-tab": "Kichupo kipya", "close-tab": "Funga kichupo", "close": "Funga", "reopen-closed-tab": "Fungua tena kichupo kilichofungwa", "browse-library": "Vinjari maktaba", "open-file": "Fungua faili", "open-recent": "Fungua hivi karibuni", "search-article": "Tafuta makala", "search-in-library": "Tafuta katika maktaba", "find-in-page": "Tafuta katika ukurasa", "set-fullscreen": "Weka skrini nzima", "quit-fullscreen": "Acha Skrini nzima", "table-of-content": "Jedwali la maudhui", "reading-list": "Orodha ya kusoma", "zoom-in": "Vuta karibu", "zoom-out": "Kuza nje", "zoom-reset": "Kuza upya", "help": "Msaada", "feedback": "Mrejezo", "report-a-bug": "Ripoti hitilafu", "request-a-feature": "Omba kipengele", "about-kiwix": "Kuhusu Kiwix", "donate-to-support-kiwix": "Changia kusaidia Kiwix", "exit": "Toka", "save-file-as-window-title": "Hifadhi Faili kama", "download-finished-message": "Hati imepakuliwa.", "file": "Faili", "edit": "Hariri", "view": "Tazama", "tools": "Zana", "window-title": "Maktaba - Kiwix", "search": "Tafuta", "browse-directory": "Vinjari Saraka", "settings": "Mipangilio", "back": "Nyuma", "forward": "Mbele", "search-files": "Tafuta mafaili", "title": "Kichwa", "size": "Ukubwa", "date": "Tarehe", "content-type": "Makala", "reset-sort": "panga upya", "open": "Fungua", "delete": "Futa", "download": "Pakua", "resume": "rejea", "pause": "Imesitishwa", "cancel": "Ghairi", "apply": "Tumia", "port-for-local-kiwix-server-setting": "Bandari ya seva ya Kiwix ya ndani", "zoom-level-setting": "Kiwango chaguomsingi cha kukuza", "download-directory-setting": "Pakua saraka", "monitor-directory-setting": "Kufuatilia saraka", "reset": "Panga upya", "clear": "Futa", "browse": "Vinjari", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix hukuruhusu kuwa na Wikipedia nzima popote unapoenda! Kwenye mashua, katikati ya mahali, au jela, Kiwix inakupa ufikiaji wa maarifa yote ya wanadamu. Huna haja ya mtandao, kila kitu kinahifadhiwa kwenye kompyuta yako.", "about-learn-more-about-kiwix": "Pata maelezo zaidi kuhusu Kiwix", "about-release-title": "Release", "about-source-code": "Programu hii inatolewa chini ya masharti ya toleo la 3 la Leseni ya Umma ya GNU. Tazama msimbo wa chanzo kwenye Github .", "about-version": "Toleo: {{VERSION}}", "about-reporting-problem-title": "Ripoti tatizo", "about-report-issue": "Ili kufungua suala, tembelea kifuatiliaji cha toleo la Kiwix-desktop na ufungue suala linaloelezea tatizo lako.", "about-report-issue-2": "Tafadhali taja toleo hilo katika toleo hili.", "about-libraries-title": "Maktaba", "kiwix-server-running-message": "Seva ya Kiwix inafanya kazi na inaweza kupatikana katika mtandao wa ndani kwa:", "kiwix-server-description": "Kuanzisha seva huruhusu kompyuta zingine kwenye mtandao wa karibu kufikia maktaba yako ya Kiwix na kivinjari cha kawaida cha wavuti.", "fullscreen-notification": "Sasa uko katika hali ya skrini nzima. Bonyeza ESC ili kuacha!", "online-files": "Faili za Mtandaoni", "local-files": "Faili za Karibu", "category": "Kundi", "language": "Lugha", "hide": "Ficha", "open-in-browser": "Fungua katika kivinjari", "start-kiwix-server": "Anzisha Seva ya Kiwix", "stop-kiwix-server": "Acha Seva ya Kiwix", "all": "Zote", "fulltext-search": "Utafutaji wa maandishi kamili", "pictures": "Picha", "videos": "Video", "ftindex": "Faharasa ya maandishi kamili", "details": "Makala kamili", "yes": "ndiyo", "no": "Hapana", "ok": "sawa", "no-filter": "hakuna kichujio", "open-link-in-web-browser": "Fungua kiungo kwenye kivinjari", "download-dir-dialog-title": "Je, una uhakika unataka kubadilisha saraka ya upakuaji?", "download-dir-dialog-msg": "Njia mpya ya saraka ya upakuaji itakuwa:\n{{DIRECTORY}}", "invalid-port": "Mlango batili", "zim-open-fail-title": "Jina batili", "zim-open-fail-text": "Faili ya ZIM {{ZIM}} haiwezi kufunguliwa ipasavyo. Itaondolewa kwenye maktaba yako.", "monitor-dir-dialog-title": "Je, una uhakika unataka kubadilisha saraka ya upakuaji?", "monitor-dir-dialog-msg": "Njia mpya ya saraka ya upakuaji itakuwa:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Je, una uhakika unataka kubadilisha saraka ya upakuaji?", "monitor-clear-dir-dialog-msg": "Hii itaacha kuangalia saraka ya kufuatilia kwa faili mpya za ZIM.", "monitor-directory-tooltip": "Faili zote za ZIM katika saraka hii zitaongezwa kiotomatiki kwenye maktaba.", "next-tab": "Nenda kwenye kichupo kinachofuata", "previous-tab": "Nenda kwenye kichupo kilichotangulia", "cancel-download": "Ghairi upakuaji", "cancel-download-text": "Je, una uhakika unataka kughairi upakuaji wa {{ZIM}} ?", "delete-book": "Futa kitabu", "delete-book-text": "Je, una uhakika unataka kufuta {{ZIM}} ?", "download-storage-error": "Hitilafu ya Hifadhi", "download-storage-error-text": "Mfumo hauna hifadhi ya kutosha.", "download-unavailable": "Upakuaji Haupatikani", "download-unavailable-text": "Upakuaji huu haupatikani.", "open-book": "Fungua kitabu", "download-book": "Pakua vitabu", "pause-download": "Sitisha upakuaji", "resume-download": "Endelea kupakua", "open-folder": "Fungua folda", "couldnt-open-location": "Haikuweza kufungua eneo", "couldnt-open-location-text": "Kiwix haiwezi kufungua folda {{FOLDER}}", "move-files-to-trash": "Hamisha faili zilizofutwa hadi kwenye tupio", "move-files-to-trash-text": "Kitendo hiki kitahamisha faili hadi kwenye tupio.", "perma-delete-files-text": "Kitendo hiki kitafuta faili kabisa.", "clear-filter": "Futa vichujio vilivyowekwa sasa", "language-searcher-placeholder": "Lugha ya tovuti", "category-searcher-placeholder": "Kichujio cha kategoria", "content-type-searcher-placeholder": "Aina ya maudhui ya kichujio", "no-details": "Utangulizi pekee", "no-pictures": "Hakuna picha", "no-videos": "Hakuna video" } kiwix-desktop-2.4.1/resources/i18n/ta.json000066400000000000000000000213001473106011000203750ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Fahimrazick", "Gurulenin", "McDutchie", "Siddhan" ] }, "name": "தமிழ்", "error-title": "பிழை", "error-downloader-window-title": "பதிவிறக்கியை உருவாக்க முடியவில்லை", "error-downloader-launch-message": "பதிவிறக்கியைத் தொடங்க சாத்தியமில்லை, கிவிக்ஸ்-டெஸ்க்டாப் தொடங்கும், ஆனால் அனைத்து பதிவிறக்க செயல்பாடுகளும் இயங்காது!", "error-launch-server-message": "ஓர் பிழை ஏற்பட்டுள்ளது!", "error-archive": "இந்த காப்பகத்தை பெற இயலவில்லை", "open-zim": "Zim கோப்பினைத் திற", "local-kiwix-server": "உள்ளிட கிவிக்ஸ் சேவையகம்", "random-article": "ஏதாவதொரு கட்டுரை", "random-article-error": "ஏதாவது ஒரு கட்டுரையைத் திறக்க முடியவில்லை.", "home-page": "முகப்பு பக்கம்", "main-menu": "முதன்மை பட்டியல்", "print": "அச்சிடுக", "print-page-error": "அச்சிடும்போது பிழை ஏற்பட்டது.", "new-tab": "புதிய தத்தல்", "close-tab": "தத்தலை மூடு", "close": "மூடு", "reopen-closed-tab": "மூடிய தாவலை மீண்டும் திறக்கவும்", "browse-library": "நூலகத்தை உலாவுக", "open-file": "கோப்பைத் திறக்கவும்", "open-recent": "சமீபத்திய கோப்பினை திற", "search-article": "கட்டுரையைத் தேடு", "search-in-library": "நூலகத்தில் தேடு", "find-in-page": "பக்கத்திற்குள் கண்டுபிடி", "set-fullscreen": "முழுத்திரை அமைக்கவும்", "quit-fullscreen": "முழுத்திரையிலிருந்து வெளியேறு", "table-of-content": "உள்ளடக்க அட்டவணை", "reading-list": "வாசிப்பு பட்டியல்", "zoom-in": "பெரிதாக்க", "zoom-out": "சிறிதாக்கவும்", "zoom-reset": "பெரிதாக்கு மீட்டமை", "help": "உதவி", "feedback": "பின்னூட்டம்", "report-a-bug": "வழுக்களை அறிக்கையிடுக", "request-a-feature": "ஒரு அம்சத்தைக் கோரு", "about-kiwix": "கிவிக்ஸ் பற்றி", "donate-to-support-kiwix": "கிவிக்ஸை ஆதரிக்க நன்கொடை", "exit": "வெளியேறு", "save-file-as-window-title": "கோப்பை இவ்வாறு சேமி", "download-finished-message": "ஆவணம் பதிவிறக்கம் செய்யப்பட்டுள்ளது.", "file": "கோப்பு", "edit": "தொகு", "view": "பார்வையிடு", "tools": "கருவிகள்", "window-title": "நூலகம் - கிவிக்ஸ்", "search": "தேடு", "browse-directory": "கோப்பகத்தை உலாவுக", "settings": "அமைப்புகள்", "back": "பின்னே", "forward": "முன் செல்", "search-files": "கோப்புகளைத் தேடு", "title": "தலைப்பு", "size": "அளவு", "date": "நாள்", "content-type": "உள்ளடக்க வகை", "reset-sort": "மீட்டமைத்தல்", "open": "திற", "delete": "நீக்கு", "download": "பதிவிறக்கு", "resume": "தொடர்க", "pause": "இடைநிறுத்து", "cancel": "கைவிடு", "apply": "பயன்படுத்து", "port-for-local-kiwix-server-setting": "உள்ளக கிவிக்ஸ் வழங்கிக்கான புறை", "zoom-level-setting": "இயல்பான பெரிதாக்கு நிலை", "download-directory-setting": "கோப்பகத்தைப் பதிவிறக்கவும்", "reset": "மீட்டமை", "browse": "உலவு", "about-kiwix-desktop-title": "கிவிக்ஸ் டெஸ்க்டாப்", "about-kiwix-desktop-description": "நீங்கள் எங்கு சென்றாலும் முழு விக்கிபீடியாவையும் கிவிக்ஸ் வைத்திருக்க உதவுகிறது! ஒரு படகில், எங்கும் நடுவில் அல்லது சிறையில், கிவிக்ஸ் முழு மனித அறிவையும் அணுகுவதற்கு உங்களுக்கு உதவி செய்கிறது. உங்களுக்கு இணையம் தேவையில்லை, அனைத்தும் உங்கள் கணினியில் சேமிக்கப்படுகிறது.", "about-learn-more-about-kiwix": "கிவிக்ஸ் பற்றி மேலும் அறிக", "about-release-title": "வெளியீடு", "about-source-code": "இந்த மென்பொருள் குனு பொது உரிம பதிப்பு 3 இன் விதிமுறைகளின் கீழ் வெளியிடப்படுகிறது. Github மூலக் குறியீட்டைப் பார்.", "about-version": "பதிப்பு: {{VERSION}}", "about-reporting-problem-title": "சிக்கலை புகாரளி", "about-report-issue": "சிக்கலைத் தெரிவிக்க, Kiwix-desktop issue tracker பார்வையிட்டு, உங்கள் சிக்கலை விவரிக்கவும்", "about-report-issue-2": "தயவுசெய்து எந்தப் பதிப்பில் சிக்கல் இருக்கிறது என்பதைக் குறிப்பிடவும்.", "about-libraries-title": "நூலகங்கள்", "kiwix-server-running-message": "கிவிக்ஸ் சேவையகம் இயங்குகிறது மற்றும் உள்ளிடப் பிணையத்தில் அணுகலாம்:", "kiwix-server-description": "ஒரு சேவையகத்தைத் தொடங்குவது உள்ளக பிணையத்தில் உள்ள பிற கணினிகளை உங்கள் கிவிக்ஸ் நூலகத்தை ஒரு நிலையான இணைய உலாவியுடன் அணுக அனுமதிக்கிறது.", "fullscreen-notification": "நீங்கள் இப்போது முழுத்திரை பயன்முறையில் இருக்கிறீர்கள். வெளியேற ESC ஐ அழுத்தவும்!", "local-files": "உள்ளிடக் கோப்புகள்", "hide": "மறை", "open-in-browser": "உலாவியில் திறக்க", "start-kiwix-server": "கிவிக்ஸ் சேவையகத்தைத் தொடங்கவும்", "stop-kiwix-server": "கிவிக்ஸ் சேவையகத்தை நிறுத்து", "all": "அனைத்தும்", "fulltext-search": "முழு உரை தேடல்", "pictures": "படங்கள்", "videos": "காணொளிகள்", "ftindex": "முழு உரை அட்டவணை", "details": "முழு கட்டுரை", "yes": "ஆம்", "no": "இல்லை", "no-filter": "வடிப்பான் இல்லை", "open-link-in-web-browser": "இணைய உலாவியில் இணைப்பைத் திறக்கவும்", "download-dir-dialog-title": "பதிவிறக்க கோப்பகத்தை மாற்ற விரும்புகிறீர்களா?", "download-dir-dialog-msg": "புதிய பதிவிறக்க அடைவு பாதை :{{DIRECTORY}}", "invalid-port": "செல்லத்தகாத புறை" } kiwix-desktop-2.4.1/resources/i18n/te.json000066400000000000000000000315751473106011000204200ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Rishitha 1238", "Veeven" ] }, "name": "తెలుగు", "error-title": "లోపం", "error-downloader-window-title": "డౌన్‌లోడ్‌ని సృష్టించడం సాధ్యం కాదు", "error-downloader-launch-message": "డౌన్‌లోడ్‌ను ప్రారంభించడం అసాధ్యం, కివిక్స్-డెస్క్‌టాప్ ప్రారంభమవుతుంది కానీ అన్ని డౌన్‌లోడ్ ఫంక్షన్‌లు పని చేయవు!", "error-launch-server-message": "ఒక లోపం సంభవించింది!", "error-archive": "ఆర్కైవ్‌ని పొందడం సాధ్యం కాదు", "open-zim": "ZIM ఫైల్‌ని తెరవండి", "local-kiwix-server": "స్థానిక Kiwix సర్వర్", "random-article": "యాదృచ్ఛిక వ్యాసం", "random-article-error": "యాదృచ్ఛిక కథనాన్ని తెరవడంలో విఫలమైంది.", "home-page": "ముంగిలి పేజీ", "main-menu": "ప్రధాన మెనూ", "print": "ముద్రించు", "print-page-error": "ప్రింట్ చేస్తున్నప్పుడు లోపం ఏర్పడింది.", "new-tab": "కొత్త ట్యాబ్", "close-tab": "ట్యాబ్‌ను మూసివేయండి", "close": "మూసివేయండి", "reopen-closed-tab": "మూసివేసిన ట్యాబ్‌ను మళ్లీ తెరవండి", "browse-library": "లైబ్రరీని బ్రౌజ్ చేయండి", "open-file": "ఫైలును తెరవండి", "open-recent": "ఇటీవల తెరువు", "search-article": "శోధన కథనం", "search-in-library": "లైబ్రరీలో శోధించండి", "find-in-page": "పేజీలో కనుగొనండి", "set-fullscreen": "పూర్తి స్క్రీన్‌ను సెట్ చేయండి", "quit-fullscreen": "పూర్తి స్క్రీన్ నుండి నిష్క్రమించండి", "table-of-content": "విషయ పట్టిక", "reading-list": "పఠన జాబితా", "zoom-in": "పెద్దదిగా చూపు", "zoom-out": "చిన్నది చేయి", "zoom-reset": "జూమ్ రీసెట్", "help": "సహాయం", "feedback": "ప్రతిస్పందన", "report-a-bug": "ఒక సమస్యను నివేదించండి", "request-a-feature": "లక్షణాన్ని అభ్యర్థించండి", "about-kiwix": "కివిక్స్ గురించి", "donate-to-support-kiwix": "Kiwixకు మద్దతు ఇవ్వడానికి విరాళం ఇవ్వండి", "exit": "బయటకి దారి", "save-file-as-window-title": "ఫైల్‌ని ఇలా సేవ్ చేయండి", "download-finished-message": "పత్రం డౌన్‌లోడ్ చేయబడింది.", "file": "ఫైల్", "edit": "సవరించు", "view": "చూడండి", "tools": "పనిముట్లు", "window-title": "లైబ్రరీ - కివిక్స్", "search": "వెతుకు", "browse-directory": "డైరెక్టరీని బ్రౌజ్ చేయండి", "settings": "అమరికలు", "back": "వెనుకకు", "forward": "ముందుకు", "search-files": "ఫైళ్ళను వెతకండి", "title": "శీర్షిక", "size": "పరిమాణం", "date": "తేదీ", "content-type": "విషయము రకం", "reset-sort": "క్రమాన్ని రీసెట్ చేయండి", "open": "తెరవండి", "delete": "తొలగించు", "download": "డౌన్‌లోడ్ చేయండి", "resume": "కొనసాగించు", "pause": "పాజ్ చేయబడింది", "cancel": "రద్దుచేయి", "apply": "దరఖాస్తు చేసుకోండి", "port-for-local-kiwix-server-setting": "స్థానిక Kiwix సర్వర్ కోసం పోర్ట్", "zoom-level-setting": "డిఫాల్ట్ జూమ్ స్థాయి", "download-directory-setting": "డైరెక్టరీని డౌన్‌లోడ్ చేయండి", "monitor-directory-setting": "మానిటర్ డైరెక్టరీ", "reset": "రీసెట్ చేయండి", "clear": "క్లియర్", "browse": "విహరించు", "about-kiwix-desktop-title": "కివిక్స్ డెస్క్‌టాప్", "about-kiwix-desktop-description": "మీరు ఎక్కడికి వెళ్లినా మొత్తం వికీపీడియాను కలిగి ఉండటానికి Kiwix మిమ్మల్ని అనుమతిస్తుంది! పడవలో, ఎక్కడా మధ్యలో లేదా జైలులో, Kiwix మీకు మానవ విజ్ఞానం మొత్తాన్ని యాక్సెస్ చేస్తుంది. మీకు ఇంటర్నెట్ అవసరం లేదు, ప్రతిదీ మీ కంప్యూటర్‌లో నిల్వ చేయబడుతుంది.", "about-learn-more-about-kiwix": "Kiwix గురించి మరింత తెలుసుకోండి", "about-release-title": "విడుదల", "about-source-code": "ఈ సాఫ్ట్‌వేర్ GNU జనరల్ పబ్లిక్ లైసెన్స్ వెర్షన్ 3 నిబంధనల ప్రకారం విడుదల చేయబడింది. Github లో సోర్స్ కోడ్‌ను వీక్షించండి.", "about-version": "వెర్షన్: {{VERSION}}", "about-reporting-problem-title": "సమస్యను నివేదించడం", "about-report-issue": "సమస్యను తెరవడానికి, Kiwix-desktop ఇష్యూ ట్రాకర్‌ని సందర్శించి, మీ సమస్యను వివరించే సమస్యను తెరవండి.", "about-report-issue-2": "దయచేసి సంచికలో సంస్కరణను పేర్కొనండి.", "about-libraries-title": "గ్రంథాలయాలు", "kiwix-server-running-message": "Kiwix సర్వర్ అమలవుతోంది మరియు స్థానిక నెట్‌వర్క్‌లో ఇక్కడ యాక్సెస్ చేయవచ్చు:", "kiwix-server-description": "సర్వర్‌ను ప్రారంభించడం వలన స్థానిక నెట్‌వర్క్‌లోని ఇతర కంప్యూటర్‌లు మీ కివిక్స్ లైబ్రరీని ప్రామాణిక వెబ్ బ్రౌజర్‌తో యాక్సెస్ చేయడానికి అనుమతిస్తుంది.", "fullscreen-notification": "మీరు ఇప్పుడు పూర్తి స్క్రీన్ మోడ్‌లో ఉన్నారు. నిష్క్రమించడానికి ESC నొక్కండి!", "online-files": "ఆన్‌లైన్ ఫైల్‌లు", "local-files": "స్థానిక ఫైల్‌లు", "category": "వర్గం", "language": "భాష", "hide": "దాచు", "open-in-browser": "బ్రౌజర్‌లో తెరవండి", "start-kiwix-server": "Kiwix సర్వర్‌ని ప్రారంభించండి", "stop-kiwix-server": "Kiwix సర్వర్‌ని ఆపు", "all": "అన్నీ", "fulltext-search": "పూర్తి వచన శోధన", "pictures": "బొమ్మలు", "videos": "వీడియోలు", "ftindex": "పూర్తి వచన సూచిక", "details": "పూర్తి వ్యాసం", "yes": "అవును", "no": "లేదు", "ok": "అలాగే", "no-filter": "సంఖ్య వడపోత", "open-link-in-web-browser": "వెబ్ బ్రౌజర్‌లో లింక్‌ని తెరవండి", "download-dir-dialog-title": "మీరు డౌన్‌లోడ్ డైరెక్టరీని ఖచ్చితంగా మార్చాలనుకుంటున్నారా?", "download-dir-dialog-msg": "కొత్త డౌన్‌లోడ్ డైరెక్టరీ మార్గం:\n{{DIRECTORY}}", "invalid-port": "చెల్లని పోర్ట్", "zim-open-fail-title": "చెల్లని ఫైల్", "zim-open-fail-text": "ZIM ఫైల్ {{ZIM}} సరిగ్గా తెరవబడదు. ఇది మీ లైబ్రరీ నుండి తీసివేయబడుతుంది.", "monitor-dir-dialog-title": "మీరు ఖచ్చితంగా మానిటర్ డైరెక్టరీని మార్చాలనుకుంటున్నారా?", "monitor-dir-dialog-msg": "కొత్త మానిటర్ డైరెక్టరీ మార్గం:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "మీరు మానిటర్ డైరెక్టరీని ఖచ్చితంగా క్లియర్ చేయాలనుకుంటున్నారా?", "monitor-clear-dir-dialog-msg": "ఇది కొత్త ZIM ఫైల్‌ల కోసం మానిటర్ డైరెక్టరీని తనిఖీ చేయడం ఆపివేస్తుంది.", "monitor-directory-tooltip": "ఈ డైరెక్టరీలోని అన్ని ZIM ఫైల్‌లు స్వయంచాలకంగా లైబ్రరీకి జోడించబడతాయి.", "next-tab": "తదుపరి ట్యాబ్‌కు తరలించండి", "previous-tab": "మునుపటి ట్యాబ్‌కు తరలించండి", "cancel-download": "డౌన్‌లోడ్ రద్దు చేయండి", "cancel-download-text": "మీరు ఖచ్చితంగా {{ZIM}} డౌన్‌లోడ్‌ని రద్దు చేయాలనుకుంటున్నారా?", "delete-book": "పుస్తకాన్ని తొలగించండి", "delete-book-text": "మీరు ఖచ్చితంగా {{ZIM}}ని తొలగించాలనుకుంటున్నారా?", "download-storage-error": "నిల్వ లోపం", "download-storage-error-text": "సిస్టమ్‌లో తగినంత నిల్వ అందుబాటులో లేదు.", "download-unavailable": "డౌన్‌లోడ్ అందుబాటులో లేదు", "download-unavailable-text": "ఈ డౌన్‌లోడ్ అందుబాటులో లేదు.", "open-book": "పుస్తకం తెరవండి", "download-book": "పుస్తకాన్ని డౌన్‌లోడ్ చేయండి", "pause-download": "డౌన్‌లోడ్‌ను పాజ్ చేయండి", "resume-download": "డౌన్‌లోడ్ పునఃప్రారంభించండి", "open-folder": "ఫోల్డర్ను తెరువు", "couldnt-open-location": "స్థానాన్ని తెరవడం సాధ్యపడలేదు", "couldnt-open-location-text": "Kiwix {{FOLDER}} ఫోల్డర్‌ని తెరవలేకపోయింది", "move-files-to-trash": "తొలగించిన ఫైల్‌లను ట్రాష్‌కి తరలించండి", "move-files-to-trash-text": "ఈ చర్య ఫైల్‌ను ట్రాష్‌కి తరలిస్తుంది.", "perma-delete-files-text": "ఈ చర్య ఫైల్‌ని శాశ్వతంగా తొలగిస్తుంది.", "clear-filter": "ప్రస్తుతం సెట్ చేసిన ఫిల్టర్‌లను క్లియర్ చేయండి", "language-searcher-placeholder": "ఫిల్టర్ భాష", "category-searcher-placeholder": "ఫిల్టర్ వర్గం", "content-type-searcher-placeholder": "ఫిల్టర్ కంటెంట్ రకం", "no-details": "పరిచయం మాత్రమే", "no-pictures": "చిత్రాలు లేవు", "no-videos": "వీడియోలు లేవు" } kiwix-desktop-2.4.1/resources/i18n/th.json000066400000000000000000000052321473106011000204120ustar00rootroot00000000000000{ "@metadata": { "authors": [ "McDutchie", "Prame Tan" ] }, "name": "ภาษาไทย", "open-zim": "เปิด Zim", "random-article": "สุ่มบทความ", "home-page": "หน้าหลัก", "main-menu": "เมนูหลัก", "print": "พิมพ์", "new-tab": "เปิดแท็บใหม่", "close-tab": "ปิดแท็บ", "close": "ปิด", "reopen-closed-tab": "เปิดแท็บที่ปิดไปแล้ว", "open-file": "เปิดไฟล์", "search-article": "ค้นหาบทความ", "search-in-library": "ค้นหาในไลบรารี่", "find-in-page": "ค้นหาในหน้า", "set-fullscreen": "มุมมองเต็มหน้าจอ", "quit-fullscreen": "ออกจากมุมมองเต็มหน้าจอ", "table-of-content": "สารบัญ", "reading-list": "รายการอ่าน", "zoom-in": "ซูมเข้า", "zoom-out": "ซูมออก", "zoom-reset": "ตั้งค่าซูมใหม่", "help": "ช่วยเหลือ", "feedback": "คำติชม", "report-a-bug": "รายงานข้อผิดพลาด", "about-kiwix": "เกี่ยวกับ Kiwix", "donate-to-support-kiwix": "บริจาคเพื่อสนับสนุน Kiwix", "exit": "ออก", "save-file-as-window-title": "บันทึกไฟล์เป็น", "download-finished-message": "ดาวน์โหลดบทความนี้แล้ว", "file": "ไฟล์", "edit": "แก้ไข", "view": "ดูหน้า", "tools": "เครื่องมือ", "search": "ค้นหา", "settings": "การตั้งค่า", "back": "ย้อนกลับ", "date": "วันที่", "open": "เปิด", "delete": "ลบ", "download": "ดาวน์โหลด", "resume": "ทำต่อ", "cancel": "ยกเลิก", "apply": "ใช้งาน", "about-kiwix-desktop-title": "Kiwix Desktop", "about-version": "เวอร์ชัน: {{VERSION}}", "about-reporting-problem-title": "รายงานปัญหา", "about-report-issue-2": "กรุณาระบุเวอร์ชันในรายงานปัญหาด้วย", "hide": "ซ่อน", "open-in-browser": "เปิดในเบราว์เซอร์", "all": "ทั้งหมด", "pictures": "รูปภาพ", "videos": "วิดีโอ", "yes": "ใช่", "no": "ไม่", "open-link-in-web-browser": "เปิดลิงก์ในเบราว์เซอร์" } kiwix-desktop-2.4.1/resources/i18n/tn.json000066400000000000000000000157661473106011000204350ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Sekhomba" ] }, "name": "Setswana", "error-title": "Phoso", "error-downloader-window-title": "Ga o ka ke wa dira download", "error-downloader-launch-message": "E re ka go sa kgonege go simolola go gatisa, Kiwix-desktop e tla simolola mme ditiro tsotlhe tsa go gatisa ga di kitla di bereka!", "error-launch-server-message": "Go dirilwe phoso!", "error-archive": "Ga o kgone go bona direkoto", "open-zim": "Bula faele ya ZIM", "local-kiwix-server": "Motlamedi wa Kiwix wa mo gae", "random-article": "Padi ye e abelelwang", "random-article-error": "Go bula padi e e abelelwang go retetse.", "home-page": "Tsebe ya gae", "main-menu": "Dintlha tsa konokono", "print": "Gatisa", "print-page-error": "Go dirilwe phoso fa go gatisiwa.", "new-tab": "Tab e ntšha", "close-tab": "Tswala tab", "close": "Tswala", "reopen-closed-tab": "Bula tab gape", "browse-library": "Tsamayatsamaya le motlhobo", "open-file": "Bula faele", "open-recent": "Bula ya bosheng", "search-article": "Batla setlhogo", "search-in-library": "Batla mo motlobong", "find-in-page": "Batla mo tsebeng", "set-fullscreen": "Setshwantsho se se tletseng", "quit-fullscreen": "Tlogela FullScreen", "table-of-content": "Tafole ya ditêng", "reading-list": "Lenaane la go bala", "zoom-in": "Atolosetsa mo teng", "zoom-out": "Atolosetsa kwa ntle", "zoom-reset": "baya katoloso sesha", "help": "Thuso", "feedback": "Phetolo", "report-a-bug": "Bega sekganedi", "request-a-feature": "Kopa karolo", "about-kiwix": "Ka ga Kiwix", "donate-to-support-kiwix": "Ntsha moneelo go rotloetsa Kiwix", "exit": "Tswa", "save-file-as-window-title": "Boloka File jaaka", "download-finished-message": "Tokumente e tserwe", "file": "Faele", "edit": "Fetola", "view": "Bona", "tools": "Dithulusu", "window-title": "Motlobo - Kiwix", "search": "Batla", "browse-directory": "Tsamayatsamaya le patlisisi", "settings": "Dipaakanyo", "back": "Ko Morago", "forward": "Ko pele", "search-files": "Batla difaele", "title": "Setlhogo", "size": "Selekanyo", "date": "Letsatsi", "content-type": "Mofuta wa diteng", "reset-sort": "go busetsa dilo kwa morago", "open": "Bula", "delete": "Phimola", "download": "Baya", "resume": "Tsweledisa", "pause": "Kgama", "cancel": "Sutlha", "apply": "Dirisa", "port-for-local-kiwix-server-setting": "Port ya server ya Kiwix ya selegae", "zoom-level-setting": "Selekanyo sa zoom sa konokono", "download-directory-setting": "Go gatisa direkoto", "monitor-directory-setting": "Ela tlhoko rekoto", "reset": "Tsosolosa", "clear": "Sutlha", "browse": "Tsamayatsamaya", "about-kiwix-desktop-title": "Kiwix Desktop", "about-kiwix-desktop-description": "Kiwix e go letlelela go nna le Wikipedia yotlhe gongwe le gongwe kwa o yang teng! Mo mokorong, mo gare ga lefelo le le se nang sepe, kgotsa mo kgolegelong, Kiwix e go naya kitso yotlhe ya setho. Ga o tlhoke Internet, sengwe le sengwe se bolokilwe mo khomputareng ya gago.", "about-learn-more-about-kiwix": "Ithute go le gontsi ka Kiwix", "about-release-title": "Golola", "about-source-code": "Software ye e golotswe ka tlase ga ditsetlana tsa GNU General Public Liscence karolo ya boraro. Bona ko e tsang teng mo Github.", "about-version": "Setlha: {{VERSION}}", "about-reporting-problem-title": "Bothata bo a begwa", "about-report-issue": "Go bula kgwetlho, etela Kiwix-desktop issue tracker o bo o bula kgwetlho e e tlhalosang bothata jwa gago.", "about-report-issue-2": "Tsweetswee umaka setlha se mo kgwetlhong.", "about-libraries-title": "Metlobo", "kiwix-server-running-message": "Kiwix Server e a bereka mme e ka fitlhelelwa mo mafaratlhatlheng a selegae kwa:", "kiwix-server-description": "Go simolola server go letlelela dikhomputara tse dingwe mo mafaratlhatlheng a selegae go tsena mo motlobong wa gago wa Kiwix ka browser ya web e e tlwaelegileng.", "fullscreen-notification": "Jaanong o mo seemong se se tletseng sa sekirini. tobetsa ESC gore e tlogele!", "online-files": "Difaele tsa Internet", "local-files": "Difaele tsa mo gae", "category": "Karolo", "language": "Teme", "hide": "Fitlha", "open-in-browser": "Bula mo browser", "start-kiwix-server": "Simolola Kiwix Server", "stop-kiwix-server": "Emisa Kiwix Server", "all": "Tsotlhe", "fulltext-search": "Batlisisa ka mafoko a a feletseng", "pictures": "Ditshwantsho", "videos": "Dtshwantsho tsa motshikhinyego", "ftindex": "Tlhatlhobo ya mafoko a a feletseng", "details": "Padi e e feletseng", "yes": "ee", "no": "nnyaa", "ok": "ee", "no-filter": "Ga gona sefarologanyi", "open-link-in-web-browser": "Bula kgolaganyi ye mo web browser", "download-dir-dialog-title": "A o tlhomamisegile gore o batla go fetola lenaane la di-download?", "download-dir-dialog-msg": "Tsetlana e ntšhs ya tsedi ya go itseela e tla nna:\n{{DIRECTORY}}", "invalid-port": "Port ye e sa letlelesegeng", "zim-open-fail-title": "Faele ye e sa letlelesegeng", "zim-open-fail-text": "Faele ya IM ya {{ZIM}} ga e bulêgê sentlê. E tlaa ntshiwa mo motlôbông.", "monitor-dir-dialog-title": "A o tlhomamisegile gore o batla go fetola lenaane la batlhatlhobi?", "monitor-dir-dialog-msg": "Tselana e ntšha ya go itseela e tla nna:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "A o tlhomamisegile gore o batla go phepafatsa lenaane la batlhatlhobi?", "monitor-clear-dir-dialog-msg": "Seno se tla emisa go tlhatlhoba direkoto tsa difaele tse disha tsa ZIM.", "monitor-directory-tooltip": "Difaele tsotlhe tsa ZIM tse di mo lenaaneng leno di tla tsenngwa ka botsone mo motlôbông.", "next-tab": "Fetela ko tab e e latêlang", "previous-tab": "Ya ko tab e e fetilêng", "cancel-download": "Khansele go itseela", "cancel-download-text": "A o tlhomamisitswe gore o batla go khansela downloaf ya {{ZIM}}?", "delete-book": "Phimola buka", "delete-book-text": "A o tlhomamisitse gore o batla go phimola {{ZIM}}?", "download-storage-error": "Phoso ya mabolokelo", "download-storage-error-text": "Tsamaiso ga e na mabolokelo a a lekaneng.", "download-unavailable": "Downloaf ga eyo", "download-unavailable-text": "Download e ga eyo", "open-book": "Bula buka", "download-book": "Download buka", "pause-download": "Kgama go download", "resume-download": "Tsweledisa go download", "open-folder": "Bula bobeelo", "couldnt-open-location": "O ne o ka se kgone go bula lefelo", "couldnt-open-location-text": "Kiwix ga e kgone go bula bobeelo {{FOLDER}}", "move-files-to-trash": "Fusolosetsa difaele tse di phimotsweng mo matlakaleng", "move-files-to-trash-text": "Kgato eno e tla dira gore faele e nne matlakala.", "perma-delete-files-text": "Kgato eno e tla phimola faele go ya go ile.", "clear-filter": "Phimola di-filter tse di beilweng gone jaanong", "language-searcher-placeholder": "Farologanya teme", "category-searcher-placeholder": "Farologanya dikarolo", "content-type-searcher-placeholder": "Farologanya mofuta wa tshêdimosôtsô", "no-details": "Matseno fela", "no-pictures": "Ga gona Ditshwantsho", "no-videos": "Ga gona ditshwantsho tsa motshikhinyego" } kiwix-desktop-2.4.1/resources/i18n/tr.json000066400000000000000000000155531473106011000204330ustar00rootroot00000000000000{ "@metadata": { "authors": [ "1917 Ekim Devrimi", "BaRaN6161 TURK", "Can", "DDPAT", "Hedda", "Ice bulldog", "Joseph", "Rofiatmustapha12", "SaldırganSincap" ] }, "name": "Türkçe", "error-title": "Hata", "error-downloader-window-title": "İndirici oluşturulamıyor", "error-downloader-launch-message": "İndiriciyi başlatmak imkansız, Kiwix-masaüstü başlayacak, ancak tüm indirme işlevleri çalışmaz!", "error-launch-server-message": "Bir hata oluştu!", "error-archive": "Arşiv alınamıyor", "open-zim": "ZIM Dosyasını Aç", "local-kiwix-server": "Yerel Kiwix Sunucusu", "random-article": "Rastgele Madde", "random-article-error": "Rastgele madde açılamadı.", "home-page": "Anasayfa", "main-menu": "Ana Menü", "print": "Yazdır", "print-page-error": "Yazım sırasında bir hata meydana geldi.", "new-tab": "Yeni sekme", "close-tab": "Sekmeyi kapat", "close": "Kapat", "reopen-closed-tab": "Kapatılan sekmeyi yeniden aç", "browse-library": "Kütüphaneye göz at", "open-file": "Dosyayı aç", "open-recent": "Son aç", "search-article": "Madde ara", "search-in-library": "Kütüphanede ara", "find-in-page": "Sayfada bul", "set-fullscreen": "Tam ekranı ayarla", "quit-fullscreen": "Tam Ekrandan Çık", "table-of-content": "İçerik tablosu", "reading-list": "Okuma listesi", "zoom-in": "Yakınlaştır", "zoom-out": "Uzaklaştır", "zoom-reset": "Zoom sıfırla", "help": "Yardım", "feedback": "Geri bildirim", "report-a-bug": "Hata bildir", "request-a-feature": "Bir özellik isteyin", "about-kiwix": "Kiwix hakkında", "donate-to-support-kiwix": "Kiwix'i desteklemek için bağış yapın", "exit": "Çıkış", "save-file-as-window-title": "Farklı Kaydet", "download-finished-message": "Belge indirildi.", "file": "Dosya", "edit": "Düzenle", "view": "Görüntüle", "tools": "Araçlar", "window-title": "Kütüphane - Kiwix", "search": "Ara", "browse-directory": "Dizine Göz At", "settings": "Ayarlar", "back": "Geri", "forward": "Yönlendir", "search-files": "Dosya ara", "title": "Başlık", "size": "Boyut", "date": "Tarih", "content-type": "İçerik türü", "reset-sort": "sıralamayı sıfırla", "open": "Aç", "delete": "Sil", "download": "İndir", "resume": "Devam et", "pause": "Duraklat", "cancel": "İptal", "apply": "Uygula", "port-for-local-kiwix-server-setting": "Yerel Kiwix sunucusu için bağlantı noktası", "zoom-level-setting": "Varsayılan yakınlaştırma düzeyi", "download-directory-setting": "İndirme dizini", "monitor-directory-setting": "Dizini izle", "reset": "Sıfırla", "clear": "Temizle", "browse": "Göz at", "about-kiwix-desktop-title": "Kiwix Masaüstü", "about-kiwix-desktop-description": "Kiwix, gittiğiniz her yerde Wikipedia'nın tamamının elinizin altında olmasını sağlar! Bir teknede, hiçliğin ortasında veya hapishanede, Kiwix size insanlığın tüm bilgisine erişme olanağı sağlar. İnternete ihtiyacınız yok, her şey bilgisayarınızda saklanıyor.", "about-learn-more-about-kiwix": "Kiwix hakkında daha fazla bilgi edinin", "about-release-title": "Sürüm", "about-source-code": "Bu yazılım GNU Genel Kamu Lisansı sürüm 3 koşulları altında yayımlanmıştır. Kaynak kodunu Github'da görün.", "about-version": "Sürüm: {{VERSION}}", "about-reporting-problem-title": "Sorun bildirme", "about-report-issue": "Bir sorun açmak için Kiwix masaüstü sorun izleyiciyiyi ziyaret edin ve sorununuzu açıklayan bir sorun açın.", "about-report-issue-2": "Lütfen sorundaki sürümü belirtin.", "about-libraries-title": "Kütüphaneler", "kiwix-server-running-message": "Kiwix Sunucusu çalışıyor ve yerel ağdan şu adresten erişilebilir:", "kiwix-server-description": "Sunucu başlatmak, yerel ağdaki diğer bilgisayarların standart bir web tarayıcısıyla Kiwix kitaplığınıza erişmesine izin verir.", "fullscreen-notification": "Şimdi tam ekran modundasınız. Çıkmak için ESC tuşuna basın!", "online-files": "Çevrimiçi Dosyalar", "local-files": "Yerel Dosyalar", "category": "Kategori", "language": "Dil", "hide": "Gizle", "open-in-browser": "Tarayıcıda aç", "start-kiwix-server": "Kiwix Sunucusunu Başlat", "stop-kiwix-server": "Kiwix Sunucusunu Durdur", "all": "Hepsi", "fulltext-search": "Tam metin arama", "pictures": "Resimler", "videos": "Videolar", "ftindex": "Tam metin dizini", "details": "Tam madde", "yes": "evet", "no": "hayır", "ok": "tamam", "no-filter": "filtre yok", "open-link-in-web-browser": "Bağlantıyı web tarayıcısında aç", "download-dir-dialog-title": "İndirme dizinini değiştirmek istediğinizden emin misiniz?", "download-dir-dialog-msg": "Yeni indirme dizini yolu şunu olacaktır:\n {{DIRECTORY}}", "invalid-port": "Geçersiz bağlantı noktası", "zim-open-fail-title": "Geçersiz dosya", "zim-open-fail-text": "ZIM dosyası {{ZIM}} düzgün açılamadı. Kütüphanenizden kaldırılacaktır.", "monitor-dir-dialog-title": "Monitör dizinini değiştirmek istediğinizden emin misiniz?", "monitor-dir-dialog-msg": "Yeni monitör dizini yolu şöyle olacaktır:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Monitör dizinini temizlemek istediğinizden emin misiniz?", "monitor-clear-dir-dialog-msg": "Bu, yeni ZIM dosyaları için monitör dizinini kontrol etmeyi durduracaktır.", "monitor-directory-tooltip": "Bu dizindeki tüm ZIM dosyaları otomatik olarak kitaplığa eklenecektir.", "next-tab": "Sonraki sekmeye git", "previous-tab": "Önceki sekmeye git", "cancel-download": "İndirmeyi iptal et", "cancel-download-text": "{{ZIM}} indirmesini iptal etmek istediğinizden emin misiniz?", "delete-book": "Kitabı sil", "delete-book-text": "{{ZIM}}? silmek istediğinizden emin misiniz?", "download-storage-error": "Depolama Hatası", "download-storage-error-text": "Sistemde yeterli depolama alanı yok.", "download-unavailable": "İndirilemiyor", "download-unavailable-text": "Bu anket mevcut değil", "open-book": "Sahte Aç", "download-book": "Kitapları indir", "pause-download": "İndirmeyi duraklat", "resume-download": "İndirmeye devam et", "open-folder": "Açık dosya", "couldnt-open-location": "Konum açılamadı", "couldnt-open-location-text": "Kiwix, {{FOLDER}} klasörünü açamıyor", "move-files-to-trash": "Silinen dosyaları çöp kutusuna taşıyın", "move-files-to-trash-text": "Bu işlem dosyayı çöp kutusuna taşıyacaktır.", "perma-delete-files-text": "Bu işlem dosyayı kalıcı olarak silecektir.", "clear-filter": "Halihazırda ayarlanmış olan filtreleri temizle", "language-searcher-placeholder": "Dile göre filtrele", "category-searcher-placeholder": "Kategorilerine göre filtrele", "content-type-searcher-placeholder": "İçerik türünü filtrele", "no-details": "Yalnızca giriş", "no-pictures": "Resim Yok", "no-videos": "Video Yok" } kiwix-desktop-2.4.1/resources/i18n/uk.json000066400000000000000000000201701473106011000204140ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Asokolov", "DDPAT", "Daries1", "Ice bulldog", "Ignatgg", "McDutchie", "Renamerr", "Renvoy", "Ата", "Пан Хаунд" ] }, "name": "Українська", "error-title": "Помилка", "error-downloader-window-title": "Неможливо створити завантажника", "error-downloader-launch-message": "Неможливо запустити завантажувач. Kiwik-десктоп буде все-одно запущено, але всі завантажувальні функції не будуть працювати!", "error-launch-server-message": "Сталася помилка!", "error-archive": "Не можу отримати архів", "open-zim": "Відкрийте файл ZIM", "local-kiwix-server": "Локальний сервер Kiwik", "random-article": "Випадкова стаття", "random-article-error": "Не вдалося відкрити випадкову статтю.", "home-page": "Домашня сторінка", "main-menu": "Головне меню", "print": "Друк", "print-page-error": "Під час друку сталася помилка.", "new-tab": "Нова вкладка", "close-tab": "Закрити вкладку", "close": "Закрити", "reopen-closed-tab": "Повторно відкрити закриту вкладку", "browse-library": "Перегляд бібліотеки", "open-file": "Відкрити файл", "open-recent": "Відкрити нещодавні", "search-article": "Знайти статтю", "search-in-library": "Пошук у бібліотеці", "find-in-page": "Знайти на сторінці", "set-fullscreen": "Перейти до повноекранного режиму", "quit-fullscreen": "Вийти з повноекранного режиму", "table-of-content": "Зміст", "add-bookmark": "Додати до списку для читання", "remove-bookmark": "Вилучити з списку читання", "reading-list": "Читальний список", "zoom-in": "Збільшити", "zoom-out": "Зменшити", "zoom-reset": "Скинути масштаб", "help": "Допомога", "feedback": "Зворотний зв'язок", "report-a-bug": "Повідомити про помилку", "request-a-feature": "Запропонувати нову функцію", "about-kiwix": "Про Kiwix", "donate-to-support-kiwix": "Допомогти Kiwix пожертвою", "exit": "Вихід", "save-file-as-window-title": "Зберегти файл як", "download-finished-message": "Документ був завантажлений.", "file": "Файл", "edit": "Редагувати", "view": "Переглянути", "tools": "Інструменти", "window-title": "Бібліотека — Kiwix", "search": "Пошук", "browse-directory": "Переглянути каталог", "settings": "Налаштування", "back": "Назад", "forward": "Вперед", "search-files": "Пошук файлів", "title": "Назва", "size": "Розмір", "date": "Дата", "content-type": "Тип вмісту", "reset-sort": "скинути сортування", "open": "Відкрити", "delete": "Видалити", "download": "Завантажити", "resume": "Продовжити", "pause": "Призупинити", "cancel": "Скасувати", "apply": "Застосувати", "port-for-local-kiwix-server-setting": "Порт для локального серверу Kiwik", "zoom-level-setting": "Рівень масштабування за замовчуванням", "download-directory-setting": "Каталог для завантажень", "monitor-directory-setting": "Каталог монітора", "reset": "Скинути", "clear": "Очистити", "browse": "Переглянути", "about-kiwix-desktop-title": "Kiwik-десктоп", "about-kiwix-desktop-description": "З Kiwix уся Вікіпедія буде у вас під рукою, куди б ви не запроторилися! Будь-де, на човні чи хоч у в'язниці, з Kiwix вам будуть доступні всі знання людства. Для доступу вам не потрібний Інтернет, оскільки все буде збережене на вашому комп'ютері.", "about-learn-more-about-kiwix": "Дізнайтеся більше про Kiwik", "about-release-title": "Випуск", "about-source-code": "Це програмне забезпечення випущене згідно умов GNU General Public License версії 3. Вихідний код доступний за адресою Github.", "about-version": "Версія: {{VERSION}}", "about-reporting-problem-title": "Повідомити про проблему", "about-report-issue": "Аби повідомити про проблему, відвідайте відслідковувач проблем із Kiwik-десктоп та додайте опис вашої проблеми.", "about-report-issue-2": "Будь ласка, повідомте номер версії у описі проблеми.", "about-libraries-title": "Бібліотеки", "kiwix-server-running-message": "Сервер Kiwix запущено і він може бути доступний у локальній мережі на:", "kiwix-server-description": "Запуск серверу дозволяє іншим комп'ютерам у локальні мережі мати доступ до вашої Kiwik-бібліотеки за допомогою звичайного браузера.", "fullscreen-notification": "Ви зараз у повноекранному режимі. Натисніть ESC для виходу!", "online-files": "Онлайн файли", "local-files": "Локальні файли", "category": "Категорія", "language": "Мова", "hide": "Приховати", "open-in-browser": "Відкрити у браузері", "start-kiwix-server": "Запустити сервер Kiwik", "stop-kiwix-server": "Зупинити сервер Kiwix", "all": "Усе", "fulltext-search": "Повнотекстовий пошук", "pictures": "Зображення", "videos": "Відео", "ftindex": "Повнотекстовий пошук", "details": "Повна стаття", "yes": "так", "no": "ні", "no-filter": "Без фільтру", "open-link-in-web-browser": "Відкрити посилання у навігаторі", "open-link-new-tab": "Відкрити посилання в новій вкладці", "download-dir-dialog-title": "Ви впевнені, що хочете змінити каталог для завантажень?", "download-dir-dialog-msg": "Новий каталог для завантажень тепер:\n{{DIRECTORY}}", "invalid-port": "Недійсний порт", "zim-open-fail-title": "Недійсний файл", "zim-open-fail-text": "Файл ZIM {{ZIM}} неможливо відкрити належним чином. Його буде видалено з вашої бібліотеки.", "monitor-dir-dialog-title": "Ви впевнені, що хочете змінити каталог монітора?", "monitor-dir-dialog-msg": "Новий шлях до каталогу монітора буде таким:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ви впевнені, що хочете очистити каталог монітора?", "monitor-clear-dir-dialog-msg": "Це припинить перевірку каталогу монітора на наявність нових файлів ZIM.", "monitor-directory-tooltip": "Усі ZIM-файли в цьому каталозі будуть автоматично додані до бібліотеки.", "cancel-download": "Скасувати завантаження", "cancel-download-text": "Ви впевнені, що бажаєте скасувати завантаження {{ZIM}}?" } kiwix-desktop-2.4.1/resources/i18n/yo.json000066400000000000000000000143241473106011000204300ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Rofiatmustapha12", "Sheriff" ] }, "name": "English", "error-title": "Àsìṣe", "error-downloader-window-title": "Ko le ṣẹda olugbasilẹ", "error-downloader-launch-message": "Ko ṣee ṣe lati ṣe ifilọlẹ igbasilẹ, Kiwix-desktop yoo bẹrẹ ṣugbọn gbogbo awọn iṣẹ igbasilẹ kii yoo ṣiṣẹ!", "error-launch-server-message": "Aṣiṣe kan ti ṣẹlẹ!", "error-archive": "Ko le gba ile-ipamọ naa", "open-zim": "Ṣii faili ZIM", "local-kiwix-server": "Agbegbe Kiwix Server", "random-article": "Àyọkà àrìnnàkò", "random-article-error": "Kuna lati ṣii nkan laileto.", "home-page": "Oju-iwe Ile", "main-menu": "Àkọlé àwòrán", "print": "Titẹ sita", "print-page-error": "Aṣiṣe ti waye lakoko titẹ.", "new-tab": "Titun taabu", "close-tab": "Pa taabu", "close": "Padé", "reopen-closed-tab": "Tun taabu pipade", "browse-library": "Ṣawakiri ile-ikawe", "open-file": "Ṣii faili", "open-recent": "Ṣii laipe", "search-article": "Wa nkan", "search-in-library": "Wa ninu ile-ikawe", "find-in-page": "Wárí nínú ojúewé", "set-fullscreen": "Ṣeto iboju kikun", "quit-fullscreen": "Jade ni kikun Iboju", "table-of-content": "Àtẹ̀sílẹ̀ àwọn ohun tó wà nínú rẹ̀", "reading-list": "Akojọ kika", "zoom-in": "Sun-un sinu", "zoom-out": "Sun-un jade", "zoom-reset": "Atunto sun-un", "help": "Ìrànlọ́wọ́", "feedback": "Esi", "report-a-bug": "ṣe àfisùn àsìṣe", "request-a-feature": "Beere ẹya kan", "about-kiwix": "Nipa Kiwix", "donate-to-support-kiwix": "Ṣetọrẹ lati ṣe atilẹyin Kiwix", "exit": "Jade", "save-file-as-window-title": "Fi faili pamọ bi", "download-finished-message": "Iwe aṣẹ ti gba lati ayelujara.", "file": "Àkọsílẹ̀", "edit": "Satunko", "view": "Yẹ̀ ẹ́ wò", "tools": "Àwọn irinṣẹ́", "window-title": "Library - Kiwix", "search": "Wa", "browse-directory": "Ṣawakiri Itọsọna", "settings": "ètò", "back": "Pada", "forward": "Tesiwaju", "search-files": "Iwari iwe", "title": "Akole", "size": "Iwon", "date": "Ojo", "content-type": "Orisirisi nkan inu", "reset-sort": "Iyipada tito", "open": "Sii le", "delete": "Paare", "download": "Gba lati ayelujara", "resume": "Atun bere", "pause": "Dawoduro", "cancel": "Fa igi le", "apply": "Lilo", "port-for-local-kiwix-server-setting": "Ibudo fun kiwix tibile", "zoom-level-setting": "Ifeloju to baa wa", "download-directory-setting": "Ona ati gba lati ayelujara", "monitor-directory-setting": "Sakiesi ona", "reset": "Atunto", "clear": "Pare", "browse": "Sawa kiri", "about-kiwix-desktop-title": "Kiwix Ojú-iṣẹ", "about-kiwix-desktop-description": "Kiwix gba ọ laaye lati ni gbogbo Wikipedia ni ọwọ nibikibi ti o lọ! Lori ọkọ oju omi, ni aarin ti ko si, tabi ni ẹwọn, Kiwix fun ọ ni iwọle si gbogbo imoye eniyan. O ko nilo Intanẹẹti, ohun gbogbo wa ni ipamọ lori kọnputa rẹ.", "about-learn-more-about-kiwix": "Ikekosi nipa kiwix", "about-release-title": "Itu sile", "about-source-code": "Sọfitiwia yii jẹ idasilẹ labẹ awọn ofin ti ẹya GNU Gbogbogbo ẹya Iwe-aṣẹ Awujọ. Wo koodu orisun lori Github .", "about-version": "Ẹya: {{VERSION}}", "about-reporting-problem-title": "Ifejo sun abuku", "about-report-issue": "Lati ṣii ọrọ kan, ṣabẹwo si Kiwix-desktop olutọpa ọrọ ati ṣii ọrọ kan ti n ṣalaye iṣoro rẹ.", "about-report-issue-2": "Jọwọ darukọ awọn ti ikede ninu atejade.", "about-libraries-title": "Ile kawe", "kiwix-server-running-message": "Olupin Kiwix naa nṣiṣẹ ati pe o le wọle si ni nẹtiwọọki agbegbe ni:", "kiwix-server-description": "Bibẹrẹ olupin ngbanilaaye awọn kọnputa miiran ni nẹtiwọọki agbegbe lati wọle si ile-ikawe Kiwix rẹ pẹlu aṣawakiri wẹẹbu boṣewa kan.", "fullscreen-notification": "Oti Wani oju ero kunkun. Te ESC lati dawoduro", "online-files": "Iwe eto ayelujara", "local-files": "Iwe eto tibile", "category": "Eka", "language": "Ede", "hide": "Fipamo", "open-in-browser": "Si ni awakiri", "start-kiwix-server": "Ṣiṣẹ Kiwix Server", "stop-kiwix-server": "Duro Kiwix Server", "all": "Gbogbo re", "fulltext-search": "Wiwa kikokunkun", "pictures": "Awon Aworan", "videos": "Wiwo", "ftindex": "Atọka kikun ọrọ", "details": "Apileko kunkun", "yes": "Beni", "no": "Beeko", "ok": "Otida", "no-filter": "ko si àlẹmọ", "open-link-in-web-browser": "Si ona ni ero awakiri", "download-dir-dialog-title": "So da o loju pe ofe yi ona ati gba lati ayelujara pada", "download-dir-dialog-msg": "Ona ati gba lati ayelujara tuntun ma je {{DIRECTORY}}", "invalid-port": "Ibudo tio sise", "zim-open-fail-title": "Iwe kole tio wulo", "zim-open-fail-text": "Faili ZIM {{ZIM}} ko le ṣii daradara. Yoo yọkuro kuro ni ile-ikawe rẹ.", "monitor-dir-dialog-title": "Ṣe o da ọ loju pe o fẹ yi ilana igbasilẹ naa pada?", "monitor-dir-dialog-msg": "Ona ilana igbasilẹ tuntun yoo jẹ:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "Ṣe o da ọ loju pe o fẹ yi ilana igbasilẹ naa pada?", "monitor-clear-dir-dialog-msg": "Eyi yoo dẹkun ṣiṣe ayẹwo ilana atẹle fun awọn faili ZIM tuntun.", "monitor-directory-tooltip": "Gbogbo awọn faili ZIM ti o wa ninu itọsọna yii yoo jẹ afikun laifọwọyi si ile-ikawe.", "next-tab": "Lọ si taabu atẹle", "previous-tab": "Yí lọ sí àtẹ́lẹ̀ ìsàlẹ̀", "cancel-download": "Fagilee gbigba lati ayelujara", "cancel-download-text": "Ṣe o da ọ loju pe o fẹ fagilee igbasilẹ ti {{ZIM}} ?", "delete-book": "Paa Bulọọku rẹ", "delete-book-text": "Ṣe o da ọ loju pe o fẹ paarẹ {{ZIM}} ?", "download-storage-error": "Aṣiṣe Ibi ipamọ", "download-storage-error-text": "Eto naa ko ni ibi ipamọ to wa.", "download-unavailable": "Gbigba lati ayelujara Ko si", "open-book": "Si iwe", "download-book": "Iwe gbigbalati ayelujara", "pause-download": "Da gbigba lati ayelujara duro", "resume-download": "Tunbere gbigbalati ayelujara", "open-folder": "Si akpo iwe", "couldnt-open-location": "Ipo ose si", "couldnt-open-location-text": "Kiwix ole si apo iwe {{FOLDER}}" } kiwix-desktop-2.4.1/resources/i18n/zgh.json000066400000000000000000000023451473106011000205710ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Hakim1bal", "McDutchie" ] }, "name": "ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ", "new-tab": "ⴰⵙⴽⵙⵍ ⴰⵎⴰⵢⵏⵓ", "close-tab": "ⵔⴳⵍ ⴰⵙⴽⵙⵍ", "open-file": "ⵕⵥⵎ ⴰⴼⴰⵢⵍⵓ", "find-in-page": "ⴰⴼ ⴳ ⵜⴰⵙⵏⴰ", "help": "ⵜⵉⵡⵉⵙⵉ", "about-kiwix": "ⵖⴼ ⴽⵉⵡⵉⴽⵙ", "save-file-as-window-title": "ⵃⴹⵓ ⴰⴼⴰⵢⵍⵓ ⴰⵎ", "file": "ⴰⴼⴰⵢⵍⵓ", "edit": "ⵙⵏⴼⵍ", "tools": "ⵉⵎⴰⵙⵙⵏ", "window-title": "ⵜⴰⵙⴷⵍⵉⵙⵜ - ⴽⵉⵡⵉⴽⵙ", "search": "ⵔⵣⵓ", "settings": "ⵜⵉⵙⵖⴰⵍ", "title": "ⴰⵣⵡⵍ", "date": "ⴰⵙⴰⴽⵓⴷ", "open": "ⵕⵥⵎ", "delete": "ⴽⴽⵙ", "download": "ⴰⴳⵎ", "cancel": "ⵙⵔ", "about-learn-more-about-kiwix": "ⵙⵙⵏ ⵓⴳⴳⴰⵔ ⵖⵔ ⴽⵉⵡⵉⴽⵙ", "about-libraries-title": "ⵜⵉⵙⴷⵍⵉⵙⵉⵏ", "local-files": "ⵉⴼⵓⵢⵍⴰ ⵉⴷⵖⵔⴰⵏⵏ", "hide": "ⵙⵙⵏⵜⵍ", "all": "ⴰⴽⴽⵯ", "pictures": "ⵜⵉⵡⵍⴰⴼⵉⵏ", "videos": "ⵉⴼⵉⴷⵢⵜⵏ", "yes": "ⵢⴰⵀ", "no": "ⵓⵀⵓ", "no-filter": "ⵡⴰⵍⵓ ⵉⵙⵜⴰⵢⵏ" } kiwix-desktop-2.4.1/resources/i18n/zh-hans.json000066400000000000000000000205031473106011000213450ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Anterdc99", "GuoPC", "Huajing", "IceButBin", "Josephine W.", "Key0121", "Kichin", "Lynzrand", "McDutchie", "Nadine Siak", "Shuiwater", "SomeyaMako", "Stang", "StarrySky", "Sunai", "TFX202X", "XtexChooser", "Zhang8569", "沈澄心" ] }, "name": "简体中文", "error-title": "错误", "error-downloader-window-title": "无法创建下载器", "error-downloader-launch-message": "发送一个下载器是不可能的,Kiwix-desktop将开始但是下载功能将不会工作!", "error-launch-server-message": "发生错误!", "error-archive": "无法获取存档", "open-zim": "打开ZIM文件", "local-kiwix-server": "本地 Kiwix 服务器", "random-article": "随机条目", "random-article-error": "无法打开随机文章。", "home-page": "主页", "main-menu": "主菜单", "print": "打印", "print-page-error": "打印时发生错误。", "new-tab": "新建标签页", "close-tab": "关闭标签页", "close": "关闭", "reopen-closed-tab": "重新打开关闭的标签页", "browse-library": "浏览图书馆", "open-file": "打开文件", "open-recent": "打开最近的文件", "search-article": "搜索条目", "search-in-library": "在图书馆中查找", "find-in-page": "在页面中查找", "set-fullscreen": "设置全屏", "quit-fullscreen": "退出全屏", "table-of-content": "目录", "add-bookmark": "添加至阅读列表", "remove-bookmark": "从阅读列表中移除", "reading-list": "阅读列表", "zoom-in": "放大", "zoom-out": "缩小", "zoom-reset": "重置缩放", "help": "帮助", "feedback": "反馈", "report-a-bug": "报告程序缺陷", "request-a-feature": "请求一个特性", "about-kiwix": "关于Kiwix", "donate-to-support-kiwix": "捐款支持 Kiwix", "exit": "退出", "save-file-as-window-title": "将文件另存为", "download-finished-message": "此文档已经下载完毕。", "file": "文件", "edit": "编辑", "view": "查看", "tools": "工具", "window-title": "图书馆 - Kiwix", "search": "搜索", "browse-directory": "浏览文件夹", "settings": "设置", "back": "返回", "forward": "前进", "search-files": "搜索文件", "title": "标题", "size": "大小", "date": "日期", "content-type": "内容类型", "reset-sort": "重置排序", "open": "打开", "delete": "删除", "download": "下载", "resume": "继续", "pause": "暂停", "cancel": "取消", "apply": "应用", "port-for-local-kiwix-server-setting": "本地Kiwix服务器端口", "zoom-level-setting": "默认缩放级别", "download-directory-setting": "下载文件夹", "monitor-directory-setting": "监视目录", "reset": "重置", "clear": "清除", "browse": "浏览", "about-kiwix-desktop-title": "Kiwix 桌面版", "about-kiwix-desktop-description": "Kiwix 能让您随时随地拥有整个维基百科!不论您是在船上、荒郊野外、甚至是待在监狱,Kiwix 都可让您获取全人类的知识。您不必需要互联网,所有内容都能存储在您的计算机中。", "about-learn-more-about-kiwix": "了解有关 Kiwix 的更多信息", "about-release-title": "发布", "about-source-code": "该软件根据 GNU 通用公共许可协议第 3 版本发布。您可在Github上查看该软件的源代码。", "about-version": "版本:{{VERSION}}", "about-reporting-problem-title": "报告问题", "about-report-issue": "要提出问题{{TRACKER_URL}},请访问Kiwix电脑版问题追踪器来提出一个问题,然后描述您遇到的状况。", "about-report-issue-2": "请在问题中提及版本。", "about-libraries-title": "图书馆", "kiwix-server-running-message": "Kiwix服务器已在运行。您可以在局域网中访问。链接是:", "kiwix-server-description": "开启服务器可以允许局域网中的其他电脑使用普通的网页浏览器来访问你的 Kiwix 图书馆", "fullscreen-notification": "您现已进入全屏模式。点击Esc键以退出全屏!", "online-files": "在线文件", "local-files": "本地文件", "category": "分类", "language": "语言", "hide": "隐藏", "open-in-browser": "在浏览器中打开", "start-kiwix-server": "启动 Kiwix 服务器", "stop-kiwix-server": "停止 Kiwix 服务器", "all": "全部", "all_ips": "全部 - 双栈模式", "ipv4": "仅 IPv4 模式", "ipv6": "仅 IPv6 模式", "fulltext-search": "全文搜索", "pictures": "图片", "videos": "视频", "ftindex": "全文索引", "details": "完整条目", "yes": "是", "no": "否", "ok": "好的", "no-filter": "无过滤", "open-link-in-web-browser": "在网页浏览器中打开链接", "open-link-new-tab": "在新标签页打开链接", "download-dir-dialog-title": "您确定您要更改下载路径吗?", "download-dir-dialog-msg": "新的下载路径为:\n{{DIRECTORY}}", "invalid-port": "无效的接口", "zim-open-fail-title": "无效文件", "zim-open-fail-text": "ZIM 文件 {{ZIM}} 打开失败。我们将把它从你的图书馆中移除。", "monitor-dir-dialog-title": "您确定您要更改下载路径吗?", "monitor-dir-dialog-msg": "新的下载路径为:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "您确定您要更改下载路径吗?", "path-was-copied": "路径已复制", "monitor-clear-dir-dialog-msg": "这将停止检查新 ZIM 文件的监视器目录。", "monitor-directory-tooltip": "这个文件夹下的所有 ZIM 文件都将加入你的图书馆。", "next-tab": "移至下一个标签页", "previous-tab": "移至上一个上一标签页", "cancel-download": "取消下载", "cancel-download-text": "您确定要取消下载{{ZIM}}吗?", "delete-book": "删除图书", "delete-book-text": "您确定要删除{{ZIM}}吗?", "download-storage-error": "储存错误", "download-storage-error-text": "存储空间不足。", "download-exceeds-max-file-size": "下载大小超出了目标文件系统支持的最大文件大小。", "download-dir-missing": "下载目录不存在。", "download-dir-not-writable": "下载目录不可写。", "download-unavailable": "下载不可用", "download-unavailable-text": "此次下载不可用", "open-book": "打开图书", "download-book": "下载图书", "pause-download": "暂停下载", "resume-download": "继续下载", "open-folder": "打开文件夹", "couldnt-open-location": "无法打开位置", "couldnt-open-location-text": "Kiwix 无法打开文件夹 {{FOLDER}}", "move-files-to-trash": "将已删除的文件移至回收站", "move-files-to-trash-text": "这将使文件被移至回收站。", "perma-delete-files-text": "这将使文件被永久删除。", "clear-filter": "清除当前的过滤设置", "language-searcher-placeholder": "按语言过滤", "category-searcher-placeholder": "按分类过滤", "content-type-searcher-placeholder": "按内容类型过滤", "no-details": "仅介绍", "no-pictures": "无图片", "no-videos": "无视频", "open-previous-tabs-at-startup": "启动时打开先前的标签页", "preview-book-in-web-browser": "在网页浏览器中预览书籍", "file-not-found-title": "找不到ZIM文件", "file-not-found-text": "ZIM文件不存在或无法读取", "zim-id": "ZIM ID", "zim-name": "ZIM名称", "zim-path": "ZIM文件路径", "bad-zim-file-error-page-title": "无效的 ZIM 文件", "bad-zim-file-error-page-text": "ZIM 文件无效或已损坏。", "zim-entry-path": "ZIM 入口路径", "export-reading-list": "导出阅读列表", "export-reading-list-error": "导出阅读列表时发生了错误。", "import-reading-list": "导入阅读列表", "import-reading-list-error": "导入阅读列表时发生了错误。", "disable-sandbox": "Kiwix是从网络驱动器启动的。这会导致已知的由浏览器沙盒的兼容性问题。因此沙盒将被禁用,您想要继续吗?", "save-page-as": "另存为...", "portable-disabled-tooltip": "便携模式下此功能被禁用", "scroll-next-tab": "滚动到下一个标签页", "scroll-previous-tab": "滚动到上一个标签页", "kiwix-search": "Kiwix 搜索", "search-options": "搜索选项", "read-article": "阅读条目", "read-text": "阅读选定的文本", "read-stop": "停止阅读", "stop": "停止", "voice": "语音", "select-read-voice": "选择朗读声音", "select-read-language": "选择阅读语言" } kiwix-desktop-2.4.1/resources/i18n/zh-hant.json000066400000000000000000000175061473106011000213570ustar00rootroot00000000000000{ "@metadata": { "authors": [ "Kly", "Weather Top Wizard", "Winston Sung" ] }, "name": "繁體中文", "error-title": "錯誤", "error-downloader-window-title": "無法建立下載程序", "error-downloader-launch-message": "無法啟用下載程序,Kiwix-桌機版將啟動;但所有的下載功能將無法運作!", "error-launch-server-message": "發生錯誤!", "error-archive": "無法取得存檔", "open-zim": "開啟 Zim 檔案", "local-kiwix-server": "本地 Kiwix 伺服器", "random-article": "隨機條目", "random-article-error": "開啟隨機條目失敗。", "home-page": "首頁", "main-menu": "主選單", "print": "列印", "print-page-error": "當列印時發生錯誤。", "new-tab": "新分頁", "close-tab": "關閉分頁", "close": "關閉", "reopen-closed-tab": "重新開啟已關閉的分頁", "browse-library": "瀏覽圖書館", "open-file": "開啟檔案", "open-recent": "最近開啟", "search-article": "搜尋條目", "search-in-library": "在圖書館裡搜尋", "find-in-page": "在頁面裡尋找", "set-fullscreen": "設定全螢幕", "quit-fullscreen": "結束全螢幕", "table-of-content": "目次", "add-bookmark": "新增至閱讀清單", "remove-bookmark": "從閱讀清單移除", "reading-list": "閱讀清單", "zoom-in": "放大", "zoom-out": "縮小", "zoom-reset": "重設縮放", "help": "說明", "feedback": "意見回饋", "report-a-bug": "回報程式錯誤", "request-a-feature": "請求新功能", "about-kiwix": "關於 Kiwix", "donate-to-support-kiwix": "捐款支持 Kiwix", "exit": "離開", "save-file-as-window-title": "檔案另存為", "download-finished-message": "文件已下載。", "file": "檔案", "edit": "編輯", "view": "檢視", "tools": "工具", "window-title": "圖書館 - Kiwix", "search": "搜尋", "browse-directory": "瀏覽目錄", "settings": "設定", "back": "返回", "forward": "向前", "search-files": "搜尋檔案", "title": "標題", "size": "大小", "date": "日期", "content-type": "內容類型", "reset-sort": "重設排序", "open": "開啟", "delete": "刪除", "download": "下載", "resume": "繼續", "pause": "暫停", "cancel": "取消", "apply": "套用", "port-for-local-kiwix-server-setting": "本地 Kiwix 伺服器通訊埠", "zoom-level-setting": "縮放層級", "download-directory-setting": "下載目錄", "monitor-directory-setting": "監視目錄", "reset": "重新設定", "clear": "清除", "browse": "瀏覽", "about-kiwix-desktop-title": "Kiwix 桌機版", "about-kiwix-desktop-description": "Kiwix 能讓您隨時隨地擁有整個維基百科!不論是在船上、荒郊野外、甚至是待在監獄,Kiwix 都可讓您取用全人類的知識。您不必需要網際網路,因為所有一切內容都可以存放在您的電腦裡。", "about-learn-more-about-kiwix": "了解更多有關 Kiwix", "about-release-title": "釋出", "about-source-code": "此軟體是基於 GNU 通用公眾授權條款第 3 版本釋出。您可以在 Github 查看該軟體的程式原始碼。", "about-version": "版本:{{VERSION}}", "about-reporting-problem-title": "回報問題", "about-report-issue": "要開啟問題,請參訪 Kiwix-桌機版問題追蹤,並開啟一個問題來描述您遇到的情況。", "about-report-issue-2": "請在問題中提及版本。", "about-libraries-title": "圖書館", "kiwix-server-running-message": "Kiwix 伺服器正運作中,要在本地網路存取請在:", "kiwix-server-description": "啟動伺服器能允許在本地網路上的其它台電腦以標準網頁瀏覽器來存取您的 Kiwix 圖書館。", "fullscreen-notification": "您現在是處在全螢幕模式。若要離開請按下 ESC 鍵!", "online-files": "線上檔案", "local-files": "本地檔案", "category": "分類", "language": "語言", "hide": "隱藏", "open-in-browser": "在瀏覽器中開啟", "start-kiwix-server": "啟動 Kiwix 伺服器", "stop-kiwix-server": "停用 Kiwix 伺服器", "all": "全部", "all_ips": "全部 - 雙堆疊模式", "ipv4": "僅 IPv4 模式", "ipv6": "僅 IPv6 模式", "fulltext-search": "全文搜尋", "pictures": "圖片", "videos": "影片", "ftindex": "全文字索引", "details": "整個條目", "yes": "是", "no": "否", "ok": "好", "no-filter": "無篩選", "open-link-in-web-browser": "在網路瀏覽器開啟連結", "open-link-new-tab": "在新分頁開啟連結", "download-dir-dialog-title": "您確定您要更改下載目錄嗎?", "download-dir-dialog-msg": "新目錄路徑會是:\n{{DIRECTORY}}", "invalid-port": "無效通訊埠", "zim-open-fail-title": "無效檔案", "zim-open-fail-text": "ZIM 檔案 {{ZIM}} 無法正常開啓。這將會從您的圖書館裡移除。", "monitor-dir-dialog-title": "您確定您要更改監視目錄嗎?", "monitor-dir-dialog-msg": "新監視目錄路徑會是:\n{{DIRECTORY}}", "monitor-clear-dir-dialog-title": "您確定您要更改監視目錄嗎?", "path-was-copied": "已複製路徑", "monitor-clear-dir-dialog-msg": "這將會停止檢查用於新 ZIM 檔案的監視目錄。", "monitor-directory-tooltip": "所有在此目錄的 ZIM 檔案將會自動添加到圖書館裡。", "next-tab": "移動至下一分頁", "previous-tab": "移動至上一分頁", "cancel-download": "取消下載", "cancel-download-text": "您確定要取消下載{{ZIM}}嗎?", "delete-book": "刪除書籍", "delete-book-text": "您確定要刪除{{ZIM}}嗎?", "download-storage-error": "儲存錯誤", "download-storage-error-text": "系統沒有足夠的可用儲存空間。", "download-exceeds-max-file-size": "下載大小超過目標檔案系統所支援的最大檔案大小。", "download-dir-missing": "下載目錄不存在。", "download-dir-not-writable": "下載目錄不可寫入。", "download-unavailable": "無法下載", "download-unavailable-text": "此下載不可用。", "open-book": "開啟書籍", "download-book": "下載書籍", "pause-download": "暫停下載", "resume-download": "繼續下載", "open-folder": "開啟資料夾", "couldnt-open-location": "無法開啟位置", "couldnt-open-location-text": "Kiwix 開啟資料夾{{FOLDER}}", "move-files-to-trash": "將已刪除的檔案移至垃圾桶", "move-files-to-trash-text": "此操作將會把檔案移至垃圾桶。", "perma-delete-files-text": "此操作將會永久刪除檔案。", "clear-filter": "清除目前的篩選設定", "language-searcher-placeholder": "依語言篩選", "category-searcher-placeholder": "依分類篩選", "content-type-searcher-placeholder": "依內容類型篩選", "no-details": "僅介紹", "no-pictures": "沒有圖片", "no-videos": "沒有影片", "open-previous-tabs-at-startup": "啟動時打開先前的分頁", "preview-book-in-web-browser": "在網頁瀏覽器預覽書籍", "file-not-found-title": "找不到 ZIM 檔案", "file-not-found-text": "ZIM 檔案不存在或無法讀取", "zim-id": "ZIM ID", "zim-name": "ZIM 名稱", "zim-path": "ZIM 檔案路徑", "bad-zim-file-error-page-title": "無效的 ZIM 檔案", "bad-zim-file-error-page-text": "ZIM 檔案無效或已損毀。", "zim-entry-path": "ZIM 入口路徑", "export-reading-list": "匯出閱讀清單", "export-reading-list-error": "匯出閱讀清單時發生錯誤。", "import-reading-list": "匯入閱讀清單", "import-reading-list-error": "匯入閱讀清單時發生錯誤。", "disable-sandbox": "Kiwix 已從網路磁碟機啟動。目前已知這會導致在瀏覽沙盒時發生相容性問題,因此已將沙盒功能關閉。您要繼續嗎?", "save-page-as": "另存為…", "portable-disabled-tooltip": "功能在可攜式模式下停用", "scroll-next-tab": "捲動至下一個分頁", "scroll-previous-tab": "捲動至上一個分頁", "kiwix-search": "Kiwix 搜尋" } kiwix-desktop-2.4.1/resources/icons/000077500000000000000000000000001473106011000174365ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/add-to-reading-list.svg000077500000000000000000000005001473106011000237050ustar00rootroot00000000000000icon / add-to-reading-listkiwix-desktop-2.4.1/resources/icons/add.svg000077500000000000000000000004221473106011000207100ustar00rootroot00000000000000icon / addkiwix-desktop-2.4.1/resources/icons/blank.svg000077500000000000000000000006521473106011000212540ustar00rootroot00000000000000icon / blankkiwix-desktop-2.4.1/resources/icons/cancel-button.png000066400000000000000000000022251473106011000227030ustar00rootroot00000000000000PNG  IHDR22?bKGD pHYsodtIME . v(R"IDAThMlTUCZlEXMHD h#&HHQvʊ v52* 0H iZMQ>&# |b΋ׁy̰Mfsν30>GUF!x  4O /; N` ,PpR0*c>*<`@𵠽^& n w/ M````̱A"`1,.5/c|;/R43܊*vY[ 1{>`>p,n67=h u+BqŁ>7"ec79;-a3E#h7~+. -"|<<t|b) 8t|+xu6ڞ٧LQKuO0 ù0/5IndD8 AbbY]RݞT Z$cDk,j?m= k淳ySgCqݱǞi0B;xn/dw㘠Z5þČN}^U6bԉQK ^7xn.bۭwLi,qrzRk/~;ɔt`6csPqA]r}`-{`oR ^o;J?8xC;f#H+IENDB`kiwix-desktop-2.4.1/resources/icons/caret-down-solid.svg000066400000000000000000000006251473106011000233350ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/caret-left-solid.svg000066400000000000000000000006011473106011000233120ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/caret-right-solid.svg000066400000000000000000000006241473106011000235020ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/caret-up-solid.svg000066400000000000000000000006231473106011000230100ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/check-solid.svg000066400000000000000000000006541473106011000223510ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/checkbox-active.svg000077500000000000000000000005261473106011000232240ustar00rootroot00000000000000icon / checkbox-activekiwix-desktop-2.4.1/resources/icons/checkbox-indeterminate.svg000077500000000000000000000004701473106011000245770ustar00rootroot00000000000000icon / checkbox-indeterminatekiwix-desktop-2.4.1/resources/icons/checkbox.svg000077500000000000000000000003261473106011000217510ustar00rootroot00000000000000icon / checkboxkiwix-desktop-2.4.1/resources/icons/close.svg000066400000000000000000000030761473106011000212720ustar00rootroot00000000000000 image/svg+xml icon / close icon / close kiwix-desktop-2.4.1/resources/icons/copy.svg000066400000000000000000000006241473106011000211330ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/donate.svg000077500000000000000000000004361473106011000214370ustar00rootroot00000000000000icon / donatekiwix-desktop-2.4.1/resources/icons/download.svg000077500000000000000000000003131473106011000217660ustar00rootroot00000000000000icon / downloadkiwix-desktop-2.4.1/resources/icons/downloading.svg000077500000000000000000000011541473106011000224700ustar00rootroot00000000000000icon / downloadingkiwix-desktop-2.4.1/resources/icons/drop-down.svg000066400000000000000000000005331473106011000220710ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/exit.svg000077500000000000000000000004271473106011000211360ustar00rootroot00000000000000icon / exitkiwix-desktop-2.4.1/resources/icons/filter.svg000077500000000000000000000012111473106011000214420ustar00rootroot00000000000000icon / filterkiwix-desktop-2.4.1/resources/icons/folder.svg000077500000000000000000000006001473106011000214310ustar00rootroot00000000000000icon / folderkiwix-desktop-2.4.1/resources/icons/full-screen-enter.svg000077500000000000000000000011151473106011000235120ustar00rootroot00000000000000icon / full-screen-enterkiwix-desktop-2.4.1/resources/icons/full-screen-exit.svg000077500000000000000000000011131473106011000233440ustar00rootroot00000000000000icon / full-screen-exitkiwix-desktop-2.4.1/resources/icons/help.svg000077500000000000000000000004031473106011000211070ustar00rootroot00000000000000icon / help?kiwix-desktop-2.4.1/resources/icons/history-left.svg000077500000000000000000000033011473106011000226100ustar00rootroot00000000000000 image/svg+xml icon / back kiwix-desktop-2.4.1/resources/icons/history-right.svg000077500000000000000000000033061473106011000230000ustar00rootroot00000000000000 image/svg+xml icon / forward kiwix-desktop-2.4.1/resources/icons/home-button.svg000066400000000000000000000023201473106011000224150ustar00rootroot00000000000000 icon / home-button kiwix-desktop-2.4.1/resources/icons/input-number.svg000077500000000000000000000003101473106011000226010ustar00rootroot00000000000000icon / input-numberkiwix-desktop-2.4.1/resources/icons/kiwix-app-icons-square.svg000066400000000000000000000053721473106011000245060ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/kiwix-logo.svg000066400000000000000000000033401473106011000222500ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/kiwix/000077500000000000000000000000001473106011000205715ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/128/000077500000000000000000000000001473106011000211035ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/128/kiwix-desktop.png000066400000000000000000000161171473106011000244210ustar00rootroot00000000000000PNG  IHDR>aIDATx]x֦'TUzDV,׫W? z"v RD;R6&l/3{vNM<˙e=};m5 n-܂[p n-xoj4Z@e slpeBZ}%RGr8M&3\%mD| 3%bҳ( Lg3eo=$UJJPyin'!;/ƾ@~!C}[HJ;] h$HtEHB>>lXGCf Ow~ RH DA$~Eþ7'(+NpAOqP)`l8!- RD< hT7+þ@>d2 w>ӝ$ߢN] P'"'Iip+@~pZU'vI ת8sk&kNJ~}þFג۳DAg^%8&&?]K RDEkB\&_<kの#^,߇ɿʎX_ Wz},P@~ y H_t 80 o09dy$0 _Ap(sa?/ ?_CXG:6_ƛͼfc~%>W+6m3:!)I+++B!4d4u?IΟɗi^F":ᣣp2?}V%0VCqj>Gȏc poN\~Uĉ"#h ɵW/&37e7k %er}i!1P7|ϞDwt};F3FM^^~)8@ɿ̎ .~ 9c܄p23̴rrp D/cd??oܘ07oOop4 @,5 S^[Suիѷ>ڃ·jՙMy`B~,3}Osp_?j1^u?ӔA,C12|$g3dL>~%ڷK.ݻ\-8n$\RS幛7o+z㍷˟zyOQcrҤiظL(A~G.c}BlJ 5j\w]O?%[!GȿH|BhOII۷57iyd,} l8u /ߜ9V5޲egӉ RLȋ^Weu\4@ôi&O_ݶm/}U(?lxFRed38CyR{Wh}dM .>NA|FBO[=5m ҼE>$)5z uݼR"7o!pQ-|#ǴQڤIk[e(,,NA.?Gk @W,||ǎO+L&C:JJd5imgeosKco83~9wz뽔Ud!dׅ'NLᣙ9-j*xsg<5kƏqè<e sjݺdaHh["Q ! yM0Gr<2_0hF6l|wIVvCbo_|8w2A&ѣ4"k}7ߪH Oa: P `ŏ3M0J&sê&M @FgkzN>`DFT(Ḁڙg~AB''ؾGJsFD8 zƒ:Zs ,$ l)љ*vf~1O!QQL~2~m˂/6,[tm,`T=ݚv6}EEWHL1x PkO# M wcq{-AШ-"Hƪ!%38CQ>qِ k`]~~G!\'c,r2 H8vdm[n]>FV:umؿHJ>pH vKƅ1:6]Xs Pѱ%KeR͏'S{Ӻu?1 pޣٻZA;qbD1DK@y~71k,@HHN<}|6(oѢuL $/&waTTI@iƚ^|mvz:voС8bb;pMVe,maE7o֬57lX $䈓H.--CA-y_b>NBdrd tFZ!ucŋ?.Eps92YZVffVfNN;eVV"==C +r޽sVZ{%ӧ(ioE;pH1Ы z,ƌK3Kܒ{I9d蔇lL0Rhъ[z=/;kP/O`lZ G JN؂*dT 0RQ ~Rs‚#`ÓTb2@(GCyC^2F2%tH3RWe.ui37o SJM;wBclmS_GQQϒ)sځ'UyOjOÞ5k5|( q%cj27gHk*v,M ~FNwu$Qb8{B306Ϣ`v2ND> Uq{4 ^-jv%E78Azi갰8;5 SO3ˤ2mWG>}J7 O>Y:$p΢X"^p/Op70GAjs~5erT#mI:p(+X"^]Ctf ykn*j,FDT8a|V,Kӻvo?eis_)׮+i\xŋ?M-#+$($HbzQ`7{dWqRw+i,HD tn-{߈AuD;\VV& (+Oת #~dĉ!&Mbxt$ғ^o۶pXr8#k֬W G뛡ZcAW}=$*&CqroD@.V%ԍ 'Km GDt\I4Qe> L:7 @<ªBI#'_pIfU+ ,bKx  h  k% qΐ/Y[UlNrrjVc'pNzIxll3-r*;wAv1p$F (.NJvǣJmw&OkN2]&KURhW1Zh!e]]9(zwAEƞ(T sBu5K˿ 6j 4璟GMpT )Cx֙3H!#:999%՝yue6,'T5~:bg^T1((1QFe)J=6 ~K䋬] 'K g|~;gk@9ЙC{xOСu#Y HU6GO$cǞ<{:x^yeapDZ9k`- ){3# hL> B$k(;z4?s6R-]64PI>Ȥ:;9(tfaFHl|"eO3=ӯZrN{$qK,NNIwmzqYrƧ =}B)GBH -њ,ZQ '}eIY=HMBf;̂=LO$?D~b OK=JQJk>kAf:Ś2!|0aMV(J[gjzc۶hu ͛1u$K[DXgC6a 4sCj~uQblTmED-!՞0 "wV&%Sm IN(.]Q`SK&zXJZ<}ҤTw1UW9D/t+rͣGE|x ]K*ڴet;XۻW:%5q|` In#Ӯ\IT""X m=z Yvd+,E2.]g>>a4u6+zmqBJRQ[Y -S<,{d#YC>rmZqs[(&!BE9 6>|z ^TrUFҺ/SUyoJ۾>GI9~I{$zT#Vx y?^thdJ U꧒ݫ@o QPW~q;3`% ?c,\1qblj߷pURRY{|bJT#/ pVT5"j]h3TT*)OÇВ1"~ϞɓYHw(b%uZ_'ǚ}baj(?~b< 3N>e1%X.zKJ>_-))AQqCV;03fQF%7DdWfrx o˗VН/n"R-%)ÆQc]]ǹBO\qɧOn]'HǾJ~8Wwb(BɛHKEm^uQҸSȄ'*>Z=($YomY:G\æ'N)Cj%$ɣs(,N&'(KY<څ7u0˝8jWdg[ ٻX(8rK[*BΙ9sv%j V$PzYvA׳l6S ;%'ߕTLtT 4O =<^&|U\.kM?GռTCOpHE>S"eRY䋣zxTk 8*о#*yPl&^!d:JL~%M-QjNK}~-}"Bv|_R F`K:;sк<|)`-K t#||O5^C)` hKԍg /$SQ$䳀S" KXW| g),T/&%;"AR+z Z"ߑVlsg^TiE}gȗVpQ(X@H KHv _G`'P_2;5j@I,A}|a06-4%Xx6  6 JP!< H!6G DE qT XA(B>}9%(=Z=`]g:_ԉ[> 2+T}`x#wm& _ x.$o+I6.$0coB o3ׯB <`.8ח _9 /z6$a_|ߐ|yg ȧfLS.af Qp n-܂[p n-܂(`IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/128/org.kiwix.desktop.x-zim.png000066400000000000000000000141761473106011000262560ustar00rootroot00000000000000PNG  IHDR>aEIDATx tUIX *"⌊3 (2hT*B>\ag8  k =$yW]U]A:t:sO:J_{}ުQC9*hȯzO~#G%''/N3iȭ?,Z3_f MɼiLB/* 7qA ;wvQǢv]_#FMB>¯JdggiE^/$7!`HI%pêd+@b#*&CbbR3oLAI @.&GP6lhWH 1.]?@;0cz'@F2?4*R)S >| ҏ2$"b >Csxj j53eH3bU? ef6VSZR 28 lMx8DɊ+B"[8lE>.V̒y&1/<-DCr@gGr9 i/0e j&n@0C`t ab6ļ 0$@ H0UL 7 Ν;z,Xy [QB!7x j Ȥxi:i8|0I*p 7qq(akd$8GU1yCP\huXU]R0+z7+%pQJa) 6ne)ǶT26s-d =v= s D eѫ;ql/78ebײy쫯B{aV_a1DB}N}1P)[- i*a7j&_aa,8v Fo)5kfjͺwc" BsqHDDg!+S eSPi6|8kѲnX`Z|Ԏ~}FY'>u!Ӹ :PQ ($b 4y2kҤ24&ܕ矧4hÆɦԲ-VXV5%mfB_, }}U xcǎ.O>yo=֫Ǝ ( ]UM#km} L *t%zmtmEIj;Y6m4[ ':r'R\5F t pP Q^#h.7m̫|yl7lYl̘lܸqxx(La5FXdr%9@ͣͤ$PU!hԸ {#zTuڕo(OJJWV W9 鵴#R%[eO$X,P# ~ϭq>M6cmڴ>CX>}!󮢣cg qi/W3 tt Ƞ8G}:Y$e1~KV> ˉWD":ذ-l99A!6232׮Siv1m:c6`@K=cs}te͚ʚm='sl׮(gn"!Cl} A+#e8ײU@v`\1k|A5%Pl_W^X (y>Y6aD g=˛Skn=j84p|=z\!UGpFx7 Ջ/&S23wMy9J!|~e˖3SGM<}fyiյnG66{Z8t۵ܗt U*eSُ?(p5Fci ]:lۊmd.y9۵sY|"?c =h9? ppЪW ٻҲ͛Un\w}78o}ʕXz<9zl޼QYg@jY,,X/1>`X{Zn]9W#&1dp'DyYiWPb1Rȅs9C*yR)LǠŊ;V`H !\-x>h5|^/xjTfy?EZqvmWE*$|zI -7h]h* 8CZahSѫ !p>lx _d ;-ؑހO 2vo>nҤVI@D>1ENk._ v9E DHfcߑ+%^b 6.rq3',`護bnY_pce|WS]W0q @%,lذ8@M|sgzOT÷ vf˻ympA!!ô7z& j@B ]eZPiL=wCl$?`w[nQ-@r&w_أ=N?=1-|衇}֓r-%Ŗ9hܷ}G;tzէcujp0_Y܈Q-P0nO ݎ_"gN ^mLw¨'i6?=r<؃;YSV-sg|(" CId" qĵ~ @u@ H$ @ H$ @ H$ @P}X>SJ՞tC/)+^E/@W^['J7~uؾ}jeaa 5Yh!៬w9W(H)Ժut{Sf ^K_ @4ziW03]^e(kٿ?6h;ԛh{OEal5}tn&c&?Ns$U qoc&`/*}𚐐~ܹ%U7n,{wzX0C &Nb߾}>=l„$U̞=*~zSxVҴj~)1HhO?XPUMMÇחHmٲYP@iޯQS5qOS!2dݤ)SPU 8?WPߋ/n ^r3%KݟeӧVǏef͐2p֦O=Oc'O=!vGqѣJsGkJ!11A/_J&?K^@ HԖHS' r;!~D[Ow6.&)'N=z|:}M' T2ۑCr {I iNҐ/*-HZJPi~ ;P- )^:wKW)9C9CyEIENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/24/000077500000000000000000000000001473106011000210165ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/24/kiwix-desktop.png000066400000000000000000000022201473106011000243220ustar00rootroot00000000000000PNG  IHDRw=WIDATHǽU]hSgNNvB;]elScl.& 26[-,Q1(M~2i) #6bK53MIjfc7ہ;|Ib`v3ċHڶ5M:spxz2ޮT*D`Kd@L. >GƴoRw.~Ћ.ˢu5sI"%&I\jy;/:㪺C`: *k iUOP~Grlvu d 0|ǶncثR,=yS5?]xd^ I PU,nN80x]n C#60 4wqL #`6YTF Eѥ rfCޯq4>7zY3`){a<ChE &seMU26K&_S0i1ThB9϶1:&'jqo r(7n\_ik{,V,$2uL|PTăʹ|<@%‘#T|(,U`X{xpѣ΍cww)ž ^êPT*@--W3;v_yV8"^l}O~[##ߏ>|,}W@#VĀ|G@{ I@*}ûnl~`ee"Fy!8ϥq1y  풗qN$JD`"c! .~xmmO?SSGΈ 1ҚO`p=Jy3ꪝ^p P P9H&QsrV7X,`6^n2>ERL+0ylYzep"?H$qj>)z} y#p8.jzt i:&HUx ("IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/256/000077500000000000000000000000001473106011000211055ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/256/kiwix-desktop.png000066400000000000000000000341751473106011000244270ustar00rootroot00000000000000PNG  IHDR\rf8DIDATxe)Ф( fEDN,(ذAlYYbEe){fKeI]vy?$$ٔ>t7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqI cZy <69j|N l^WW7d2-G6ˏoR zWP O1H8>c*mY8ރ^w+jhhE1;I8v+cmڢ/߬ߤFojll@cq[+mY8^,˫|cAVU:nK6MZ,?b4 '\[!~MMoKrXC6ۨ8c ԛI8cTR:Lx?*Րp?*IU?Yt.@/ $S_F1.*qb7H8BE- p|q\(mw2h4?o8>HaiG WWۦ6 e/ B*UTHW,,,T)QZ8sI8E- يp,7F 0 o|?.,AW~zbV3gJhyο ?)MFC?La? /xOEKCV m, ^PSS3\l0l ?~+y4g~}4>0EN> ;g@+ Ï`u<07]=?N ?8Nri{ @aaa8~x6 ?30 >e@lX *S')lX g~e3 l`[ïCd`3 ?b0 g~R&0 pŸg~6 ?` _6X?6 Wl2'g~~6 ?`~!_`~~N0 p/&u+% =` _68 to5`u <^0ïO=`[ rgu ?(~>Na3If'Mz~Gg;$_Тn9$I 򕿴̖f=d۳'_l7onٲús4Kqq ?5K=z K}>RXX_)"d{SrcԨ y|}O?1'6cPPG3 !y p]?"-_tt≃NzH:tBP8E EaPxԳ ȑomg޷@= nj^6>N, _}C Wwx']2:tkC * ';F=c޸zXA  ?~7sz\ҊI70{{E Uڵtٗ,yX~jPq2 ? ﱘ'gJ4bx8k|oCul_jjjY @{r_"7D57h |O#PCt.`WUU`p_~R26]K^zSjGzO07 C`5Ubjlp+a4v:ߓ!&L/kk;U`7lOo+pB7KpBwi̻ᐄg ?KpÕV^+ 6F~WC"}W߆'A]9<~/whŐ^u[h{s_u *HX$6-Ǽ|i[>~T¯ b40͸O ï cP4?t(VŐ"9s; gž{KC G˞=*0%(a5 ?\mۅ3Ű08?n_g8IE#|x\> F!TB!?A=1n4~rSގ^{;8A #(,ܿ?Wa믿[{U~m,IIIsr۲pƘ8Idcm&oQ 'xHf%F "p^w hkPR`[?'po.}UvC}O#Fv`arwY¤I'$$..A~:g 9ԩ7?@@xxo7#w ~6~['uҝWym۶f l~~r?y𧹅=q0i Е4K4B'ѹsϦLŭ[ 0eJo?-HGjcqժ_J([mێe˾,{k94$t5m7/ `*+^cUeeȡ'v Yt xssoޚ -t)CKkq3Nо/W?{uޟVi.'LZW;whHC.+1IgNPO.AS }X{q @9]Շ@JWw 9gbCM< `-K9vr'BoDܐ^,fb=t8s $Pe E1h2. J@w~#RoQ|yÆMޛYQQ9lxs `MLrDp8,OrIxG;RVpfeeSӰ#;3<st92#&]~Tvwp8{u5ؑ3OGzjiű#%̟HUˆN3n%u4Pu x2>} "7_arn}^fɁDhGtYHv1A?cɎ]DDu /yf6T8\?zjǷhf&Fh!oƭTg_hߩY__Cc1'p$XۨQ8ht>)Gpg6{v8T/h fwbe_DZ #6}s͓&MN| GTx&+Bm 3EbOwW#oG 0^x^ B"Cw?Q$*dq|[؊:eL6쌄}-(Gxq2`@4DŽ/zƌ~׮0ɊpHY؊X9K=:ַ%8oh6-?_acW`;HrOŽp$0=`Z?fZP܊pSd]wbJ %?\ @DZL-}|AqUjI7M Z?p84P @ϻUU7^x%4M]6vĈjl?l ;v8w6?Xl\hs{wV$ -.((Lilt: %xqi?3itfL ¤nD8{o7 '-;F00jAGIDq=4ױcE6kphKCapru~?TY\\<$5F 1HU^ @ ҳϾLSh~G6M*K*b;wYlJ o ogzX,?Kbb磞^>lyyU[ZZ[\\ g\lazVXY-Yb}-4XsƎrw6Nƅ>*cr w0>G߾C]vG.[~cNMMm?xQM,Z.% a5 dH5t'K`>v`!MYtF,-))-t5Bm+ psH8eVu8JYΔݎ\ *ύ+ $vY]Ͼ.~>s>RӦ\;yua]]wnj@".kU3gwG}^mێl|*މ$RkOdžy5iOA(G/ W+kIˣٳ 6{"eb$:q. Mm*đcYTW-2B72:/H8hXN42ACFWxʹ&{+⻧l<|K!>NT{;} iȐ1 @Ewh$aϝ)q\KUvDmPPie}׌iiVq"JW)C-tM"oRVR.\D`q*j?Er!?D^W}~_۶o/~#USQ~ mLHH=_[0(HoWBBzjdW LZ)LQ-¯Դe˾,6Υh&37Rdd?ۖ-)`Gx ]ߝo?.866l)o.i_6h8 ?2)Sf4l= Rkn1`9|_?~woeǎ^k_irΏ 9eǷFk?4G]]|E/ ]}((FѤ*"`$66ۛ70HV~;H_&{EW6z9?唳EE%y×_|u!~Dj;x-B,aI#3x I7 PaL𣗅 k7 #F{}q˯= r~5k(c}JLLlvާYB=\[q}^^!~w~;SRң*x<< ,R>Wq\(dDH.'!A_y/J/O4iISC[n\ٕӞ_|#Ӷ\Qi9#_+u1HyZC;EycQ K`?kNEϗHD kyC!y?}Ohÿ+]$Q(?il@{Mr7P'gdF`>^ bihSnVڼy +?Zp ٰÏ> $ˆ7s43ƉoTuRm~57%|_VC3?]D(?u~Ϟ}bbw_xt Hw'aK`Wъ}2Е}Ӧm]+sƍQ8qT=t()v>J'~-ׅ6҂QS`IߨGQh6T=j9<ɧʘfoA >Y4~_JF 4ayR;A+# @;y8 d6T?VxQ2(rFoAH4IqM#O9)~#ǔ@4XxEGh%4k?*U1*x\ԩnݟxlvK2 ʕy.:! cǀ|Z bV)S CT](:_%{V{@^W{jkMyk6TGWLdt05p饗,%cZ>ݻ! coÿJa3Sso5FI˖}Q$[ ?II}- KUvS  @s[?7{^JV7+p{slRTR)JQ6F(YW\q-Uz+14h2zDӀ/y6xڋ8f'iK/Qy7mB-_Mfͺ2c.\+v5e.NsB^{ p(ь+x|Gsi+[aƚɽ|dW䫾"N`7xP79\ D+"GɓtuM񻃟'!o3*231<⋯efTTTbXFjb- TX:sT/:L\ n'J[{6r ?]{/->$m W`6>\4'Cm/6{I}4QG޹8kA~L=) ~'{p;rP7Hf"d@U.T^:DrDdh޷9P ;/(aoÏ[ï?2/A]w_Mᾮ~YmH^_RRGj~^KSSS/ye?sU޼i8_QQ5e/@]x[pMxlZ2;E2e®]{y߼yE+|BD.p6Sۏ(BW,srA ? n]5+qF1z,R?S"F&ن`ĈOx M8uLGkgGP8[$z wd͝P]JQ>OǏC,8G*Dzp[NA(<3^SŨfϾjǎ=0<k8B?>;;'iР P]K(d'>v ?Zk`0 rψ7x A^<5OsKa5LqN=B%oHXXi3^JœzSį6sn: I'Y1Ŋ[ =x}7+Dͨ@- %>26lؔ} p N8㪫Wc2WWvh޼{7ht?~+4g((UhF3x'T#-uQUUQIrZRoJ~>I۷zA%tNE"@"7IJuz'NiڏQQڮ _?M+)' pR鯾YS4^@gg>"~|uQ3[n /e-Ib-!s.si"=n3~G)0sfҮ&:se ?}Eb,E-ڶr>k+"_i1pʔQ R{ԣ8 A@7F"|CXL5V89.Q16 Ј &O>3fB]ǎ<'m~ي6U?k&cLW] J7ьVBv3;7~ #GoFJp3K.Xv{VQSqiif8!Mho! 1 V#P"ZȎHzjo_Cu <{xf V }~ *C-rA$̧7 ->|\P]{ Dx$>jI>趬DEtw+x]Z'/fOsPV:2)7x[9?<*2ɾ>Ohoޫ3-Kz ?Ϗ$bw9>=TᲢq&6ۗӧV+.\qP2=N j?&tpϞ-.1:r2Rv'#J|N `R?~>Ē섄>:}hJ=)gsd=t,}]tEW1 ] cn%1dtO< ?_Ad:zIV?6,:hSrȆ)Գ6o`%;9Gx-* ~WQ"N|U~ɻihqڳ8$hiD@%y ..К5$/_]G}d|i+V|ciAL[v>ē3 ?kė @0¯wH42\9ӭ/1 AtJ(3$ܖ}$(AH4'cW,l*~7Uz# yf͚S]g_0^D!Z_(ZhJ{PO>}iP`Z}ϟ<p/h_^M L<Ld{Cs|$%-XxY߾CuI&L63$ {18q~h{Vqo2cexРQD9$oӤ`ïs8J.}+9J6_~dԔfi7_oxY@2n~L_{R3 ?5@#|_? 1_s#un ïaUW_k0 ? oVe~~ ï[pE-4d~7u& _ ?o:M\0 ?߮< PWWwC9~}/~ek-5LA~oЩ2xCng`x }~OY& XGԏ\ 3 :4`g?,~=A/ `',O$ Ig~D\ԫi@>MMۄJl7:"P%] FRF8NU(>ٍ0d\KP܎')LJ)q$22cb F'~ z` z2}m`4p-MSˆ= Z B,$ ;@}@P G c6Bn zzA "'8,ܷp?j>u;ބPZo*o}p5OU⢗UzE/pB^^I) ?eYM%B&>Eϐp*=ŊXzB~ѫ/Ep[?IozE IEMEMe!EM$Sz~w}BT#́n΃uƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸqƍ7nܸ]|Q܌/IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/256/org.kiwix.desktop.x-zim.png000066400000000000000000000357141473106011000262610ustar00rootroot00000000000000PNG  IHDR\rf;IDATxxC"ذ";|"Y@(VQAHSEz BB@H!!!!Ϲ3wْ̝ews/fwv69qq$$$$*5HC$$Q%IJWH"v񋋗װ $$l_۹sg͛7m4)5%%E6lP?cuP׮]ǚ5kƬ\rDrr/0o޼f: Jp8UUPp` +q-F "(X%K،3 ũE XAW/`z Y 9n(L¾ #Fe vyz\@0(A` [x3gNСC!BX@Ԃs7Ai5y,'w7ӏY d K` !hBecƌyI?H@jbeE+,,~A OcZ 4쳸ZkZPKKLyC@J ?Erj-x}!liF[iր@K@A lѢEhkזA\8&$@T@+:Rz@ JA`u FL^? 90X/DPTL>OVA hT#QE@BBG 5(2Fb"DYOJZpg͛Μ98moA$' Ha{H[=Tih.+ 5xخͶnъ6@,Zimv` @ :bDd!UPX.r\n 2*KC`@&[z "0H5oA$EAZ UP7p JpK jV~ӎC90(Xˆ7x˖-喀\mۋZjuA Pr8(=Z\1}U(T@HfR4AI\-0+n^?ChI8p AAk̠/p V ZN, Þ]y\e8 Э@ݫm@^{gy ;v( d;K 2 GL.*u(2杊=-  y6 @d0V_.Y$SNA(eBp@t5MhaY]|O@X|٢.]\@ Q`me%Gj[W*\C:/WTxdT"Ee)V@ @W{.KXW._^kDD X=^ZP[xL4K [^,Ğc +D%@±xhĺ~8IHYX@`SPNVC W@ mìsKjpV^O> @hZ&}_j{^Q5] Pc4ňJ0ZJ{!wK\` =@H+݅XS>W_N ` w_W;% "a@  %`1bwM To`a _`A/`l6݂0TA PG5dȐu%TCmbMWW!X )C@v"(hu000G9YK@Cްa:s\0$ S>sޝ Q) gRcPT0rqq@7 T;; \9+`,:h`AZ8x?%m B@&~GF+%Qba{YtC]~%.\u@0ZI D-AiH_,$]&` \qf]({@eEVpk|iǜ~W~ (|UDwR`:{R`Vcp.bq>%&,< 4K`'N>\$POX  5` PVA#C0 pc@; !*aTy_:!!gج[Vkێ,"0 ܁=|FOqA@+SX v@#@;w> @?Dx +v zF޵#Bn 9Ȗ-m˻v*  yÐ.c&QB O'^0,gϞWy ҂~9¦A5`P =LZ܁}w`ٲei{zYr"-(m +܀,9? {0[ا 4~GF d[TX, n=b.@4`ň׏%`T.܁lاC @aT8M (4d A]萑D{k؊s @5%2rֹNmEA 8h,Çf\<8`@CX JػحC`=ϭJqz ,mѪU ~g>@m Xl LAس;gF$ ܁\!5!P4|}i'! ʄ<@mYۈEl)A}0TCG`{w9,28ҒRIqri[Z=CA C WSzQFY R 2iǠup B6lux1ܩ%X*`ɰc6Q,A #__{LaQ[x1"0RR6>L7Bύ3 38h@|Ѫ>$D,ƣ*Wff+FWT-Ӆ"5Fyr `?>KJJP:u*,j`n9x}l` 8$DX]SFH:LĤ{P{0 P4Dh 7pu`Jwq+`X,@?'ȏve~x\"~$K9V@x 6 VBDTRpm aȁB i\yMHӋ fZ b`h @k܄by D f$?Ry`قyBP6,s@ 4`Q@(To`dVb6A 0VqCk ~K "@Ӄxr(.VOXh1^'`%hQ`\ ({\#~@G`!h Z*@`ܹlP\4%LX  @*A :f]skЀ `A  +a"f! Vr ̙ AY(_J TKX+҃(JiB6baXt(p0#Ʌ`K@HM0[t -@!ZPajTBXg (7ٳE@ ԰y,dKA7A+EN& 0`ǘ1njYvwmb!@4Z[^ƎbiCmƲ~YA^l%$lӺ {=0> v&BFZR1HB8ꝃJm.H?`m*"u*& X bOV[f@ۜh ` BC?PO~ DH`К"S/,p1h<"YM +![t u,4,={v%*,5֯okpHa,UTD t { $ Ē`@fSF'8]ت5SO=; 6c WĂ ر rAk=,U *X]KP`"~`n'CIIw  B@-rR ,>}mNiz*?hYkij5Y|Z&w烞ظ kٛo 9LA!1c'`h z,5 A[VB$Aր1кae!~6mڜ/HV#[Y߾+ժ]Ǵkf5Cj/`/]cw]`!`o7nSVl:b!|A*Q :3)+@V=9/'kh{SaY]}5lȐsn &&<4@`w $2ču=n`,X-C@n P7a/9"Ļs8J>hן@Pנ'~BXj'j (kvA3VL9 ր)@`„@}!EX z*@|]B" (f8ցl STop!f`FlV:(u32-KN$^n֭ͪ[i3NV@uEpm5[kb `i88@,|[1N* 嗇u+b0/AH^*Ԇdn/:{zH5r`' Ek-InurBZ'+ Gnƈ4\5#m7)bj@9V`A7@.Ibx (^h_r]I,`)48>}>Y~^q ʼ UEr\z*byyꀡ\G`|lQ(0{v'`Sl x@p^z50{#|lD: '%Ln Uw@vôd),(&,Yf9MwŊlKCoրs@ k= @޶kJB@pOV. hh D3V6Ц|7v fg-\?{СCYǎY˖OhjF| #iۖ=SP7c*x'P@VmLʳ"p2]k܀X.H :,~:=N=tS^iYg&.:ݔpրB;{फ़F&G2=@n@Wo@@l>|)\YH.,u=Fxk4i >@F|QjC 뮻!Pp>҇>>RLM4q)i* NրY{N!Bp8gg T'xl^XXX c:QAPsgNu nBKC|-ݻwwe[E-(. NDIҬtP 06_ 9ޱGj_7e}fg^b;,5΀Zpl1. Bc 8a3?k@h$IHjb=֣ǛÇebs7@xzxT "g5@%}F濏 ȳ cN0P3x|)>-*<=0 ު &%2Qg;YhkpM઺`ڴ[OX#]&Ҁ'v>+K^lVЪE<*x|m8*z0Ԡ A_B#F0d[_l:t4gJUvlߡC<(|G@UAٽkb;4@H6wZϙJ_|ɥJhc84: hش5х,hZR+FP%XPgd \ڦZHF\j)N%MyG%6޹U%;T4YdZ4!- $d\ߨQ(ҥK}ڝLXr98vӞ-իV+j *PO|MU*Hdgoj֬Y nH`` }݇ 0[o\~ t2̻}$pu KA;B=Hd`o8fGMB z^!fYЅ. A$P9p 5(PPUm{1z^a ӋlR5`8O e˖Q˗s?b֪S.{w7 5>ȿ8Wjk8V=h"ռB{04q@G&E:p T9I6.= ,?w#D "&#yM=d X#ݻwO:V{p  Ʌ:^ϻ0xscE@T% Q $ɼߠ![OGI23Pѷ5&+-- *W)`Z .>wŋj +++ $55xMJƛ" (Ν;H nZXz wa򫯹?wN?Ξ{+kc5ϳ'| >nv,Hw-bP͟=\.lY04t ~j-[naz/rL4y|Ɨ_`Ist>B5>,yN/_M> 6){WYLJ&W^h͚u6o{ؘw>v1O4h0O9U,zq+EL@ -1:KN@HKK Iح=];10^n:^fb'|aU&W,2h (s4{u;D]k Z9ls?So%ظqce M_Y (y ۝|zx׷.BsrcB 6eW@ijaLb &4SF8=ziO]ko~ˇ-,qǸ?Q<ϋ_ mKJJiBI7@]{d+w*hX6$W#+Rag  6.5؄=~;dE9_rit;hWczYuH 'Ȼ+Cs}]Uwqg7z+b;B﹮UXf xyWovoĉ6 qb@^u 8{e& `̙z\؂;--187P9rTM=P s{>h -Z`$T#.U:q~%#|nؠ#>f!hp/޽{}(:=\8í 'EU`ܶm7Kߓal(:քPMP;x3JEUAmA(?4\8g 6ҵJ721IG qmW6sƐQ~X xz`jժ1 BXv3f 7mGJ}Txp~ƙ{؈#o|7EBsL#IKE@5[`5 ##l@@X$??[%\-t1(jD{n9vꩧu:i,Yʪ V W=MKK3KJJ {W)4aQ?[_Vُ; ֭[n)?믿<',= g6kƟ켍x߾}F`0ր8CuSPM4] SwmRۃ^h6=ո+;.[{ʫsڴm먭Zbtp,//1r$#Fe 0p\7we쬳">2]VrȖ/FiӖO4fU< $g_|- ~;?EsEj|n\࿿Kً/n~D T;YwqA֭zğ_wߝH(&&&nw [~!3 I={6{Yi'ѣiUI.]{;Z\R6mĎ9B@ !!HH@ !!HH@ !!HH@ !!HH@ !!HHE @B H$@B H @BB Qp޽{پ}V|]QQq^xNN}*++Yff&x}ii_皕%~/+.. ,^Ƃ?žz~kN+ڼy{Nx2.^sϟܳ ܂n^2L!C~=}^gϷK}lDZʂc>o a!_*?Ss}^'a9Xqa$@>۷n}lƌΝ毛8q7oq.?C{&˹+w޽?bc&% ]v?*5kH?ܸ1eM~-ؤIlJCwzXf"@ V=s;{B(xG ԩSlO?c.*BM\lB t߅M1c_+رc@jE7"C/u#@ Fq%'X>c 0@ FqB[U@WS"/ 'O$YJdVH ;zcs @Jٹs/ 81q(ӧOwl}zCS@ Xaq0~}-ܙ+-?aPhtH́A2_ .FIH ( ӧcpӐL@ Hp3qJ7v(PDXcF!">Vu 47߸QcgyBiΜٶs&!'s*.ǵ}y!)){x ޝ{qX}q_զ# 10^b Z@w|m {gq<5={~-k4k[=x%99~&?aC-xx$@1Lߪ"I|^>g_D @ !$@ $$ @BhBpX@˖-[h}AOҥC RTTBP<"0[k>,;w\ hl۶m))i$+^x 9[ @=-3@񏆾ӥ^ z)i+^W^9h3k7N5M@&[שS-ŠF5ًm 379E n4ѩLA=OJzodO)V@}' &)ik<-a@JJBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBRE=$IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/32/000077500000000000000000000000001473106011000210155ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/32/kiwix-desktop.png000066400000000000000000000030461473106011000243300ustar00rootroot00000000000000PNG  IHDR szzIDATX}LSWƋ(*M1Θ ,Q31Bd1X9UC :0ǜff9?!11udN\R@*ml壔={NY7{<99DWi4iVu,KP+wp0y+gq? lx~c8,0Kv;A@Y:L聘N`܆fotD ` ] @Ah4V SqlqP\ї6RXrağ be\^VTt؇AjG8%D"I"ɓgoYdΜE\L:gI ʶ G2JB'4@̜9Dd$nQKK m0<<Î&A3 ~ʔ95)O5@HgL@ 8bht{y#( ^`fb ;\#lݚi>\TA\C #`;\Od`jaNJD<ٔ:L~!cp1WD>nLq[:7==\pYzu9xmji6⁁5k6ؑӓӝڃg D-qqttÊkaY5o[! 3̽JkADZ@[k^}б繹{R- FQ kNR5)¢,07Rx+d ގ@fqX:e'$] Y"+u7#E`:]=WOTZЌ6 ܁] C66v_|j>q\nәm+++n2͖龞/%9rc(64}x=X__*ƿ1883uIzLx 6m0& @R>!RJ4 堟p'P^ J%:;;JY %Z8L~6W PUUBooO""«kEbl4dfL&[oʕ/p$/n}h,U9,644( 0A;ɏ.ںe3Eb`P%ϝ׮A}~/O *p6) H3NP$ N_ǏJ3Fݺ`~TV{DP/xBEH7n$>zjh 6musu>F/"ITjYӧEKK&@ݻ]P?{^WGϋ9^*%%Ԕ9 h@{{;׎Kbɵ oF#Fص(|NE/ݎOtbWJGr _ZZJ{d#M;6^QzIENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/48/000077500000000000000000000000001473106011000210245ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/48/kiwix-desktop.png000066400000000000000000000047071473106011000243440ustar00rootroot00000000000000PNG  IHDR00W IDAThY{PT#t&JICNIm2fbK" jT#&}CD4EQj5AA.XXvy, KWd/-`ϟϣTA iBMdШʕUxFy^ou:S)Kc>^͇ o"=)1ioP?̯Lװ,LsZbc5 mh%9x0} ̡dm6B^Fr=mP(?όې e}ilRvJIIUѨܺU#~agN0e Kn17x"T:<7=|#̦o 8'Of(\p+*+kӧ O(!BLƍ *eV32(NX<"kٳWs/^|#@@wTZZf-iPP`pLvҫ}c'-;h●6Q/w6俅F N6dtbLS&dj\jƧgГݾ}}_fK p:RyǖӧBCu FEAG,{/\J%Xq6#o~͝SNQ1ٝHNN逿v>AW^!`_ FJ{ C^!۷K/S.C[U+_ӼFOCI2wSdp)ᷯ#i|{'`)wB<*D-GO8]PF _8z kAN#knX]cbb;u>} MJd %Dď%[}C mD4DGoPEFb']Al7e"lJX_H+,n8I8~C>KP36ǃPmggr}|aLA&M'Hpv3S3*8?dmd8Gȧsv08|D> l_9"\H q+ys /鏴筠8Rq/Xk9Ǥ?蘻N\$q:A+9RDa$&/6IFY)1G zэ@>D] a;!mh<6v  v#l߅EîD=5 ]{IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/48/org.kiwix.desktop.x-zim.png000066400000000000000000000034441473106011000261730ustar00rootroot00000000000000PNG  IHDR00WIDAThyLgǹDS>1tEK6ܕ,E& htL00PLNPDJ[KK9Z(m=Ӄ`o򤥿us?ʚ=J$aI(n չKJJZKҺ:T*hooxP;sa_4 Ѝ e]|gt*U;( d 7Bmm ܺgNrr456 (=(1] @R UU _~NI$ 3i{4Ћf D  ADw^wt&&&~:ѰN#DW"h6pThh>sM!>!N> 7n܀fyMQc:Qg"aԡݖ)Pv;@O022NxM]"چŀkvmfT0ʰx536cLz*ߏb(%]?1(*hMjVRQ$+qso0n|S >>IKV9F^ ?; `DΛ^7""v bB4F ${ @aݺ 2|0"AA젭2AD">nW5>GX Yh1:gӥAȸQȤ?@^tSER8[o-83t :#B!?cش)tyxz((**p?[E8O-´…_৓'3"GA gLZ(Z@% +>vf@X8qBBp_/_+x \h5_ A>0=¾}kL?$En\Kk-Nĝ:F:uӞVşᄵnVfe4_~_{qZ-]P [bw֬Y/$@kÆCO>\{w0Bt@fڵ:a7ٳg/p(ϝD?ў¡6 0cL5{DI%IJnm/̚5 =#yh-;c}yHII)d^({ n/ FG'4pi̫C`9 jNNdggAII1}|PZ.!֨vImϟ㶚&\+/ I; b|p%y_' }]qV/.6|9zӾlI0IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/512/000077500000000000000000000000001473106011000211005ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/512/kiwix-desktop.png000066400000000000000000000501371473106011000244160ustar00rootroot00000000000000PNG  IHDRxP&IDATxxUU;R.4+ Jy-(E"""*l H{O lݴ2뾲$ݙ9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaMqqqF999-㍄%//Evʟ}C4O?{"ڙuy^Gp'=Y4h Wr/Un#=u~݂;9!k٢kC`N?{ %eʗ?W^, _wsB}K. 8^h?5W,uBKWBuN?{1j@q/{섀?7_Plrݍe @ xBߛ/} @]p){`҃zB߫/M{F 'FV 3RPPp/{{B Ao>!i7y)?P/?Nfß@ ͉/@? ?sM?@M?@M?@M?@M?@M9Q(o&稏џ@ͅ) ?? ?? ?s ?? ?? ?? ?? ?s ??  ? ?? ?? ?? ?s ?? ?sM?@M?@͆ ??  ?s ?? ?sM?@M?@M?@MOAA ?/?v@ &ß@ &ğ@ &ğ@ &_E^P?P? P? P? P?׎S(dS(߄S(߄S(߄S(߄S(ߜS(߄S(߄???y~@ &ß@ &ğ@ &ğ@ &ğ@ &ğ@ &_E~@ &ß@ ?44`׮Tr--?aѣ_)1bt%yA'|z?k}s?@*JJJ\l٪=بny/~_-fz^۱{ Y0mU;pP|NU_P cbb~碷zhڴZ|yW: F+=3g۸qKN\\֭o*|g?|yn``P?% iVyUesǂ_jե^۵rv#͍?`$$$oţG/n:~޽Uف 7 '55?]9.Yg?9P6-0_EsR[)ψ-w4A nXc,4}ğ@ZeIŸ@ظFZq%`y9 @^z-!};`ѢqzPΊ?bԨqEڵ׃|- 5,!p.c <-K, _)26yxPL;S(s؉λ*!ٳǃ?Wy~@(SO=E?W $^X)!o͑Ɵ@(ɬY9b'r[lQ^xcV?ǎD%Kq_%ם;̋, @qzz=!ViРen $j>)FK3jE|/ `O ䷒o8ᇟLW+s䑡i@(o }BJӨ{RWˬXMe5.t9; _cd)ߤ Zu pZԊ} \µ2+_>̟?!oh9~ \a;ß`pmp'O- 񝿆[Gb[.8p!O0q=SG(ڶhgeڴv o ~7nbWnF0f̄${KSՅQQ_˪UŸWE~VVM)&-115j\ԙ1$W/c+Ƶk?٣VSmʤIoZ?_E~O(f+Ob?0]ڵ7_g:sd[;@:}.U@v+-[_>b'' ,u~ON};qV6&,,<[%83 Kğk5j\rJ@``Pe8ph7|mƽğJS8k_]z1ZS㿮 G?[Ήc !\_v WLvM+  jO EO2.,nʔO:}w o<xX6BW稨0&Mz#.##? .);w>xp oy-_Nar $ܛ Κ5_]&|ySB0xp* H)㮌S߼G Wif KΛQ C={B{N  q Wy')RN5kևA0^p *>b!;B[G( )8 y7ytuI?-⯲hR !\~yӂ+ ş`tUn#!y'RRRR}+U""8B6mn>|{{VS\\VzZp'!Jↅ}^_"$MnǝjeaI %7(jo>v{6*~wmp*'wBtV&?>=?)-n_?B@BC=89 ?k]lsZtt?S\T <~ s9og /Gga1n}@ڥ^岷5됳o?9PL6М{n'x:)AH-cs;l_}6obhqCo+磏;Av1/ @gHU=MuZOq/ /): U:umB 34݉eYsw/z m_ԩ3Y7F۶`ᯭ}Ng, 4rUx}SY5rOy]Ɂ7|/&'m!X  {Tx  q]Z1~ouwۆ K_]?ɔ{s8(=&LFF)O_˞=5o~C<24LyPE qN}6=Nߓג|HrŐ$ǣ2Tx-Zdi\Ԅ8~AW_g ~Or17ߜep׽Naw J_%22*SMҡC%KvF]S#R%@8NǟPA0mgʓO>ʀsyqZM 7n]ڷ%CKev훣~LivMͯ[yo5kDTvq^MػZdy{ ZdQ-Ztrbra`B)S9 w1FަmncƌOܲeڴG}lkK8ֽ][=pxߩo._ː!#9 `\|qân;j $ر;&&&6R­xIqpE ݷ`ĺu?G/Z47g%>)=Dzngwyrأ0zEw:K_Ckk Gm}=3fB4;  `ZU9Y^>x|?5F_TQ@(W?i+={~/Sϧ70fl)+-pf ]w]眻z(_N7Y /Dmo3qhGm7.wODSXS/)];^̙a {x3E~Ny~:QQAsD ?sebyƾ{S0v$9ېOXGsI=z|҄ SMpQ6l ;xPկE~r}g#]Jap)3/ZLuH;>]ԠHV^ZdY`e }𷍿y:zk~"?^Kmo](gT pE\{ N0+Z8 UyԾlZ.ނ+w>ť6l崿*f_E` }SB-,С#{)f_[_ 9UN3%@9`]?K2vVi~=/H3С>}Lseӣ e3DGǤ˕P<ә!&>>QZ)S uῥ?[7$ ϪU%?]N;޸qkݻ /Er_l} -W'[(ERU%@MVO(zcǞ n 2?Wz;@o P zA:;eذ ټxxK_Yl>[(6mڵJdܸi_>{}!t"(KE_TTI>R,.㔯Z e_1ZdiSzW Ŷݷ_i)_o-<24+,ddll-~lDV6gbS, Jxxdj- A̘^ ٶ7`-a ,֦Mɓ l})9J-H/O#n#Dq-hg{Ÿ`@g/y$kᨭ>5rd'N-\$zaW_)g-nȑdcY7f{? OU>$1:G6_߲e[c6lM}l5/Y4k1+!!_^`UbUd9V@9/yw }5Q7ޅr&Mz3Vns"Ǜݺݞ@޶rXZ~thd!YX|d׮} ر~_񖾓'ӷ:[+9͖rWTUdsua)Wy7`ȱzwޕEÇNHHH<wSu׃I:))$QeŊoYڵ7+u?GȺ;Դiw]Lƍ[WoLKK ;52vl/IHc2%Q*pvD/+ocW?;ӳg1Pa" ;at=oP=)?+%+͙ HOɒ3-`+F_Y'=  g/JGV,(e[.𷽱}=_0:ɡ-s7P _$r`/ͼy ,˗Uf=.Dw߭ 63􍉉/U_+)"볧/;TS~a}$lܸ5$u6wً}dgΜgrgo#g|{ѱZ HzorA_E~ŋH3Z]bFF:_&Fj;-Yj;_~mUnv>MLG% goSGX! o%>lڢ`Ŋoѷevȳrdٿ3,ɠ^Qf}ޮ~))CZfşPN"'tt[iXr"#GԪ!2< 3⋓_Ť~8 neǪhWϒcN3/) ;y-)޻+?>*e5 X+) `/?^7ߜhF)6 ;y駮W^7X2C>kӦ1fүY!qQ l󷷫_jj&MTZӻ͆<P"@wZz۴隗(UqQرR̈́]BknupmϬ?бiW(|4WٞLvn{X3ooW_ܰZw<f_S+xUqA"gE.,]^O7w{睹q;V.Ϭ.Y__fPN/K2aT0`H3W1z?nnf'D.Tc_Nf G.:y3F'$:-jw?)aވ|~wgg?fm_~tK;̀?F/i^x9ӑB#bԽş{*s~ igիz7̀<X._e :Ɋ^_/_E齯gzrV'˛ Ҽyl~]Ϟe*eWrOo_EnϜ/KҾ-MqZ p% ePo_婧Kbff௢-}zj]rGyt/r'w-*˙CV|䑡Y_eʔuc'[z GQ .ssXլYwyqގ?N_G8d_g y"Jl)6 -7|%j\O*K\~ ]1h)LNzV,4nr巇/zy'͂>P_m+>vOq_[OMsmaF_EΰgŘ=[׿MJ{;(6ɓE yN.^">{5]w߭yKI02*\>T=+r;G #%q[fp]̨w*)))!ŕno?'λ =,^1{cO(WQ=ر;UkL19usz^jwY)v ~]f'NMq%*}D@|4ֈS6lT(e.;ߢWȈS]۵JUBCxc37Z @ًk'L=3)X7ŹU_%66.X݅sL+#3o[O?kS7*#Gѽ9ЁD -zݫk5ChU~7(oo)6 %K} _m3~ݫ._uWGSAճ"wD?[OQߘ##=w?JUḱ:u-z/?G֔gK`_?[O*o\t~́뢤Wᯢ6QmQWɂAճ| R7W9s_&Uk |.ھ}G;>))'kԸX=#W_.3@+olU9Ϥ5k~r\]y0wᯥK^4hX,5{uus@[y\JJJJ7ts5k-1=-[Yp?5;ʸqu_m۟Q_ҷ_}v37'IovA,^YO7Մ)Sގ('(7S̈UQ ?7|{  ZO>+@ρQՋϩЁJceCO{n..bѣ'Hu^x*˛Rܔzb_!PN_gh}U:zk~"?^[;8q2詧KV;9{MkȦ?'#vVN? cl}ş`Oh 2a/<9;;Ν{f^}X)TdtPvm}tD U.A-O ym^h-􍉉4xg_ЦٟB_]Ԁ \FZe˅{j @C=N6H[FnU]𳨫nLL4i[EKZ>pv~5#7n9 _U#@9hu_e7zE;h[&==D5o~S@-T+'vo?W @=4D?-r|ǎ5"*|<)O'-[Ѯ-FqXǐ/?~LY"Y~?[o'+hVyF:IQXnwd: 3FUy|C\҈[ _( {*fKp{jd?[߷iڱp֬QU_˷߮ VcRVUgH*o`r>:?1ϯ[Ox1*W9^{;8zQ!{sel?rJE_S  E70C7_N wP'|k ?&լYaEছdT-ӧώq}WX#TU6l%w~{Nܾz+ɶɾjYߋ/n{lXUL8-?]1_EA;݃܃2x0VDng\ gb1'խ}W^\WzWwޙ@ϯrQwY0_㿒`{Ter|5[&&&1 ˫ί׺uEV QW~Mu?w[w̘ ,S{3J',4k;TB=k_pٻ\3F8W/nTuv_~*mۛ+_׃Yy磌ϯlLS Xw~Կ{e`=Unn?/0ecwg~J3dHً!u_A({݄\̚5kև:bK__?Hu|w(>w3/x?L( #o9go={?ɖ =ȓI_ˮ]N5o)ln:H9uUc _oԷ\{Goy,*;|脚5~ݺ`gE-yw#pe5Yj_EFYצ'5i6V6m\zU^zYh- 9 9T$o\BXQU}.7࿜`Q8h|F~Nm_h$'̞~\ƭ~-:bm,zq*$ɯc[3iߝ;V? u2{+[_~yrBllWlذٯw{S<񌀺gI[6 o)Voo*˗%`9ڵ.0aj_^G{c>rw?yNW߻wƭ}]Ԡp1I~~_=GuV[nH޲H{}FŸ`̶mɢ4ܬF-c#>2ASΌܹg; u#e̹As#70_Q Ȳ=djW9}A񷎬wH{עvŅ-zwloqrg^`u zĉAÆ,;+W~W;y~@'O]|.Qs_r.ڴ)wy K.iTpתF2nOw>/F͙ h >{=?{[:!!ML u_…Ec1qUqUZߓo/s|f̘[^|gM~w(e𷋿b>>Ybe+[.*$sww[<-#Xʩ(G.*$F??;e`Y+eꫯ#ڷ{Q믿)]iM<X]_eEB^Mw|<2r`lGw<^W. 9DXGoߑ#|TrUZ`q$?XGoŸ,*?tsIYTHw"[[&,,W S+?L-=5iқu4;kQ.w"_P^-pP)Ÿ`?+ |1oH?*Ɵ !(Ǟ"@=39??? [fP^F9^bRl/ǟ`]M?.3O&##??IPES*S  @E WFbPl/ǟ`]M???? 3OJ)-^?29eS**^?S/Ɵ`???{9o)9o)ȁ=??IT???{ ??O(???{){ߋ*i/ǟ`]M???? Sl/ǟ`]M?"@=3O(???{){ߋ*{^???? ]fP^R) ??OU u7̀?^??{1[XO S*S  @E W9^?^b) ??O.&`??h$S, ?$SXPUP"yMJw ???/#MJkG<{oU????EsL irUdee 7Adff6?? Pց???{q>V#ա^'퀗 Gy4W_;ŒC|???{Q>4Cx ߋ2+w\h-??dtºA??XR=1Ѽ#8 ??sϿ9/ U:??'d;9L aaہQ0o|$w`m9i7P&Jꣴ Fp |n{wـs$k]%=%5k4"T 4??#3S9:rZ>#*+/ǵE?r#?g<#W95~g/%V"T9~-+ϊȯVNG1qe2Qr2@)D,Ytt疑R-$3-LQyD2B'xV瞎<_"K"?"K"?"ϊ7|-$xy>εXG^{6e俛-OGϲӑQ)Nmy|:|ȏDEDO"77ʋqy>Nev+ڨ]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa33xk$TIENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/512/org.kiwix.desktop.x-zim.png000066400000000000000000001172071473106011000262520ustar00rootroot00000000000000PNG  IHDRxNIDATxBUQWX^U^A ,XQA@){'$9$3ygfgd239V-  (fՆlA{ AT^0X (I ہxo,IHX }l/ APo] hzܾ}_8@_ZZЭu;ӌR#nqkŽm`O@Pj :fz{ƍsWZ%lʕ`ߖ/_Ȗ-[˖[ۖ,YۢE-\p… ϛ7oܹs'̝;{̙3M2I&7nO#F?s':w|_ǎoi<\~':<>0AP^,77V,''Ƿed{[v6ʊXff庛eddXlǎ6.lm۶j[ne[l~zf ,^psY0cڴƍa^zW_mkNƺ7 x`O.ztgqw۫hs[LJ<^ 򸰶X8벹ݾuV9nxbl͛7+mӦM%6lX/z֭[֮]/׊kFld{. lŻϟ~3FݫwouO=ŵj{ ~a Z.۟ gnTXB^fan0L0ؤC;0`ak֬fkVfWbEE,'7fm֓a&,lo0`MJ{Ohyrw5O k-^*@H-@@\ƌl)i8Bx *wc-`tӯFpgnYBP0({Laf ZH@$ `'.y ܨS.2rә̱S/_9CD6axq9l.]|AP*.@Y-bsg.,,V`%쐝m /X9 5!X* $pVha oT!@y 'E8`㍄xND'l7>h/|{--@A) x_II _pvRr1 %c +d? ֪ 0g2D@@ h39R% 0s|Xǎ&ϓ˯:4kۼn!*#5~wf4Vvi\ߙp/1/#d`@U`@ BDAoR^ GQ*@+g 6m$cnj0={;Z迳>A .p<@Yn|a?O<ϕ`_<fApBn0ILT(D)_ r;b<k#!U +,aM"y`PH`;v0`K/v; `aNpdX*r}$ҥGXd0^ 0J ƎCdrgY)$ (RтC^<`SN"l.P3U'YPi!TPXHȽFAdyH`X0lذoZZ- ,?ś bI4! +]V}ۣC=IP;,O"$<2PHn!<_L' `ĈeݻwC9`/@Tuݛ)cDy a߸DQ/fGx`r' (' JC#GڻWG}tSPAwhhڧ ; t0*d8J  !{r,h^\&$5 2 CXHVw `1r|Ip+c > B~[w |!0{H!UR\2C7 [#7ْ0 x{64&F -[b+w4,FDJ3<APXsEP n^Tv C+Li<[ !#0^>M_;sO􀀽%^rrh/ $ z ]JU8$BUwCC5d99 W *#yJ O@|c y]Ǐ' ܀?.SkiU!,^ܯR eEPou|(!#aΩF'AT} Ohu0u @ 'L0a5\s ̲ @#"o5нű۫Ğ m%#yF8`}uu`q'Lm1B@z<<0o>GK9Tr( *H,nZn -R@@u,H '-)p%Pj @AIeKcF-)M۪/zHjArpH(9\G\uQ# *< SH&_xlH4ثD $0i s"(@!ao@Al*8 ^.en=fk OV2<'  8--`@1F))(@p@M~+ڶmw;@ _!(T~-Q0ץM03KJ ̈[%RyFyA3)pz.z~ p(X (Pca*YƲ\~_'QYs ?((PX8#i fEn0 nItsXtO),^[՝M/e K`[ %c|'#c#oF$<ΝÏ?>@@XRê֊cP<*{Rhv 0iYR'A9`@k{=1 e0=F(Cx^ @zNz\ǡb=n~m_~YK=AF@8!"= b*(]h``aO'`cL \gy*xQ"q^^dv ;mǙUWAa0!E*:${-xe@fG+lSkEF, EB`Pb [LO =B%%KBDkV3g><g.)qq綿wc;$9EmY[bY= P(r Xo <J1 >hm),5 wt+l)&h`v XmV!` hj M $m1X@/s0B^n^׃m`@V,JXj d`W`U6.Cv)'z41ɂ2^{uKj| @UNX\أG7ox /D 3 lynN.3,7 rxP vK>e|]**_{%%K;$ -҂o.jO@J5%g`+ܩ†>EhJT0fE(@O %h:x m"'`HK{qÆ @H'E R `., ހM< m "} fN'g8ּ+WM /14h!ZSN2vX=FuUpBlҤISe|񁥞,B"s6&᠐CA9wFi!,(a}|vvOr)@*X/ |z-.Fp\ŠA}״iӣʢ_0HdoY r9aVB[`kN@L0ۜLeuv"CchUP2KwVX=ܣP9tnvڱ5b.#X s,^P/gXbrY0_Cr@(0|gq .9r 藅X]y pH(=fX=^?㗫 %P ~KB y)h۳uȊ+W邿h@|?t +SLq]haS=qe}]Nm+wo~_e{./b.p4ژI]vn A e+$ ͂RADJyy4 2 _b 015Z $^ XP.,bs Ps&EPQ_ @_a)b^bbaY’ ;FB{aBV. !{ h6J'`V@2#AU) C.3z cǎo;K1X% 0:r묁@;k>3 yF4/6Mxн` HiQ Y bsO5 2B FSY `-@!J [.p 0ӟxK$O CP]@$߀^I;xM0H 7 2 @ ՠ { >0hiC <}0;Up3qҤyk+!PV}_7iMIr`/|@qup:L ,7^XTN K , ΑN/9,{ӽ6h G /y嗯8|On{t|oma,Sܿ9Tﱽ_ュοmy`m?Yߣ}_oPЁKC2Dz ZBG#Ä H0 aN: @,۷ a,К-^7%0cx$W-xkM>u[ou# Xr{`)ejpwya{01P#16?%mn)P ڪ%:1p0vE߁=' `f̘]v `@3~ Uݫ { 9$`Ku wy7 n#^; ys`rMp@NJ 2(1'n裏T B(J%(7J$Axz PVؽYPz\*\1}Y fV8W$4XM-~#@?,sfAPh'\%Yh{vL0 ٚ @Us / 8&z X_oΜY:uz R R?\b\_aDE2`ha`od70PVi`Z8yA~Z?PAX/ gO@ 0f p U3z@! 9.2#`rPh,^pm7}Y! '*| V?8XzaPQa508W=&kna0J 4owKt T%f%vK=@=pH*08 Fπ|}XP?NxUh@ IwddsܚY` "/5P ASx y"L];"@b8u޽-?}`o3$*wı܇:R#HOMH&'P(`E *x@ p=z|RO@jx o } D"TlU8 H60rLKYP1(Hf C{.H 6 ʉ X^y_?kРj0ěS b34P MpM t d/ , \&fgg}  PB6x媕({8D(p6ZpA xWB~2X 2(H&PhݺeYV xy@Ѣ{ƌ3XL /TdmHx(ɂ>!P6@@@yTQ @.G_P A@۴ {hƏ7穧AX\ac6Z@@hTn@-@0=!02%W<v0{XeCj &LuW@`U&4bbp9-/ ȭ*= H;=o (:@J4[[@ndDޭ7R@[DU@+ȉpOt}X6_g+]y⹔ j1ǩ{ ^BTpx2U]BTئA,@@'Â8 88!@9 H[:۷oؙ8O@$/#10`jPKϞ6h@:=? $syz2q^*lCU;`x>&DR%Fvh-P)#@x$ FYtP.)`, t!@h]mw| @>ICN9%BXJ #Ι[ާO7>HrPTK4_ҡ@ ${}i$nBKؼs+ߵYf %dL&LleAo_\hVK(@j M(TA 99<pxTp:H 0o{5o޼  7Þٿ$C?/Y { sF@`;Fk` nzzyt Rc%K؂٠A~ଳNv b9 z  Żطl@Zs\I ~Okh E 䮁y$(~, .dC.=<@1y<*$ۄRbCeX;!- l`1[5 P%%>rB xbh"6lذ]wݙ@ 3 HrP8-'etCrlPZ `?큳^ǐ (^qWV&{gb,f9_othCA l]HaZآL p (yy,ey^=pzF tx]> y߇U"(8a'/OW=r"IH,$$:.rwo0h7h^-#NqEz~tJzDp,yF_C C -+ Skr;`ü2'ZZ y rJ^HhDoԏxmyㄍbM rzl͂@ɁG^Ժuc P"T8@ SUyA@d/QWvtx$p&f~Ɖ LۡƎ⥗^A(Q ʄt `u\3mHS: ! R-?<Asm]2,!`„ k|@!.vsABIAAg%E'Q9@Lp66gT$41 w t"„I'nl߾=? PXe)'fN@2J- 28@5 퀋vه(yvЫEh}i0iҶ?A~:A(3 :J8^hU `bG@XU %Q]VV&j2eJ?N5 \ (O' ZI`KȂ D@ @%q} K]rr%9dSN/ӏ[F:@ t(O=fB`\^a9!p^a۶GwfA^' ; خ!ӧOꫯ^ǫ H*Z<<ޥnE(ae9"eYYYw$\O@K #' ;$OXb[Dp(ҥK~jRK=?A(HNU((ܼ7//YmmaEBsB5 `D0> 'J P$@S9ڵu P IK3+PUU P=pK. p91N}a@c/pX! %1p[fm@0s̲ݻwlР@2uY` $+o=Ŷ0H(@}|~@D(u d!@( `l֯^͛7o $ PaYhV ȋVda (0 vT8?y'R$(<=2 9s氁 Nv I Ll.@EBy=CAAj/#PUlt>ؓ65CXUy9'' nsere(hH@`Iv" 05]d7;h#xCG@z Pcbތ|~v%`ee!JܣL}DR(7]VGhC Oׯϟ͛<򪫮:#(.IICU 9qZNp$z7gМ‚B:y>%SR|ҥl路pHccy|̙~6mg&Ob'NQllܸqlرl̘lhQFQGa=M47KiϺkؖMX&zhaRbUOV0fh s?xP (j56QC^ZfH Z&*4ꌀ" G( m#y:tuqUJRe˖ [tpӢH?ɍdrS^Rf0ɓ'001chZ=r$1blذalȐ!A~? ;!)a* Vx<%%tCzA<[pʕZ8`> zÇz]w],0IX ѡD\mb @m\:!P_ಳ#\lw3 H7n(=u։Ҹ`` jJgKu(X,zٺ d2̘1 &(мc" _†Jglr(x/g^wެo^xh[A%a>9,+Vjn#F _C C+ d SHG(@9W 0Kf&jT5X+ g;`r -@@Y;P w !}fP^ &٠` [y gٟ so@ A~دzu~_A!M6}E(eHYhaz`׈}٫ XT* !ԏP \XBA4!p7@ ViQt2 0t$n"d=`d (`@0p { (t@MAϞ=O?~v~.o,:`kD Ȋ/t + t 9kU- (}xA;ݫĸl!ALo0a`}+`xV\%b ,xȖ.Z(]{@xw 2P03!r &\X8`  @0r "r~2ۗ==z,`r/>k!HC&{8`̘1k^{[LV.@EdOoHal 2X=O6H0` \"XmI !@X0 X'CL)@L֒ 'z0Bp ϓ ႞=؏?Ⱥ|Y_ &N0Jm$OhB6m޹@I  $ @T ?js|MċxtHٴkxh`Kh`yr;v~,! @X]C(OHnĀO(tʩvO2@UpH#oU0 Ày00GU`PhK$%1Z: 3@ y&]DTC%1! @*aA0. Pzb7U乄\ge@utV!` ؠ`k"$dX-<  K e y;0۵  1ҫ D@?  tI3@⥊e(@ A{2`r320eUŶw2 @/O\Y9qpC` ,` HAw!k&&,QJ4r(i&{0yc*y?X@R%z$&chP"=~: `Ehaleplh.<G3<n0 'ځO!U`3`46mz0J Jϧ; {5o޼ PTM_kiPAeAO T^Y7B ۲ťg PCP-KK∗@=Ho WmM1$+<" % R p"@mm|臙 DI{!$hNIШP @f@$w`p*Q Àw T ̐@`bU!}ez"3䪫:@/r^@rV$^"Eb`a pk%zv=IP@Ț8Qp$pB!% YnnIlx40s|#W@ɂT5@% RX`o9ܫW]wݙ@jx(@X][Pw tzPX^"U&h dZ$A \E@Vf`C`R 8ټ[h(+J S0[o= mg8%u|0sI.=l^%y &d(g X<[{L(yI':K9rl#C΃: j@K4CK u0;Ap19PTDI LR8@5',(z`AJ OtK ^32nC[@ t44#`t4F[D3!^.8XA@fHr̀|(偎fAOv*IR+`/=lq l<x y "͉D+g@PFx@F5L(Hw4x0u_BN LD\lU}gH@Q)9ٖjL %S 6( @cj*g#"/Q/ ` aZ` >Pj4o<T͂ z,*e(D0ѽ^U @y#I8B  9Xc{`P X@@ aAbX)Ipذǟ~s%Q`@i\ $ xz@uNs_ (Py<}#9fh [0r`/[ ҌH[TU@`$jм { ,S - @ F@$IP/I0 qgP>oTTMy' z# */2sQ ";k`% *d<(bͲ$0 _UA!;lU<(Xa0<rS! JO>iǏ+ @U =10ZH Tnz( @bB#P6p esx%ceeG-d @ ˖-rA2/xcE@(y-t`19u5G֭[7n'|y]a:|ލٓw(6ZdBȼ5hu1y{XF-"- O7(czwn+ 9Ɂ M  O@tP=G @  쉅y^0` 'e`4rZUy\'(6R _X&XbkZy56E@#/ `D@o$ 0!@"W xxbe kBux T`c){i@x @MXy]vo?<\[oM b*[..0p@'wL,t€+s@| W OU lV52m /@1 ~,={y5.? @ ^M /,/@0Px<k"jL Py.I\YfB{<\H8qAM:ƧUty7vZ`'j@~?X~q{*΁U QF{t@aZнPaB'ZrO T pزe3x7^ ]b{(K2Px{˪ e5P7@"s졁0@ { a&D@ 'B# 6*]uؼ"h\ڟk@(j۸qcWqXc#i%p=sQ-L _[_GfZd԰EU};;ߡRj/A{b>4OX#P0hvJT;@ Y<\vJa{g@H%1V }Ͻb ݥ|Z6j(=^{5-?#<^ ?cֻ<{<۲yXXe Hl>~K J +$ R90 9!@[s\mͮY 0yw 5mtvDӦpi^W\kɁesY- =ēMؾ>0ի߀za-XV؀xsM"!D@@ UyE1F %I3l]ҥKg^xeg" RX+VX;/̳f ,|MA7.<ST!z;Y߾}yM4ʂud0Xx(Q BNPyr v9ڵ/.4"Ky)͚7x;c#u3DAN<ŀ 'q7YŮM P[K`2TP?K9<~l6 )R} K4z$+CE-^B ?<1X(4`v/ì޳7L#tP=q0:m=wv?~>FO<&BP>BX :t AAp@,D E:T:]QP6+Z*Pp -0Aȑ#Y 1V Ђ' ;6p`ހD5* \1`ȋ~QΐV:X(I`xQĻsx7B`go((y"`)P^}[oz -?wc-A6ò?u9{Th~?,y9J}px} l`$H=4/-yGG|ytI勳f6P0Hz\a)YpB36v̘U *Xg -@ '  ſP5e`cy׼Au{84P7>}i Ocr:-<UAaz Z m7<@.DH ,jY XΝ 1N @(t+,#t7P) X_~FHƍϓq?aգJ`oC@܀my{@@c ̈́M#(z@OÇ6I-g[`{?ݻw+a+9C@}>co߾1ɨ`JصlZCQ2HÈy"`!IԯY|w Ѣy-?Z'ǓW/[3$o@"f (t4Z݆VA`ظqһbײ@" Hzv+Rk =eN=F`JhP?/NA̒4 D/#$#|ׯE" H/?,m W_@Ъ<Bɠ !u PK!JX=tp-#@G< _m7T2|иb(Y5#HP7@/eC mWr﫮?,pMd7&ֺcg}xMvSN=oqMs}9,''G*$o@ -rz\E"M~>9 lM6ի_`5!Yn؎;xm~kW=z9Ѡ~C(=0WB`UB$X#'W@t pdѢ;N?V: @33Zp?ֵ7ˉ ٘`I . X{+k!B@r=% J~^%@ ~'pR"R" * @7+ذ]:l`Bsݷ-nfܝ}eX\[ `i$sH @[ ` iӦ7tER" * @۷?3h֮YhwW1_XZ|P:1[|Y^xZ1P&%a1Хjeedlxg! н?,n7[Ίk!PݤyyP@(;?:@LyJy;]rwiMh ?,O> fϚ-"T*E<-n1 > -P;?w`]vҒ*0!CS3J(v*9<\(^t駄zk! YQ.h`ڦ>?R%J!@Xz}OߖΙ]wX+rSm ̈́zr`l4n`z{b*9rd{02~q`qU7opȢ//.gQ{ZZ.䟡|O) @ɀkVJX2`|eM@b/&_Յ(="Xh6eʴ/~P(qhz}ϛ7'^ $;ovˢX_}7.‹.f^x?@oCKTm~'p1l Yi|zʤ<#E#L@/ @Xz6p^L~VPyy:}?`?+wR0wau9\(;PZ@y4 JJrau=B 7t6JbODy5\su|&|4r@xP[k n:2*U7 ~@Y PyYDe 3q͚5k^˜ x`-4N8$,n)g @}sHT%}eоژl :h㲪Lqxu~wUXT}~ݺ^xyV\79 ƓKJJ\`%Z35lo^<hj>}F ' $A[> T]p ]2ka[6o_PB4nxoz l>џ?:W_i\w OksѹwRatiʫ TomǣPB1,}֥vץ-ikС{F-])?&jSݏR# yy GrUHڠ!7Pxa8& 3c~J G:uBZ/N>%/+''v1hz=U7]YamQNf'`c" { ؼ a@Nvֆz*nD ,>t|2334y앐U@K!#ajB wtUna@][ZjuĪyf.@d&M|I'j>,h׮fH  :=A\㈣);<ڵ_B-[`/w<[b3o9 ) 2|(ŚGe7&pġkKz"/1QCo9Zy }yrat=/@ DHe@, 5%ZPۦM D]} 8h@G]v&AaM +\Ѡ~li-I (򮂱v ( > U ( /7߼Yy `)u6ߥKַ_?vP{R/1 ';'FpK4/Sr~6QR2}U MwnqLX*{90vD ;uqlJW@o_Th=dADK@‚wia?W_ %uMS=d>۸qSsa8`fB,V[5@~2<(@@?%mVQq'VM O: 48No@dܒ`uWR NoX6YŅ@ A>  a %vϳeʁ5oiK- !uL Pp$^| ټwS>~w X[  U] <E>:8 &36@(9 S%o[nek֬ !A Uf@U5:߮i|]eF`{Oa0uH㛱`mVV D]B B [HNwc!C;ثf]YYȣ=q?lUƔC@)P^-+q@pU`-οy0Xi DTZg[ ԣ>b k۽{w!{;@ UVeNXHrH;b۶mO T( 6hTWmOԭJXٷGLTKF9f͚R#DP)%f@ݻ ڱckzQb<* X:t;dsȟlȐ!|,g68ĤCYX$XU#>shɖ/_/..~'18^J}a~؁g')90TF^i?K:/xu]T/M+4`x)VPPPP;Pn(.rA9B "VMdǏ\#W:xv=DB'_1 %:[yhɧ.\~ 8ziycIm|XbPX C?ށ؁AV$A?julҥ_YYU֑DX 'ӦTp?<r[g @)$RZ V_۴i/zeY`g4osn=Pd8j UC"TC7/$} 4$T999f'Lh`~_[K/JJJؾ};{111Ɍ>}VAd5'썉p [HZ?<??cY}jC={bGYb c]M!"RDc吁3נ^  @5Ax`X*NQBkpC~'uyNAN_' H9bD  *++c_r rI9b+譅k'ϿPB@CA0@$s,>ukvܙr~a~D``6/0 U E OGs =N7Z V3=)teΜ쬳 &|(I=mH^zeXB]s&qWkJߠ!ۇ'6Niuex6JЈ]w_~I3~/h j6ȉN @µbJ^ԘƄji#1w|3^*ڴa|-g6t0aSLe-dfΚņ .lРA߳o;wӖG qws5;ر/<ԭW߲*@x-hW_>sb ^ E4O~3A~7(1_TV:<zeet @衇 ux N#f+uֱThR*Z|Yff&lq޽g}^ 0n]tOb7n r dB4s|ȫq͞ԷyfVg{:I}pX߾};UتW` @hyb%V~ya뮻bf{iii˖-[.0u {wYϳzYqFshGс9}>X&mΞzi־{ sX^^iѷ_?֘ M978rT| ^IH#C|aݻVW7uY9yŢM1y2jkY ?y"1~ƌÎ<`kz(2u F@VN t,JpQix@a0;~oAPP͟?_\A@-vǛÍyp-< AA Iv T^kqDShǿE PJP8l˖-c>N<UV6 H6nqt @~< /СPZA`EHE VX;2#A00P(f w<zk W-Ů!(/$0d٧vd/hĮnv wNlA\V?d&:M}8ydJ@pϽ͝X {^@( )@Vڵ AEEEl*PanjVѾ&ڌsodm۶eGfy5&JPk d$vY|/˙yex)''GLK7+|~z|ځ7giC e?'H5p_>ēNfO>_ CMя?(}.IQ CH%(iXP Ojg袋xZLD}?`XԦہBcT˴kDƍoŎ}]_Um=0ގefڴ4{ lZ+ƈb?2B4ȣa"j7駟Cl?Ն3zaHYoFKhqߓ3n& E~Zե⬃߈#"jRiwSO=K~ .GJ և\U#*:4 Њlɧg ތDrMӰoI~/?nVgTcoS_a8P3o)S꘿a4;6l^yUߡPudZlsWEl5" ![oڵ+~Oݻwͣ%FZ?  @Չ$2~@|;ww޼‹.-P@ja-K~ Po% >~3:Ku  L#6ev< v9_Wπ5a?D98} s"PKޤdmGæOh"ָ!Z)m-x˟Ï*lM^ŋ \>ia-aN3#B}x}S~1̸ׂ|o;wNҰaDӫ i \6l uu СCs{mxWSzRYgV֭KhPx۶m@@ՊJ.Ptbby|$h.”v#51SOoiΜ9 w7~ ՟;6I5h flʎ<꨸*-(3~lƌi{zg{/祴 ꔛˎ;x>aw>6ߎOSr}}~jɮe˖{w-  jc.k>.T pp&ki;PsB9JgGߧgI еkWT~8zf to #!,HJ/q 4_4E˖-G@@j+?c΀Aμ/04,I!uK}YTT5Be[lI/3^7*׭{ӦMo…X<{Hヤُw o Lv6%Knzvly<2Й7?/o˥þa=XV) jժ5vI~N"x %XMiϼh`B]vRzp‰H)p/v |Nn}뭷 Eg^]~y3㛝3&:uER"yWF,y~ǴM+oon@@J>|=bз|ʩ{PdEEUڵko꧟9XtRCSNet-`ڴUW_sT)K7eLݬ-Uwŗ^ L%%%g4wy-8m2Own;xM)e/Z(~WZ? AW\q%@@j_ x]͚=;dM<*PoBϾnT餙3gZ*ҡ(j܁D ԛ`+WV~woxᣴM;?{@4TvNc? PW%+`}*o~FTRm^@J=вe3oۮ]6l aoJ=s?XD@(ɢk i#E~ؚ3gߠa@>xRO}ι0唉.AW_}{o6?rv}ι xI'9 r([~=~U,XtSO'd[^@ h˸qXμ?ߋyri,///m=z4_M+"PMg[nŏR6o:g:lʔ)oGK$%^pIK$׹袋!&TAUƍ/Z  ٖG}4P… (ioÁ*Th,I'+E_w¾w|1i˯= POڴi;|oLݩ[>8i~tH㏁W_B~߷~'[ QȣXnn.~tHρ=(Pe-~ 22v꫄^|q:IHQW\h8'v̜9ի ϾZ⣂3(a??8:|Qr@#Gzb"ܶm۸mڵkcJ0;ē؋/F- ht bS3gTҬYm3|/Z90W`үWm}갆o{ zl DٛyVٹ}@߽{7{wE&=-duw*9Ka1߮]{zL}پxҠX}&OޘyGTԈ#E2]Am{WoFl  E,p*:X>eүUN 4?0~@])12;v%@@*޽E0/~tܳ.9R^T;OyA~n~~>k捬0,T۞t<׿-@!T]Í6mzhuc;'&k{&w3SJso̺uκA?g715Ǐ%۾^{ߒ楲Çy52 đ\x0_{1n\ԧvDSO?.\gAYE˼VZ?Bw׎ @g}W'p:?=yI'¶oߎ(y / h:uСC֯goiÎ |oܹsy?{J=6?C@@u{KUd{lO?eB#A/37g?!?>jz(]۶oI&3 nt?ٔ)SlDB_3 (p׮]Q_=5: BA Pռ]4jԈ+ `U w>‹. xGMT🫯@<>;CHqmذug+gy=s{VēN\āiAѾ^v{gu(7+,,rGr8x`\ͷM[k^_~8 k{=ēŋ@@*k-|||pcF7q$%w9^~Q6%ڳg{(vm|ag}oʕ+iF@/\?,,XN=b'ƓO=XO<|HSZQ1xԩ+9瞛`, zj^}rZ/JT6 \{祗˯2f%59PAGʄyqpXvGi}񪠠w7-M\s H5+*.l# @uu*%K/9ȋE]̺8&B[ZZ2 4O2ҭ*CF֭;+**U)i{c ~m֢K.,//lٰxyIl_ ԫW]GW5y~٩_+<4P#O۶o;00b׽ sⷝ|)^ s@!f?ԍsyqھ6۸iSۗzXÏh*8Iy _[^c_q1iۖAŭ|O 'pMC }d*ƽ,njayUó|P :va;Bt4<сC=y>4<þk6DtCPL$CoA 5]K/؇}ة(bdlɒ%l…d*>HP`+~zwDX@? TDf=0F{ }U"k _Zjm6K@k[7 BBHft;t A4Z&xI%tO<AX'TgZbGA@騼|֭{wm|nW^y;Jg޽ } 36z   TSH݃=222C     @     A  A A   @     @     @ @ A @A ?5   @     @   wh۶A@ @ A @A@AA AA@AA AA@AA@ @ W%%%[QR޽(c̞={zO{Oi}CrםK/^} /f}vݶDZ֭[YC9mTTYYɺv}?$tS?~^27|~-LrMorݶn;52*^;v7+__d ٧'zn}gAU-m;}ݓTso\och=;]{7-[,!<n/@jM7ŢD c",o> ٧tvO  m=O\-_U=+$w?.'@(eEuҥKK|i|26y$#;<w` U/\ Pګ}YGH`>=6!=z*L}Q Jk]  e ?p$8}vC=K@iѣGZuk]vE}0SV,f`a(yȑj {b睷 [K,a>ґG7S΁ u;]|gJ;8cС/>wJ+ر=ܳ?}l+l_ؼy,剴]x@iM6zU߃>-Zs 7ԭO0oZ+|6"@$AU;ZG;@ǎ/^lG䓏;wFo~<#,33 ~S/sܯH(-^zE炮O:560쟦  6㏁:|H%ŝ<   OӦMUEFfgg:%KD*>k,Pzbޏ?#~G~Zj k:gŲzV믿rx @Z G|<~>%K4h$5;T)=K5{,i@iup hGok&V\)F=ɍQ9];@#:SvK/BWz3 0~U!@ڊbr\y!kM Jh* w^~E@3g C˗/}i/O?$ۼyS^;Y`G}0ޮ|~nho"( ,^ƂΝOhm['ݻ;n@Jw8Qd5<ې, G?pܟ/?glPuSekg?.֯_x$e; Ta((={pP%=?ZZ~edd$m[ !C8Ӿ};VQQ!_TTZz6oʈ  (ዬ3*V\I6lݺ=Ѓ0@˖M6Ϟ=my֞PJn۵{رcM:6O믿xn @(eUQQɾKEP@x,@}@RCugPS`m"!{|y;^ye1Q T4gK|[o*۶w<ok RN:} 6wM:#+@֮] :M~!C[n=Ȩ-Ǿ`Ν@jԵk~'Ĩܮ{\o"Q~ L8>*7uF69st(%.@@U":ݾ}ƯY@hqԵ0rss R4ؿ*YNN}Ӿ   A A@ @ AA AA@AA AAP"6@ ( pnP,P@&;tS MA @@6kV4@~`V^~jA) t>`o鮣Fz6)k׮?5Ryyy~>T@$IDy9s>],++kyff رc 1jsK᜜cu{@`_i)v*v>]rnWpۿ[aW`0LictR?^nr;Y$* $ֵa8}"NZN3w߳˭]B.`0XfK/Џq;{v:?̏tbvx@*>󢜜⊃vv?33  1&&<00{v  MDDv}}0''+!!f]]vy2>( @ Q|{zyxwvtromkigec`^\ZXXYK :UShRfRfShTngg횔ԼkUෲKDD%8--c\\䔎PGG "mVH<<}vv{{OEE B66>33 pW/##ᗒ(௪nddrX礟G;;skkqggcYYuY[QQ}vv9--8,,h]]䳮wZ =11|ww1$$ݾ! e[[лE99z[9-- cYYޑ||꺶<00¾|\ XMMxppyqqh``XMMQHH_WW🛛9--\C88 RGGvqq0%%\)  0%%\1$$  +I?? tkk\f\\pii \   \   qii귵\c\\$ SKK\\\^L(0` -j~}||{zzyxxwutrqpnmkjhgfdca`^][ZYYYZX, 45k=og``cZZs>㠝誥dZZyy騢jcc0&&&7--|uut?JBBMBBYMMQIIaVV900! 5++v?{ss及鈀2'';..~~' G<(&Z}              YPP ~ww ٶNEE ܬE<<  c[[phh5** ?66|| >33;00<11>222%%  ?22> QGG񶲲J@@yy i__ull[PP    "    /"" 㿻.##      xpp Ώ *J@@ ?33ں 6** }ttaXX% ݩ    >22 ߮ 7**܋  i``tkk܆ 瑊PFF/"" ܙ NDD ) (°/##   }uuaWW+ YOOVKK 餞 1$$=22 xpp  TJJ * $ MAAWLL  뿼 tllODDݦ   !˳sjj 6,,   闏 ݌  1%%& VKK  ݤ!  8..e\\  yy ?33qkk% 3))ғ [PP 񾻻 yyܴ㊅vnnzqq뒍ÿӮ3&& =11Է -""|vv¾¿ծ  3&&  +KAAg__yrr{{zz{rroff_UUKAA:..*6++jbbԔ    LCCiaa  [PPؿ9..  &  zzÿg^^ ' ¾   F<<  voo   ,!! ||J??    졜    ,߷ ZOO     A55ߋ<66tkk  ,  )  鴰 bXX e\\ TJJ6++   0$$qggg]]# _UU MBB  4''  3(( yy  ^VV XNN pggrii.## )^VV OEE  `XX .%% mee \TT  TKK jcc&   )ldd yssOEE4((&  '7++SJJzz             aMn\( @9o~~~}}|{{zzyyxwwwvuuttssrqqpoonnmmllkkjiihhggfeeddccbbaa`______________U4 %2';FZչ}vv׳KCC !٧B88 RGGڛ9// A77Өۂ{{neekaawoo䗐ݑ2(( A88ϞG>>  /%%xppRFF900<00<00<00=11( 4((=006**5))5((5((-''Թݛӷ900  zzaXX  ½ԶOFF :--~ww  E<<jbb+!!)  )++++,,+?77իF<<i``kaa 2%%A55  5**ا<11  C99{rr9.. ږ5++ A88װcYY◑ A44QFFLBBMAAMAAMAANBB-   D88MCCG;;F::H<>" ÿF==  """""!㩥  3%%)  ;00ٽyye\\ndd ܢ  MBB-  zrrYPPypp 0$$⽸ &;//  e[[ $yqq[RR  aXX #;// ⌆ H==nee * K@@݌ =11獅K@@ ں f\\épggK??⡜  9--'  NBB' ^SSwnnkcc ) &꜖  '  yyUKK D99I>>䮪  +sjj /##Ⱥ 뵱dZZVJJcZZ9.. ?33 1##4)) 餟 ' ͊  [QQ =11skk_VV  !/$$  H==}uu QGGWMM  -!!;00  𩤤 ڪ?55  %{uucYY $   ڽummC99)$7,,^VV҃{{ VKKXMM C88Ӗ 3''򫥥 riiԝ 6))  ]UUԕ   *YOO𰬬嶲砛銃tkk_VVNBB>336**0""+.!!5**D99`XXрyy :..    "'&"   ://bYY     1'';11 i`` yppӒ   -  aXXJAA # 8,,茄QFF:..  ^UUsjj  ZPP7..K@@  rjjH== C77TJJ PEENDD NCCC77   @33`WW  <00  3&& 9--~vv @55Ꮙ   I==J@@ߔF>>TLL¾ ndd  &強 C77 zqqPEE  - yyaYY   - WNNQFF" ;00wnn   $   !ZPP   NEE6++7**aXX   IAA*E;;誥~xxg__e[[wpp񝘘-## e]]B88ngg   KBB5**  /%%+!! 1&&G>>  QHHVNN-"" 7++cZZ-^  av&:=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<;;;;;;;:::::::99999998888887777776666666655555) PNG  IHDR\rfsRGB8eXIfMM*iD"8s@IDATx}\EW^ @RUt$" ?DTlT)RiҤB ]zKBH!=?ޜwow_^rS眙3II"D @$I$H"D @$I$H"D @$I$H"D @$I$H"D @$I$H"D @$I$H"D @$IvR+{\NlgV3zdh*/U #ϙE TG*(N koo߰k'I w2ҮDOց2G=YVQ)WLh>uGxXc1}ihKqdM#4WJDS~l6l[[ Æ [@j^_JӧS{ UۙD_"Iz1laAu I̺UϩS>ڕ22sCduavp웯q8+IKgggCP\U2q''4uttH$*xzRa 4.X_ <Ǘ: } 6bC[+ *dΖ|Lb5`,sIWczE2ҟqɡ:!i2ZG&:@"P/o7UW@Y& 4[~&*e&%[&quE=qi2Z_&:f xC~'YtO 4}̤-I#$E;8P6~<eTmɠd_Ec[I3. .o*,U[/^l)~_yY'oV:U5eߔl+'ɿr%9 {8QɌ w`wO*O"[$ɿ&?Z֔V2epY*EV PPVK2d /oYu+cur>;g"chٸ ҖjǐX=8;PNDIYJLOIDQǰ QcO™ |* Y'Ia a!Iɣ|>z{E(ꊍ@+1Y\ 8ͰGUIIJ׷d_Œ{Ld$z}G6IU0rc%$ed(;t}B0I$+PQVpIcyPLLr#bO\&U4+t"\fH[In1#cXpM1g9ım?}8 P 'LH)cL@ǎ;8;७>~On11_{Bsd`!CK~zHM@pm57-eOa4b$J *'ɟh@?chUgU_0GvdRTZgR֓*ȝ[0 j3yr,29lkzD֩X(k:DZ/Վ?qu6pq8(]O8ꉲcʸ:q١N@7&vJ}Ϫгx-&$人.I\nѢ ֶ-(TmmMؐ0`@iHnȐOhЇA]ݦn;N.=!nSObG8ЀhۢE<F]FEc-_r8ڊ[١N@&N9PvICD#A{{{~8=zͷS3gNϛ7$gg$sWNc ct!C1cFƏ_;eǏ[o ٵ.6eq6z&?mDsB-+&8iul"qZ l6JC2 xG[QvBu,'NmarK9$<LRsSr'?Bϛ@mh>?γ⇺9PPa1e>l&ÇFj-;[oѽg!i L%&bp~,D%qف([vp%W9#Kb9s怦6b8쒋 z'-aW Njcu]7v}vcAv 0p%7$ zZm[A%A@Cmp|<oQ&?>Nh7V e^^am$ 2B&{^| ϻGyB?I$;*\Fo4 .YnAw߽6tL&m,Td̈́TJ$ zZ7Trxv@F m䛅8&QF=ygcKAG=Qv SO =CQ8C>K7 NaW5b IW+?33sK~ݲgZn]u1GvNsd'7uurZG8n]͖'xF] m;d?>jqN-١N@&NcpTpWe]mib[zaϠSvm}ǶC)XfNTB3uR.nUg5 '2 P|NAN㨇8cZG(;Q8U'Vra3g^p\rE0}BẢ~' \33<쀭ުo?:lː􅓗0IEI0n (XU݉'UL~ǎٓ:f*_pF?k38C[5{*@d^Rs1 jpQ(dDŤG)V]'fKhm7GYXG=c89v,([Qvp1mzV[}N|? >_'t0iSt#_+#^9#'ku NRX=dNϖ.7ੇ|lSSAxm+NQ.>=?ګ\K~!7|CW /70IdNbuDHOP]WыIS>GYXG=c89v,([QvpQy`\;<<[8 B :>Ig 7ꫯ@\'h\LOP]')pL.m'V Q8I$^}nC\ېiYf̃ksϓkqie;{ ۨ u_~M\rU=LH=YuJue I~ Nl?~rIUj.?-+$*o~`oW>>MpI;AsKD!'/ɏ1[ef?N+A)gşױ˟?@{iye{<_! *vIK0KcV[~>wq?)na~Mzmw*O2g]&: <Ř_FivC[ĀnXYhCy8! ͱcy\Fي+նS٠^.a$?GmɤG.={v4u)o3_s(L ,\O?fM;w~%%O%b!; #G^gǎݍDSrNRtKJ?h++I@]@i8ݎA488x%7W@nvߖ?6Ikn|ٟ=ekϾnʔq`ɒt. < RcnРctmw+m;}ꫯ.bMw^ p_AP,8!mر.xlEى•j[AR80⓭;\Z|`wַIökQaO4<HL#*1_Ə_rч6o&؂(,1I2V?qL쨄-88;NVʮZ9:N>\pwߍ7^/>{^+k$aڤ'!=u]G|?\$/6ơ~\Yu)`Kʕ8s.d(w$z]]}Uҷd_aVO*2ЅΆ`ѢE髮b;5JH rˆDCFl'ڶ8vpqvDmp4ppo-z%S[˅'{7HaUe'gov1O>$#w$gxwk0~$&+I@.xې6JOT 3~,^PB՗^ځKJa0F뀑@]0JJeҕXY?\nq$`-QY`>6mZUW]?@ % d*j۴C>N,p(ClF{xc*,/^7 NT%E6Xd1nK^ozܒ,s>I~cTk\c,pErs\E_Xr5겶'dM7 s_Q[InwR,]|'_W:)V|M wSVgNBr'e<_*7:Xsyg+'59?eY>IC${7DV={≧eQ+v0/>c!edp)VaԓRK?9DF8ICbtu *]wl[ď䎿7}7`ν޽fWggGwޯ{3x~:KN$m{j8d}l9[G0y \ жe1ݓ= 0q+2qv Kԣl_N)u^Qo^{''RfO=E?+)c$ܛRA/z 7ORw@;ڶG_QqN N088'Ozq]mj%/{WARe{zΟ?Kl%g{=Cfs-fL7O׉&uu}v?+$t0R{Y57x㭃fzA:G%œi?;rf#r>'ki)ea)t gp4!Tmv]Q Do/8Oehsbc=j$wx4fX¥F>j#<rup+K˭_cXH >9yrgUupD &'CE:b^Oy#Yxz ꊱQ /xzL%)S۞],)6sJ~V|.3^}H3f-;6lcwIMN΋I]f5ׅ$9,cm̙3'˂:yP"2%%}gL"yܼ/Y]~n93y܅I>x! Nҟ|Q8p`vmn?}GŻnj-1cRš)S^sϯ%Ao'-%*?55k8\+`rM>֜[c,?餟⊿X$jQN>vm\?]4_ݹ'kQbS9%_2@Y%~=-^@.DF¦?L~tI}g _.ɏ|T'fy#)a0GB/{gDJkK\!W?͞T{Эtߪqe^>$Kij~?y,=`ƌjq!>:n}vp+sWc!=8Wci2򅥗?`jNnwڊbeOUx{2 S 38 CA{PibУj 38WtױGIkIsOX9% Ff\w-@tJ>jd6'?+MF U1qmR$ @b[˯jkq5a/-C_JH]}2z:sry|XpaUH~HuPJ4 08~rJȜK @:hn^:W'\k湔qO)|{`Ĉ]L 'V8*'Y+v%<ˊ@|棚:|)|s e Aܺ8swWtKUHdsb퉂*EFN-Glƭ% Zֹ̧.9ګfj'6x〦e@$<喾8N::4;FV$nn=i3#Pat< ѓșXgr] 6u;t)&. w0^NY $ACk͹aÆ 5kRV^?<jdA7JN\KCLa~yb~dG&'ۆQ#+ҦnEQf8N2 _Zk[wuDGɰ$~W0rvرy]v[o؈p1(2 N<'k rIGA sD L~ QI e`'^>}e'O~\ρ vu>+o^(| { jn!vG{+o6,<﹚\AݕWѣGudN[AdsphZYyO t(eU=i:.uuLv[gS$oY۽:8}kލw  bM;?'?},|\{qCmkypr0"^I%:h!_6u;SɹCm4% RY%*e)*Qq2: =Plّ#Lj޹"`w{o[uۆ:qNt9 S=|E?~߇'2_ QE^!}9x|^/ f^RJCF6u;tZ&. ~MCh-spD tX4< 8nXb-|;э L[&LX㦛k.huEꂏ>^wM7>@2 8ϣLNN]P EAӔU8d:hR>7v/`EӼHSN[>S֯O]!. BP۶z `@C+VM N;m5j|xl冮گ/se{Cg8%7nLM7]= aCeX+Tj*5AKKKFn{y.w2Wqv ezW+chEAQI8Ntu@:WԱ(o^@6rɿ>|28}oޣ{"YlY0OX@q :0'N;Esmyk!AF1Н/s9a.hW~;:M LyLCː]_&E;ֳ\pw*?"YC?ɯWXA?5n'NNAm,*M7]Oh?qV֔?#-aCD_釨34 lRAbtG uq]j€F!P&MzRJ'1L-"Q%Oɝjsry++뒻ƍ'p\ךku1,+f+%1xEAL`,_7oSr\zy,ר?䳌MYp2 OF^YxtIL~ qOq#`CÆ hϵo֭_-_vml`0ګC8G9|޺o?de>f^O|_1)zF PMFk,̜9s!CɹǙctΰO [~'5L,>J]\"H۪C>ٱ_h ;mGYBas%1Ŗ|VA6DrcY$ 38씒uHBCȵ>dNF`7o,dX^paZFjk됏"_<ˏz;7h_cЦ,C[2KU߸jx|͘1]&Hv'E|h)zqQPeN&pX.=2UmcgeD,_j€ֵ~x5GulC6]\|Çe7ZweѣGfe"QLt M8Ɩ'0*./p"-{9 9àN{Â-25. Y=nl~S6n2?vw}K>Vt K͸m{nzqQPH#.FcP@͛3 v n=`@ь3`~'{$AŸc=Y&VvqYak_ }%mu\TRMvߎie\1;Q>Eg[%[f9EK:owe6Yg~9Ј'P@I{e/vЪ )PǺvX]DPԡxԁo<' AG(V[mӟں:p 5VWvlpGtkLv{wL8c).KyG<쏏C(C>6 \IBw\[o ['sQbc]!NCM89v0tB&Άu_clp?>}̘ m}dgxbRlMoֱm-xil)˘)z؁Ohs8KҩO۱4gGΖ$ZdXۮpM6o ^zAr[a/OKX1Pӵ(tGjCn,Tmc_&Nu_t0PZƧgyF|AF:#M9mN?3q8[ R #NAF//#?" /n6̙WZZZ\ΨU9fzh+N2WG>BzhGrr8}W8~ڢ7uw9?hI u:7x%:Oh^j,L:C۞3t@aAGǧ\ x-7ʙRɻ^sҤ 4P`dcۨ6l1tG ă:rI0߬{ɧ_}z$̙k-Z, S!N}}CN.u9}ykS[n|u ˛orә]wgiȞ8g3Ck; i] 8QGP|n?C'~uG=ġ-?$lrrR9Ǟ8}ǵ-o#FyVg@v„_΋>x_ⶭH:]mPc?x(OG=c1~p]Ev`5Ǵ?]on8y"N#qUI~x9b]Vʄv::-?[yP(wgbXQ%%P&6ꜜ>Ng32@:Ɵ~;9f}&uW {wa!\7徟'm 1#کbtm/f̙3j.Mrc9LlԩqǽM?@9L`:p2Kƅ}b3o-/i5 /<}u3Nno}iV_{嫶/j79 1#-ږ;;8kګ־ܤuBRɓ}qkJɇIQ dyO5sP@uMySg@뾎R2|7_|lwRE]j݁娒 Z[x9 V(q8C^p:fqc -!y|I~!}u eoŗ~nE>2.GT|FgX>A~ѣd>jK,̜v/^dI^5򌵆Vm8{9m N~N hch:dP+5!YvkKD%[+?jDkl 0P&n +ᇟh萷QHrGqM838L8Ν}iӦJQjoٛ8{opGȇ<WT#g,"ʆojj~\nH]6]p#a.0¦Po< r$1Ts;UmB>i:_NiC^J~ [w/_8PSyjC.lo<Mg'| o5`ʔ?h ɭ&m38N$)|g+*I\j\яN_.HN} }F=*@&@o9Ay~Do0ҁSpW^yMZ:|Q4((U_ŒN Pnw҃4ޱ",]{cbt:|Is =ݩ{bP&S۽;˘c!c8..#8jIewйs?%-W7f>xNa<R8a:`NqÞҋg}v9 h 6(ѯ&J妕@^o|C^jFX-{ WYkY<Gx̷ggγB0<#F/d]Hb>Qi8?_"xZÊ =9眷楗^9DS~u|cuq@G E#Ri 2Vdr(p3DC]GBm6IO=%9^ѱѯ^H~bniAm^m2 `9{Y rY~r>K_R6xfϞ#h\ DEY1#ǡ tȕԵ8 ~7{?FrǤ;S1PG[*jLyI9dc~W^y~zg'^U^(8۾(s?^kƌYieHq@ێ= \j1w9?1jY ^xaJ\I&{}HtDtc>iyz : c^`IK9j噹F'#*$tII"sG(Dd/ ^l` A$r8֖O93 ִ<߰t>Ѧ}jYX_7Lq~b 7f:0^qpx;%OɋIQ]ͩF\[^Nx8mLW^7xF us0[5DNƖ|x1$1ɔ϶v{5ONpz#`3'Wv˃'x@0bPG7@~pN>X!'ww,XnmmK@,HMhG90E|P1t?a *-mΙ3'~\zUiK  mU0GSB!dJ)x&.1 k{C};%Ⱥ$? 11unԠ!ݵ8 ..HT\%op a<5JzGRjdjNye ttnۘԩ?=qKI6o` 84ƘZ3ry/r ;wf>6!Tn`y߲AȲ5(AJS ~8 _![~oz;WpGx{'!j"j cĈ5bZzA 3 ~9i%M?_()%{sq| <<'kxtd;>` ԯ D>T#T%qq&]== qu>/Æ SwEGT/zW=AJ *)_)[zL>fb-7t({O?\jPjJ?y)<3 r7I_bA}˓{)A>Ck_)ܶ$- |Y՜cߴOBY$,ck'TUvڃ!CwsO?D:}vC@wl%D0\DQta@P#=(PK:Aǒ%ͩw%m? +-;c(ǧzG˝Y?}/~%#J~Od 1 \_M~ۛV]u\SD>5ZtI]'j:sG袞(;̙aYzɒŲRŝ{d,`O.\$yeb66Nҋw n1֔%Բr%v[lƭ2;}}!z֗}ųܺ4G%xuN0IA~-Rعk%-e TpBFo 8yie~x'wp>l~^ǟыLpGJ$&%4V wי#8N (>Z XzJ*a6ʱQopS K-^$-s%\dtį%KZdID#nj1֤GA0Zi\I~Ujkhh P5r^soRD_.n;؁|54F^FogtsBrM cqg@(JS嚳wWXT4U[pt?%t7lr( 's<x]ИD̄qyx#G6 OƝ2O픛0JՕ`Z[k$8J%?d: [3pn\9'|^v (o걐,F ѝ y |2g= 1VB;+wK?>^*|(+TG !.i$  cKi {m4r7U~gsxYWso쪿kvսɢaL6 ]d9l hS-*6[YI9ٻ?}7pUK~P_Vm ?S+#U(:̥֍b ՃD}0iNйce+u|ͩÖlۚ+#̛77裏VWglz\#O=[I+_?9y;.yIK' u0yBYƖP˒GATWĖ_)8l-VD0~ @_,r3˫e&Ûv,2=d|x3#UG ^{Sa02Ƅ:i-I$uWp/=U[@;㯕_64XߗAt 8#6bU-Ǐ 2;G1iLzBM:cL2CU[dlvr pἴ<3<@\ _̙y!ewu&Qyq?y/{2٠赐mץq\6l%{Ub׊=̆ܶnՌ~`1ym1k9&|#$.ĠڀԲ(Z7e9pv ykZ>nܘޢA>)LB-$0n09r|??gSƭ5aºEvkco7: {k-Z"׾POt{mRiа f冪]Ж,N;-kZc.t*!D\_H~ҫU{K0h:NdueW=瞻<}QjgΜ9rd ڛ}--9V<7~"CzyǬY3k~_ƌ؈zה9#e/[vtfmDL,]( TbYWZh([;;n>hl?2̙L<^>ժ'&{CApIg䒿5+%  ~O&XhazѢd^Y=A= 甆2%?B"6ҁ?KԳ4Rum"qǶ 7@vգ.B3O`^BuuoǦ?OCq?h0A:z+쳇;X哟{}V`$&U:z O]LP֖1ꬆv򺍺o8y?qNs rlv++s0u̟tyS~׻7XnU+GkD/甆6:ιCiԡ Ȝ7c~$=b: K5g `{9@)^=p- ":8 (lvuֺA"u]u\3eOL=Cd㼀h] &|⼔_xwAzW0z;SbH<9O|!4P G)(&4)<u>St̩s,n-?'l묳v;-z[0!2 5j?BX:@+I_|YN8b~c7هmm^;4l&i#b'&S.я\=٭+BeC'Pӌ#_ H1z8ԕOx~?u= 첫 Bvw% HBUڭڤ/o'993Ì6d(N{6mL0V[mTf!ڮ;s'&|e@}1?Vi7i<@Aquul1(!NTcpzNlv]||キN?G-XMF ;ﰵCʡP (~tq>˟3@rg38m:d!3gb1Fzaq&uBY7?lyH`}_HM3R%o1P)P  b22p"q\Sډz-7gd:tegg \޾6m)&0G|^>9;mZ3z#:`Ԩqr|Km 0R~@>ސl}vYf_{e#f؛I?prj ܚtbSIN:Uj:u4[L@{%:h!۸ew޼<3ʦ;WoAyTA f 6X} &tn7)QFu+Z-r(`^zˮ*n7wb}O{۶<}6x̙2þ{gw>ژy4MBY7?m q p@U]f m@{YI(䗓ou?i#^}#uAytMvQu9-k;v-v(- \uuM_3V즂[nz7y@gd7}!BۣLpb5$٦};ߝνNu=㌟L}0`v-?݇T|#PtR:u4[D1Px[~i2 ˂4Mz~ϐ2$K]] _r˖T: PFNzO~YdsV8k$I~̺:8_tt24P"m1.0J퀁u.,k֖XQ< ^B=p1h ȐGa8-^`A@N`ј;wnntoz뭷D-`̘Q} 7h,V?3r(GV=Mpx-=|RΘI"*9.?2ЛY.O5mn' GLt!Դz>'`V[mfN^L? c!!DJL4NX6e8-D007JF44&.ҙث롲AS0ǁ< ۨ4l` :}O ?rv+f(^?3*mÁ488 i`r9--0iҳrQ^"LWWd>C, upG!C6rS/~ uXA0LAbI0@Zާ6t24W"[ R  Kwϥ 6T!UaXTUд99!6q8>[ R 8!m ;)y_j+>ĤjKc_#;v|5\6˱|ط([p8ԃJQ&+$q1ΠkѢgʽ ,B-S8/ƍ!t Eb[VdRHwn /#4h:8z2PQMc'*ui^牣ab`/r+ҙM3!@ @ɯ}~]hٵʫˇ>#[[Yڃ 6ln~)yAӶUY'g3E 9 3>" %EOCb )^F z Rn`ӨCA>OZM-<@E @NI&:ǁh  .61Vϖ.8!mqhuzl*7|M; NhYp^ W~M7>|&Fىi죏^' (g<ف:!tJ1NhB[l.7-'tg#G3WҁH=V΀(;Q8auO~2Q8eAEy~|yj軱'D4/c4)yT.Wyhkra N$Q0u6P>Ngc <'M~};Qeo^?'oС]^_(\)_'~GᔍOiC!tJ1ri'ZMc'*[мڦG^렜UMdp>D*tq0=tF(l<೥@/9&?>NhRlC\o\ٟp{C|WDJ>AEQ#h'РtꢼOS0:O%Ƕ@`bx|nICФ8vAͫmsdpZ|l t|0p ʓQ&?>Nh7V(\>EE0>Y@IR qy:#4PdǶ@`bx|nO*Aɣ pԼڦG^rcX ";Cg6aؖ~wݎ .+6qQ}shsܩ>ס|u((U_~AOm0I6hRA) yM'֡h4X.3l:8pmcͣN@N㨇8c:8;e' Wbv@}Pg $n)4ea^4c''i >?:>ͺem1<ڦG^r> }R810c f ]II¶ai#uQ&?>Nh7V(\MahIR /qy:ju(? 4Tl&űGB) yM'֡|vˆUY"Guar@N yȧR:ۨML9v,ىe'  :8S2V'áOB-ON&uNO t|~RuH}u7bxM'֡|'ʱ=Du!i: '>M'۠I1:…>RЖ}^(F>WzY v9LV/KddmǾ; :8;e' qeUفyPP:mH? /%l:z=~2Znx<>M'ZYw |,-cz:nj6Y@o.N9)86H86 z<8!mر.xlEى•jдO}RH? [J$A;y0(8ǧ6b[:4Oh>O xC>AVM(l<೥@/9&?>NhRlkQDJ>ϲP9)I{iʆѡ|u((U׶@`bt4Tl&1*WyhkZΧ ëlb ;m:ǁa8QWzUA5ch`zN49Hqe űG8;F8Ov1;i[^FBIhnxPiPӤ }nO*Ь;Qãmz6eqBs\Fي+v1;i|;^~EBIR /qy:ju(? 4Tl&űGB) yM'֡|9Z{T}tL=y caZtntS'C۔ ͱcyo[눲e' Wm)h~W$-a?BMAv'`mФ8v\#e5р:O>WzNV d0 NѓY`+Ʃd$?cLhu]iCiRgAf@?OmIŶ!uu7?8&P8P<>z6qBsX^gQDJ]h'ߎצ_>n)ק)N;y0(8ǧ6b[:4Oh>O xC>AVMIRrX9>0Qئ71C4+ Fي{kVȐuߎצnB6TB/y4^k9yR @ǧ6b[:4D) hKd&u 2qAU5 1~LF c"$MN} ]ihm]CiRwE<>M'ZYw |ͪK9 8DDB8*GބC@o@ĹAILrV~ެ]ɠ]UVH\㚕 ^Ws͞TJl0/ -s*1ܰG0qS1#/bK:Va}ꔘs%[7rk8pz§ViaXG OVgVvvAz-¯`p/̅Ґ<ƥ->ŤUҙ`ª6:*x/V¨δ¨^[VcW98f:pD5zל"GE\tvZYfr½\/.]ՃA84'P1v:a~J:LJhyO:J}30jF|fz'+>7lpݪW*QVFXzŽ3R+\׬UN ^zߋ KI4f0.oatTJ:ª6:*x/V¨δ¨%cs`Xٙl5xQ{H\؃8[\υ_c&˾}.rY|$e+F_$?ctzJGN0vvw.NoάOz]>ԜGE=gYkp\rV9jٓJmޟ @C\BW=/&l#ntʧq ȯ:%w|#vfkޤ%.Wsjc"58Y9pu5I6\1eM:bG~|-s93;s'.Wsjc"58Y9pu5I6\P..K脊)V^=G?ZIgrt:LSM8JGpW;r;ҋ5`oR^95xQ{ك`duVje׬UNkRg\P..K脊)V^=G?ZIgrt:LSM8JGpW;rl|tJ:$BQ_sTr:lptVje:݃8=rK\e.Л%K輊GPr1쩶: 3JG5pW;Y_-W>:Xqb%o!֨9EXXuvZٹN {\˾1:bbSS.=Vat~ZSbz'zuVy;Xqb%o!֨9EXXu68:+sAߏ g%M4|<U a Khも#LL\1{};NB/LQ UNVW cOQj> ԜGE=GO0~7scw{xoq=~{3/D %MVL\Hbj&[iu:&aaB8Nl9ȁuu_8ŷrkל"GE\;L\{½Y.xuӿOϻ\ E8>_ ƆIJS,\Qx J<-Cw8a+tZNE0ΰQ UNo::VXI[D5kc"V.VCgVv=z,ߧ[{?E/Rs }sEL xZpV:*:SN?aa8Nl9ȁuu_8ŷrkל"GE\;L\{½Y.xuӿo.B}~q~KbuG?2tQAt]t +_uJLdFCr)?9<>*b>zվ{{k4ؤ޻y 9.J}<{1fbq 67I$l#jtػj(:%\ɖXg*ԿG 5ܤsū{Ϟ'P+;W? ~gsXiIw?'>?e_ӧOe~Ƹ|ׅR~8Gy*IٕrVa*WV:#ꔘɖXg]XbM|SFXUaǙt~^8/qne~_U/ocCߎϧkŝcfo~rAI%t:LSM8JGpW;r\C\8؃> 9ū{&R+Y9pu5̪z? @z=zp? v/Oy.0rAo~i< otDO Ck:8Nl9ȁuuU.aXһgSsW=OVgVvvAz-¯` Fo^W(˗/786߉ˤG_HQA}飋x4) FJGepwW T\у 40tp>: 83έ#{k4ؤ޻;}|쏯R/6ŋ@K?):6+n P_=*wѦ^veɪ'UtV+kh0tpD55HQ+ Ml@\{½Y.xuӿo?A_1lv񧁯~e+aⲄbQw9a E kW1#b-V\^94;;H/7UNkx#"?&u:zV9C=j >Cq_އD}՗߼y}!υMDeG)[qsa%Z]x\vSzZ ]{rXGsl2ފށW=Ws,1ca7q;~)4_{35w==============================================================~GQᰍ)IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/app_icon_source.svg000066400000000000000000000053721473106011000244710ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/kiwix/org.kiwix.desktop.x-zim_source.png000066400000000000000000003133521473106011000273220ustar00rootroot00000000000000PNG  IHDR+IDATxy%G}&޷վkAT%Ђ l1`a ^hj͘Kd"}U+޽y3#c{.z>$g,e^x?`b~iX7 KZ#W A0`%H?dy0`R]ZtAa5ʗ=qy4s"Ue@"mhap&i\OMcA g/C%(g8VhYk8;}"ļ@]0ЊC GlKMm Z 87`OORfkAb@L/="@ FѶ"p<%k+ޗ2^YS\N3H1 G-"៹o~tΝ+%?W?xz(bbMe24]MOryz:|yy8r҉ӧO:u'N;r+/Ç#~s=HĀٶ\nuj]lя^cUw@ 1 f?ӿуq3ܷ=N _|D&zϲ㳭MG{/AA{1pe˧uY azrii#SN|_~sϿsO/$@ &ׯs.`I2pI2??)8}^WfE=2zzd9N;'JO/..|O<ǟ{Wyg>O}k׿G/a(`!MpM?7rϑ\:7H0itAd?,?1Z<8;;3'6ms'O<|_zK׏}|tW[1 8Q Fb@L>gƯ}zL!'+At&=v_PyזnZWey{7Y4~^! ӕ.-xϴpy/+zӧyyO|/~O?K1BA } fL(tO9Km#YOt1ToUW "C8[^Z>z^zG~߻o~sG9r).%!l+@ (pğۗ ˫^*0!!_i2}o8s"@e@!Mjs, *v}pg}/|!' @6]I[/{W\k]8J N7N)IsE0ۍ_x!ꝕA-T.8q_x[??'3A tf_qŀ  [ /SLe)7 &}\WO(8Au|wm5UROSc? ^)OȘŽo>y6_|}BmmFzx<7g?~xߟٟ=r#oV D0!.Đ}?\ ̘@ɥ#e&1íҀfqјc-}$&k'0Q#DǏW/ɟw_|,bTa~xDm_o^z%ڎ0 7Cwwp34V59錐;HsZw A^Չ.&^ak mmԀACrb ;R6Ea}C\ "8vC]=ē_/?(,?ݸ!"ܵ@Ije10ׯ"}jWVdʆK/"gJDXZZ'_w8<(BV8N/o\~e6uz{O!:ج1.P>^ IJ53E2 :> k%י@ĉ=c?ŸRPEV1  Mesk}۷ a¯o4Ea"eP͎ioeb+KOtK9G hqqt1eه{?\5dN>\ɟ|5w'O [N!HDfTYgL a%v>T4/-ɮ+;~b)s}|,︹e^GnWՈڽM6^o޷moK/O>ıW^yei1B pښV閻͗ׯ qYuWbDH@X|s5|Abr}M!#纱1@v!Fp8\~ȑ|3oÓ ԩc]Ɗ~hos ޛwq#zXrcW7ȵHEKkhkTc]/|P*QS^= )=o o9r䩧Z,?Wmsk6޴sNqZv5;~%괭6ZDR%4u7`,oO?/(h)b9F|8߸y;U60ڴ_ćJPEr跈Lo`f={n9p}kf^|ᅗg~F 6p6.~;w]D"wkb Ұە@OAh&z@cT lgN/x12;_WW."bv5e8D_,ˊ]PhFU-ک]㠯KrHl zydD内}7p?{?{?8xPBpJ!JLM.X> fth srJ|)bWFCD2̚| 3wY]#~c Y;!z}A뱖0a֋"gff\ptͯs96Ǹ%`I ͭ˯ݣѺ&&? C#oWՠR|:$01 Du%;udQpL@}aӒS(rЂ,B%Iovn.o|/CeAu -. .RHgͲlk?z"0M+ҤhZoϻ ljCb^@a3pc(@ix{lgBe+'cb 'KYJ*jGW:@j5?,Dq|V$p~ӟ}[zLnvP>mg,CoX1oJ_~ݮ]n@O@38o7Lʛʓ>µN2LJ o|5Cq&p#SmPB{Gaa-)qױ3ԫd| ,N-98 Ff('p:oؿgϞi. 7P`Ǹ g$$1L(mWcy7J. <О<Km8Lm X/"}< fhk 5[F~abY}_ .zȁm'Nזlɗ""6DLOa `|^sno|t-0^afa%U@d t%+ձvj#WNJ:2Dj/Ye1Ж5a9~bxi] 3 t:LkUUf g87s 2:f~~~}{o})_}$y):G@W;&@fpGW[,k^0 #xNt)wW/L]F u(`c-8=ؠ\4r\ܨ Hii9TPN=Z0Y\pkv?JϝRXUHDs`@@-+eA3-Wb5%I ƌAP#7d$)$d`eR tL؄fi^aaó @"Aݻa`ټke_Mjf>/*çҠv.r*)9$\k}l#X4@ZBN_2"'t  nZ vܹW_s͆#GTÓ[]FWu]լ2(5> =fUW@̰)t$l3ljyV0?`e ^xYe1v%h\밑sqIĄdeڤk6{wǣ@l܀zսؤ,i啶 fviI,l3`_⋒篝3SgVLU%27%^U׬y zٵU-`tNNڵ]?uyԧ0}DYbo.dH`C 6 meoPV]FWu]լkK޶j3g ?IrnoI]/d%4ں€GW2~MeVЕqDP؇,||*D+ہ@ m}"KB Қ:..P#gf{9׾<Ǐ?iZ Z ` y3B5sy7WW]@.N5Vnv^$+ 袶sϻMѢ@%dE#+ jUV v#rq!Iع5_3?Oc{E\ yѦ;w?ۣO3kiH:`XC; "4yQmrYIDIMG gpLK,+r#>gRD4t7|S(Fv?}N)T7fInPp_gO}xAAUv~wa CV71IJ ^qMapL7Vi BZW.`>rȺN(M-8o<4_a e&Մ&IuhM}l~OK3Avަ?G@n(@g!9>'FA,"fLvut,udjqzO\hnB=%|٧.ժNW31_OU{; 4z?%I)XuN g$ȶA/oz?g쟾 g2Ybp+M8mxSHXQv鐲їIVMiuL;r i"4 H(ՂlK <ЌT7FЧz_3xO|z4BBhTh6|52Dƙg,2_ݧql @0YdN~[pGwX"۹}>؜ذME9H>@{Re@a P.WmȿxoIRҘz oG× `(8q89]㓺͑uprq2 ێ;Y%\s_{g^o?O{S>>WtPv|ѲsD6Nڿ"^"\ѢDi"TIM +Ozڂ@FȪ>,!$̆hPvAIo}5t v@:Нnd6!&P$ZC=›n?l7 Ib5$ AٖzDY kr"vH,׃ ;v,s/ o孳Z5] <^x$e76JzIi6Nڿ2^2\٢di21"Q.1šr- \o/S&K 5I7HUܭtXpޗD(cUcddؽú^цjϑ7K)E^ojmm_?S"ҝ:УLmOƺGE'3z}-d2`_n{6,l)UEc&`laR#|RE/I}ܷ?:l#˘`H"E]H$iϙs p!ڔ[PK$,9{L&D? V#aǎM7W~_[L"H!!*uTS2VaWx}enz4FVcɸh2$T:@\Pp{2ʴVHқ>ud0.R LI. 'O9*/xk{={v=:dVi"z.0rn;n@O{VU༮&)n#e4k/kox93.}< j«lhu"A8+m:`b`$̨)Fh] :cfF q tu a!AO>4®]]{kW^90li/`RT`L-u&sZ'SmwjIv;]4qe"m$unV&gAJt-Hʭ B@L+KBթVFpMDiUa;y2-mv?b0^N )T [UWu9fpW\f9pE1 z1,:UcKKK:ÆQdF:t'{ed3ۡLf P=򊘝7Wlpeiz]!W(8 u[}-e'Hi]I}]a+fPt3#+ӾN o FiĒ@|HaЇWYP;~>3~+F14~\ m_ 2[ C2i5mj] D0"ߧf_./s`vvV-ܹk|<{2@Qпװ gkZ (*d?5C^ LK +Xpi1:K%K}y$d]-qHAHIY2NS-,@ ':@(W$0$(0VM}HZFe @7 K0 *3uN/.. Ym۶U3wۤ8B)Zױո0p2\ 8M"& e888wyvLSI0l(Oj$ۿ~onmW߿ÇD @5&7n fRL @yXl`*vd=.XH2 p_+dFO1uFlPQDp˗l@A[=(^f?SW@+vDBrannN-[ܻw_|C-EۮI tq=i~/C>q>_K^Ƕo!.*$æ1l`oNND]1&܅Yr>:فyܴ(q]Dl^%wX/t>vP;QN_" <0'Hb}a{; Z eJ=N2w `"[1t}P4I5̃ej0\ ôw P`EአJQ,]`Sy{2?ZH>NN?v\Ή۷ל]ػo#֟'K! yX:Ǵ->7 R-r>vSi+2M:* >|[=2*?k`0= FD&2C\uz5.o!lF_8ߣG Ct@FRdۛXsm$΂㾠|s@HG  GFo޼ye]ԩ{E-yOHM&o*ze@AZA L1Z` 4SR㉆Pzl}YEf[ pQ+ LTtگU[PQ9|[b i\_-F6†Jlrť^-Mx- w~@-4}* YI,J2-]Z8IbX߾dZ+Ԣ0Wu0,@e& lZ~~\RZ 0hR;#tAe"tAe&U"/$m޼銋/xW{/v/ II_ZuWšWqRj%kKA_(IgyX(ŵ7S!WT+}R`D/7w_67SĞ m`W*zzaHGiK `Y0~W7}#iӦ.] O}|AԖLN}>sbsy1"?zv7g]/T&ҶBmkIoo܎@-UI8`J1 {KURgtJy74}}|9Vk˳@s %4B'^eV OKzB-$qk`2@h/Ձ,^dTe xtnaÆ~.EiӦK.slrk_,UŘqR#n'Jf[6+m?9gw-+m>S©s3EL`ٳ^{"s4 6aSGJv \2RepY2s J&*,@Z"M]@Te+xHhvT%@Su16D?A+;vl~2&T?B}:wQ$Kc0zZ\Zǎ7ls+@6y y[ou0;;{+}Gے(2$@i&gu?MܧzMLFog!$ eEaPᤐ8QΜP&$%_h{⡋T\Sgh1dA%p`{S)78hY^ Tȥth/-R/LK:P9bM)$IO)7Ǐ#G"`  y9]?K}G4!d4Eg[F i[A}y&XU*s2-"-'ٸC )go#w] g$*D~Ϸ%Ee/Y>֫uyB'450 w*{W&5@X;2ĉ+@Q½gt]oz;1|KJ"A>} JSGHwR k%Z&=#5W lo8 ($`,}1UlE ^$L(llfФ'?z/b".%:~@FM'O]1^ ,2vy[?zwĨͣmFԱt|`^J7-` h$&J5ʹTۤ-7L%<HWjJ׮ :#9mL=zF-F[.Ew^j?|Ӭ^> w*d!+S~d<k,81Ea`I~ U+2K?RElۯ}ˏ#wɟJzg9爒[ N.9Ai"Kk68ĺlHSOjpNNCB@v&9; B"^_OS^ &RnIDpѢ-D~SN@}zXPX lۺms]?3 "@ !N{:7tݺnSVo\'%67nā:WIF]|FL#eoXgȿ9 "V.Ok]ATX V 4u@:9gSܿpHzib$װ+cSY ^gH~־G'NT%CBu˖{=쎖"A] ٍ%ߤ[ٽEaI*w%6[uݦΝdt=.an4#>1IfjyjU|Oլ~M0d^w>5^RG/X qeِU +HXY);*—)kZ=\&) AB0...` 6nXdFpffvfۮݻko-*/+d ٽ3K`}CAENx+o鴷FIJ*ۭHuF$3[jT| - P',RO('n1iGumI' ]S1[<Y7AI+aX$'O >s!@8Yٙv{5^k:q)ox}:Hs+3񯲵{MAl*t*|RS@eU_oSvJ@_Y&w9,}GbdIO=,176rJIgm8/5{ohe 4q6A1"Ku'I*S$+a q}7L-d#,-`@& 6s׽;K.iCZ`Ն/b*S`C4B@2+Нּm_PV̇ l|BT@f [)\DE5㋁a?iʻrŔ.%#>򲘝 f aΝW^s54r[@+C[OY=8%fXRթ; "-j~/Z4÷y9PG Jj!sr#zo \Li^ <ۧl@V~ "S^7m+zg p—K2BXN7e/k xr)#.G , cs1!F0hed;xe7s \.dH:m G~Җ e,̂O@>3V jx}^onǎ_uO=y':>=lh  'سg y[qM$1ө%/ºif}Ao:5m wSikML cH"Ǩ\kSG72Y1T5t?!^(e`ò1!]CqED#_Ohd$:nB2ğZ=e70+:k[ŗ wR9RWa'Hng]ӧظq2FNIқݺmە=cJ@Aڢ. jILsSeICm<m~.(ܡ<}v{i=6'ie[6;f$m^\|mƑ͑#vdv/Lsľ seHd9LVXTk.%m8gJw=̺)L۔}MJmM54͸k*dPaLa dn^-X/i~Фi3JE9ʎ(W+ӖO#Ď#EoS]e'us'י"k5E&f@*>0 `|T7orť^m8\~| #?!5b]b,]X$Fo"JHr!otjeAZՏ4QG(`Iu,Ft{<$`q _vzk X1,Iʶگ 2]_33u~emټ劋/x'o4`D"X A@]Lb _&"%UZ].A[6Rz*^ m 80bUINDdfuk<&ZQikI& c!bq2"X%J,/laRH'rM/v>y(jK6D"!rzLDlrZ} p|rj3rlC`_[<16(@A!n'V? *|"?/{%D PHWIP$򒘙)zIRUiG(;@QdӦM^p{6nϋ"&!@iV׵Ŵ,& 9TeOj̩8#ǥ^0A}nCAW"ୣESXr}8^O~e}뿽^"xBR",pb3qKի۱cw߳µh*"%K-ȥ($_VZL$j6g2n~:AK$`fZx2:WUJ>!{s,'} (]Oi4]1?ͳ%Yd"?W޽~nG+Aq(Ly㔭&zSr6mmZ-SfѦ>V-$`p iQK,1 HN l!ѡ|f@;iS΋r4 /+kؕ.*wSG#@IA{|% P$Г{vXnWe.zɋHRZA늒 < uNg dVN.V$)hV%kINvo u 0F"$bFeq@PHT#r>Ԃ*Cz^FbUNz.Wʱ5{R Guݹ{׏o`fv}G{@g t@EWi[J;!/$LDP p]S2a] hj|:,iȆqk2IIƕi~%;iz2_ w~Zpc-:XE)!1\'h<&r5JfM IRd\Ѷs~G;ӶQ6vA&[XD$C!2 LFc{OqN\L NT鐵P s"y0\wr/.j 0,EDK;5"Wv\ׂ-˘tTJ IEq)6BRfI tz;_淼IzЃ@2&1WB7N`^L50 _{2 d,dr2%Kv5OݫұVAy|k%lg4#fI5#Hsϋ%1\^(QyZ8ߏܶ[|-н}1D Ӡ*+p9FWX`XhTTDp&4komڊqiLѹ̕EyT"wv ,zIb[ HY?>q#'h+mmeo}]iƝa @jՊ e+'/^Nʈ^&hWP 8J;JX~Jsgz﬈dݏ$I SlF s]rƓ* ")W^0PjW. )-MJ@߼yů;pwy绷m۶kt@mD1IScQQXvZ7d1MZvAc\kﻟނqV;7w! {Kvk'Y~p 3;Ac;d8Sl[Z?!ī[?!ظi79={Dй!@e}qOcW!"2~{LNYQNKE]`v!""sC7iKIu隠@Uyn^,k5ah:z>ķ_3e%zeL$1.lpu];~w/:wt4D-`m.X PRl 7)sιA?V^FF $ϱ1>ԋ[)#Bퟦ6os^؋a_q ֑ qGSd4= '1&wS w_b] H~&Yg6q"yC9R6eP^&Q+R+s+D^/kW R_Wa6(bDu&;ʔgBn +.J` #aAĶ*Ii?uhE#h(^Mq qt(tPX؈}ຝD/C-4NiѮpŸ H`"K"%[lr߾}=ܡ{X)T5 D:C^.6AA\Bt pwڊaI|Ia*H@ D0Y3mrtNn+evZXrǵ)젆eS†/{ߐ\ZP품8ùlݲu_W^y#D( nw0F1mŖV%R€>VtK :{՘_u<Ӥ\1=ƫi =ہ#mlbok%l_עTlPŒ`XH٭HD,ϋ#SRmO>s<%[{[N8~H"n=u `?\ꋕ7!CVW^QAőbjc{皩ŀVjNX#mX:O߃ZЫ2cX϶,‚3f-Џy-A7m޼.6\^~zBfA@!G ?u =6@dUZ 4DN^ ȯI{ dS=)b+LHDm>\{.D GkQGfFn՝ T[^^ssbƍEO1cEZ'/ۼy_zɎ$=oe@@nܰ1DwZn!شܮ݊ l'د_s91FYrPA "!OWUxUK bǪ.5FbfnNlذH+hہ~LN&2ٴqe^to jK`lX_@$Vj͕{{J2D Ԯm65c[RAqLƭR~qga _{KG`D׫j,~noVZJ0D{lHlڸ .x9[6o> X5 Vk 9Ymt#EM;/ /='=y@#U`)PJ6fJbǃ곲@.v++VHT|Lʈ"S) (9A:m<ˣmfƚ e]#-B\e*OM1fDǙKF0@->UJ&JHPh*(Lx tԾ vIdIK쮭 >5V,dynRr}e>XtSk%(|f(jf3Zػrc,=122-:S9-\h pOA ZRlX.ז\JA!G܏Nzؾ}o|?O|⧓^oQmy235)Cd6 ɂ&3oNR5ٳRa\b5dJkr.(g0]LKZV!#KvS\JfsQȰ}WHJ*^!@| UvWUV8V?s2$?z9'b۶[>tםwR$D_)U`BSGW^m"3ZJ,k# '1"?~8R ɳ1l`s%~Lp fLX!Jڛ}X`8"Y7;l?pm 6wR JCe˖7|ӇΖ"0orfض)2 N"+dumJDH?$l:m[ݞFvtvjMYYk=+YXKbcP3>O"@1Ob/  Mc!ЊD,"vI~3āDlڴ= 6m"@_]8@Bhp]a`ήۀ/cedYWiV@ Њ%#B5#wO&f;&!aBߘs/}v_vie\nn*'liLc{~FTC֕Cz:t^&E@I*%$q7^x 7|zݻ @Xg~ԩhJi>'2^W- Mml7`7e^QpV4OZ?5`{:~bxS}_8 pQ9aCc)}J#i'%?45ḛ;zU:/b@?'X]fT 'j57u2骓6蓋*ʠmҁ6a w!nlo٢XR@uىFH8D3M Rh`Ta췡%Ś hI`:&M8?k^˿[ѩsb ` 0` Xi?e`fE/d+՛m\-k]UU.ܣ+Z%U-f x۟ܝDbWai\g cqURȯ>Ј0]M@c`DfBOmЁD%}7(Z1^7m۶+?c:|'~XL W ! +82 eBcαVv1q#@D"l0 o܄GpҘ,D*Kz)ǴL׮!}d m~ zev{}oo|ѩNYޮX%H}ID1\RM25A>1H1&g^ozWdZL` ŠߧWcǕZp"Wf". 1*`&犙[]oލ/⣇=zTJiq2L<p m@Or~0* o+QIc)&m]gC`Nzo~榋Eo6mQ y>mǔ׫Jb dimsZz-ͪ*كP9\ xw+0 Ǔlq.nN'K= lٲwWl>yģ?#" "o uF-0ڙX.N=bqz;pF̞ SDco:Cޛܶ1 w,yo3fj#8sҿϿWLq^nQb&mcY.4P +[2KΏnQzGPRbem$Yaz剶^' RU}1F ,Rjq-8ġh Gʝ31\[^RzTs('c|d~%b&uC3忸N/9T6"mL`[6in7'h@ e/g~q0¿OcD-pD$LI̲ īyj{a%ep"YA#!aK[BD|:A N6G1l2>'+m|eqnWDij\X%;Tc ­k%Dxv D8SY1aVDWJ1s@ + 'DD/sa:dD5sL*z@e P 0 0RUi>ͲG\=??~sx)`%Iqk'&tͪ,̿mw쮏"^Vq 7X! juZ $K/Txu+eHRHMfOCX6I0;tzHSK~ "J=n^uo/`~n_ߋ" i0BVj=*ұzU4s?HST"z\Ҏ;`{S1 &zH#դ #+x!~n}k |kkg\R?ml> I{iH F{"yczitFQ,DAcS {pvX!֌ P yWIz:yvQ(YroِU;OB&˗$ۄv{Xd^Z"Q+o2KA:荱N"QrJ)QM J_Wsy_7N<` Y pY|/Lv0U'vA;EK)آ:DzP0'~䪁cET BF4&G$5qo1ˤ12եL%c5cXkj@L1"MGV^}{'~b03wWGGے"mr;FIls8zVD9Rj6汴5(d>$C+ifNH潣|>kơpru#̋*5eDSKQZiM-~ ;\zv{}.` b38eqYwpCSn7/ ?TcW^ێ"/Q ]گ]],] +Ll@oW(ltٶi)xJY"Oǖ2%U~.g7((ۯ{ˏ#`_|c-_^`pt)ZPkY] iV-N'IUHj'} 7%C\Pb2 {;t}{:4U }Hqm UO&$U?X1<` mݺ7 '6:}F Kg2_{14IpU\JES ȓMբYv.|Hj.6=i)@B;c[$|_ˆcdEM"m׻I =6Qn"b'fݍЫ `n_~nvvv{K@@o# 1w% RXGZ} 6Wj gϥX 18W3Y[ƍy36,B<4Ex@MUFc kjZSEGM$9 #) `ӦMx݁_;߽q㆝@Ɗ">RE)wRi}3jn&vbWzk\S7u/V&>E"ZdE`t3OI~-E)Pk,bpV8T|@ P&wJ%UaÆn뮻;wE`^K@@pր\74 WR>FlGj7Sxռ+nမq1z 7]:ov*pX?@!Z4WɊN@t1idM f@XN cX{4tUµls"@! )c"†5s;Qt.@&s~[,X{ϕЬ&][vsD9AlƮl"&˱ˬRLzk)+9+*du"eCpA)[pE;[Ei@\V\L-9 Hs^koؿ_/>ot4D-`}#IߏoRέo={\>X$ubX mL.𕷖Tϕjw؇g˸"%]ctIY]cbpTJ8,JY`9˪>rKȇ޷C1v*\6(Wuśd$2|M\3EC;?pᅅy133{Ak#\-NydҨE>~^"E۰cǎ+_|Opz@1= . sjf çR1 \c7"=C=Wg8 84#<Oᯣ:薭Wnj=ǸquWT8}b{Ufw-B ¿oW/0.i(rgI.--_z8uȠ¶UzQO$ ͟”R圗F %l+L~Y"Y,<~‚mfEDAψ);ڗn|LТIeE }%X۷mrUW :3<H"`/|dR/ᢶI+uzL"/˔,1uynn*Z$N{F}Ѿa*3i{M>R)vLyxsZrr5Ql>sc{iP]G-Bۗ)@LV0q֜Q֜wWr-i$|:7i ^U.zT `P/[ %R 2!)pg1ļ/5Ydb|«d\n,4=-:mg2qgbLehP <ةme ;~X<珞m۶+r駟>SO'"@LAY?sT}2HB #?yb MO,fPPYIB%/*bCIvH/ H.qf M|yDsϛi [wrټJ^h\3vW QO8KY.xA==vh $cW"i;-zJ *!kI^ɿ*QVe0`)"Dw伖~w'e L[Mm[ۻwϿc=vT@"@8!m'vh);fUM]j$ŻK޶q`66_/vG6qGq-O -dV3v}Vj̇v낸tA@['~Lڿu Yu'飭cG!]F *#-DxC Bq13K3no laCh9nyMgXd"֭⊍ǎ}?xH@ B`j[GX'P·m{22"$B;#&˙4F1fX7g9`v䅆j#&5Cc[D1_ra/ˉ9-[K>u=+-DD  ڣhIMX63 0k9S!ƷОikWõR_]Tyc[dy0DR^RnYo k ![&>.Ī_ e(L@Աh<Gz(z[6_q%l#?;gTQtUY&X8(Oo 2HAS ]qUydS\3"I@ePJIHR"DFu}|R5aV|ݕJ J/8s?w`vvѾ,C@f "bkv8p^Ppj !Щs0kH?_!x*scMʶ&GDg!`) e.`gh] ~[7 $9AJťa@+Af-ұO,ő$J/3O{9o~WfvhѶT"p#CpR/@kQb JF'@*`0Iwe% z]qc#㍵^[f> ' BM&XT]"#.ǿK҉g"˺u+K5j@^Ls5~ ޽w;33{ 4_+@@?_i!mU?"8ϋd(,Prg w]*@zh|KɹA&VKow^jy4UiXHQe3"@fETfmkڪCT,d[T$y Gvqmo}`>;g݃-;zz93sfμg,,ɚd\k6ח)e&P1`!;QKr+$P`*0calCzXHs^kuk3s~9gk~s,0  1sq:E!"˜S W7CmΆO^$-b8D2#G(5 ]j;=&mJyC ?WLmh~i(FPHx0,KYەS @ٻ7F?4"% W`0 _<,p[m>L"^`%C*!pt5 g{̗5b5(T٪%@G CmkWɚ8.AWpET!SܷPhJ ڶ F?WQUdݫw7~p#Q'N50  10m.:ޚ-r '@&^ ᙉ "=u+H PD]>ㆽ EN1!1v^<+3t@b.c+0"0E")_z MyD]'y_D```0%-/Csm]ϓ(+/l__?z5Ĉ 6a$@ o?}UjyJ"eotIt м_,^>EV-oE zJhJ JuVvr]w}ػwؾ "B `l&ns#[#jocՕ+װ ׬fbiN_ [Rg(.O)9 K CëPmh$@JHF aΤPDRIDJXq]wcݳ{u# g\@`0X`0 &oO%4 "`{fG [@ƀzr{ u`,rL|qewM2ER+F<}Q߉fIy P:@\0uJ@aE0?]O۷z"!`06t(??B0Ab@\jy\(K\,1 ]As՝ :HBHV x߶J" w9.g:Hˠ r/݋\-uIyhooRƀۖ~;z `, L?B{C V|GHԀX,3_=(KLx7.GLBMfg <=K4/LxH:(Vxܘ` zF`#@oSvX!B2,u @)P~}Z hE=z^wt X`0,0 cN(Z{j.S$Kq(|aT#':) hQ *[4Jgfgg &iŒ=r%Y}+PIC{+;!tDE첉6QN*@ HzpRdC}cxzݿ^te$H."Xh69DCO̭f0(=tj["÷rv\]U{1m܆Wqg_oVHX߿"@jklqS=rCRVդ^~Ej}On[ަ^ "d#w޴b@% ;^Zc^a$m1GcVXCBb>W^oI$IK|M<02{y\/ (c "tҬ7@L!:7b۶m{lC"@1)RxBV= q'(=&qnA#c=rS_c"tvmY`0wr?L Mrh}@0M>D bIaGcP}1awdžϷc;Vqs%/~ɶAW!o4`ٌXs6`cǭ>=T5Oڃt_'˲켏Ux g c-!D1c!"H{-Kbl6$Y,TZP?wR}%J;W9R47 Ag6B]8!{Fhm}=W)5z/Uh|)SRoalo2@{^M7|hWo_EQzӞ Ϳ t:d>_!U G\yh 0E Yb(jܧ`sEbuw8K߃PF]o+SDrFϤwmĵjRiYcmɶop+?̝d]og 9bW6=Pn"pIP9n.]}"-p}L&cBU8'lt9UI'qIQIa +C)zBA%2FA4ЈP^ KKM@=5[7g D7T ܄Կ Q?}ڹ7߼,3_}N\sG0G0.;Z ?CnCzKB Ih?=F(cUYGIB"Q| ]!Xh,uM6R$Vx{Eg 6>"#1ѩGd??GEbC1ҫeI+LY@P\@rQdT# ,M Ld&\VCVcu ~RT:DK_B{TN5 "rOv|QRP`+kbXV+x?FCt8wYMTze4ZJ#?_QYaVӂf:`CYaӑJtGa1PE*uӲԯ҉0:Gѧ~X7]J/#  F\ D]"CkɃDDZg^ZvWcO`Q+.*.$G6P.y"~H=ߺsTʘUX˙`{SЊFT:P:;N{ Df$@}ou_L0]=Oο~tJ  Fף0,Jj%$P +> (?#} !Z|Q!Fr)O1τ0t"0HEU, bP!1rHĜH qPA}DQP"#喞P6jpIw2`!I>I{_2Ey oS%kKbF C ^r;&qT2 TqVnKn"иa zvAhƆ}P֤ϿHJs%CX 4<T?%#'OZc)OzG^w[~SgJF +o`0X`0|D:a#a hjHN7kPsu+thjU"8'V A 2MAf{;Q6- t/D:E#:)8tX<-$"~tBA|@Uy7/Ǐ&vԪ|Xd@#=rFėHw{B:ӿ'r#HDo/w/*hbbeV @D b7]_*2#B/4D OX@"[ k 瑭(D J9ƀ+$VEs(@ƀ,@-vIy}Mw}.-?k_w~Z TD  F-E('H~Hޔ{+H $4InADϺv$83e'2͡:Gל S1h*>Ft ya Hsp8 ?Os,0 Olf :ɬ bbDi'W !F%gueQ"adWJ2c,Hq{T !Hgg&97+I?<"Bd f #f/7ANf$UOP$ϹT*dko ZxrBK[!wg%) !pŧC^.!&^mi*WpfsvC"%gt"2=)4f"4Ir"@`v i2TZ| #G{2_,0 ݡ{f`M8'lp?I1[A@fdYF9#̔yȘWhFB }w!wp=Nt[+%RQm!6W49!W!rlV0DB)*sp9=@b :@/-WЩ|trJ"Jh&M{7ãxI#\b`,"$w q}*HaPi۔Y7+01q:Pvkk_4֕rO ЫwVs*|AQI_:1:3{-FX+ow< X)~ 4s}=_ Fh+-B6s]ETe{u{ÿCɢXn6m@%c0`06O .Sr8VAbp[Q޹!E')9pH AwY81>V輥:Tv^͋>:ht{C"%FE7L(stjZ(ebu?{fE`0>{ɦtY~ *?W^-#(]yU3\KKd; ~]M/]eŪ De8Av\ 9['&s7Q-/L$@Ѭ>VQM,HZعrw>лwؾ "B `l݅Xj/Ps'̖c`gl>4Iώ!j.'^/=T~!7/̦ 6h~A B> BFr6"M:@D$08p:^MJ+q_zٽsu X`0,0 :vwKlhz5w": Q!z> AY@'EնbOWKIc'E@0}󻊋'mJg{\H #/m@M_Xw"/ذYE>S^$ضȝwy>c8(HMX`0,0 cc=jcȅV op?L*nf ѮꝄΒ6ud^'4pV􃮹J+099%P" <ͼl&EǜQ\XzV 0Emˇ_?}#GO7"6`06Z#•J֞?C8]=Z!`.R?SԆɫ.cM ^eWf[q p77MHHܳ @+j$3ǏۀO'/Jt6Z@&8omG;v: Ƽ.!/I?w:tNicN⏗ VntL`b/%@:͵iݖ6Z=ˍLꟉcGVai֓:zr>B!F]b6ƙ 1O?%{*Z^Z@yDąq[:9"?̋X}1>%`y'nS'zӷ˜)WmW)`|6Ap_|Q+8g%C B(]!R.9W"h?tf;P7æ *IDW%9U%yuD* Աͽf3J^[,///htD@LDz(d{uǏ-=q쩳g^~0жX`0,0X`0'w,a}"DV}< P:acSȎP9)BvCq(_r4hDF+̦`@%PNYH@?n b-dE,9{T#O fAE]᧍(2Ǐ=g>u/6""c,0 ,0L&s_%mtJYzf3sd%r[cs}!is} ضm  j,CJ@eKB؈.=]SԅThVTѕsϝz%DTun"`4>Fmh@h.~%2+<fKG,`}d8#6mPrsξm@0ü]WJHm.^C#"nG'Es ~^ڎ]|ͻ^z3> =DE1 Ir77bZkCanVs׽, :a.hy\(LC4!ve# 0(we#b|hD1`(@=j1 vyo]噯~y"@.g```l&\}|>_rh/8W%K\?ZnJ%S<'b/2 3F=F̲+I\1M~F"Bb)HQ[ď/v}_0<|"P`0X``0/'>9CJbRAz潺PYwS]T/h4vn  GKMUd<*Б˛%twl"@Ē2x (k<ī\R`m²$ܱcknmOo6EqYWODMUkhoW"d@E!ʥTnBV:V< ,S]"Z%Y3D42"DJ}B(˲B7$l?y7Pƀi6s &>pL+;v;so"S*E13 q#B*KgaA3>0o`6=$;* 2ԧ*Dt^6w챛]^sfDbmRMs_C qιgF ħ@klt 8;?s,0  qyq<4;!?練9DLj[) ?{Z 47l4@;=FѪmrθf&4oKZ"'>(y%lJ$ѿ  :dx$e&8(E%!#ICPZ 0"ľ}~[2 __, `\c{Z}B[Ӗ 9C'pEq!  }TyvV>U@Lls56&sZ\qL%`S>Juwٞ v D[2yuU_;%z y2D;}ScyRNwc#Ik2|!1U!PboS|vYoE1YxK{;7~OP#^=uT"`0X`0 F6r\7W4 ^+ _;B@{a!EM=! .&hqEYȆ?xvu o}졇~x<A  Q2Zj^ - \!,(7.Ԥio]Z^<  `*c*j3\B3@'@#Ƌ{8O{I #(fAh%@0%c4302kow<ߋPKME_פT"@Ν;o> »wؾ "B &bC]DrTIiUrqy^?_z9BUZѭrHL9(Kj/1fu'8S+HyeM"=ܶ_EE+Cp%դ"A 0hVv;v]<ݳ{u# g\@`0X`0 F>k_;}ߐ{_*'/;4  0+w'DylV 8  ,]xƈM,ī[ffwt9LG5)2"6 cOyl߾w~w6`E  ap ) t" #~$#kN7((Q0Vi^Ջ4oyLp<"J6m$7r:e#:M~(DS'@* 6[:\D( 7|6-@Z2\^^>|wϾȑ#_`0qSd!2^n[`J#9-ol {+}H`*$_e%77`WB J'B(~6G[R5cD1OVl ! q xY;mT%=oG^"``0W&5@g+pJmk لؤ6aD rYWwG|/ڈþҐKqI8' :֫D+g H>au =A!N$@Fԟ%t=wӷ~ C-e"B]pmCJ2_)5~>tН Ƃzdpʍ@W ڇ8oYtY%J3XͫT䄛&=TuU$5 Bߗ=*i 1Tb<^o^,"@ Hsx4~!@i'@)qlF-@ HXZ]]=qgϞ<{oO:n S:E<N   !*B|95~wC //7^2>h#6r{}U}617`Wq:as@7>AzBLLj?pR *]@*i XIud6rEGo3Ϝ:s@h7$ ,`\sWo~SؕM@dLzQ!ss7v<#`wIPir>*"htELv&@_ qEw@.0PwCH 1}Vڵz[nY9wܩ<R@,0,0X`D y!z<`u1X }έ~LPgdtNxST-ˇj9O-FіKDvs#!O΍]|M^z_  X`0I!'d!9 >V}j7,\}7 )W&o??R ΥpAI/?>JS\Yy͑nؿto6EĀ`0i-=&s#1`ԶW}hcG!B UGxz(IOS!܍y XqIaU?&xh eM&"SF4OU(@K^JgwQI)1 }+pH3P[,S eQz2AknÇws4>[5}OWXovV$R7(BQ `2Y&'`03sf2 Hԕ~1X:V\C@Uæuu1G:7lǫ勇UY{8GǼd7{s)YM弦ǘMW#"7~>a7*hkTPT\ Gx(oM˲:f>x;S䧾0}*79  `$}x Vc3noöq\f(FEZbNF{7}߀wMuC6~RW^9'*KznvD="+j,F)Cv,+ĺ>mIAseK܈p{:G__{X`0,0 c#mB5y r>:_9A 0y@"127ٷ`V#tQ)BND)S@t??}+Gȟy$&_,U"%)E-(\_l熶fι{{?< .`00$w`0fpT0-7͟]p[`R!fzր'BC q8C'0) y 3YVR*8V "_Wp uT6qs"0sSYh^}^WO_w7'buzR{V"C``0 F M=V* JE I^=s!F]496B%IWNnTP A\m H5..y6W5n0wWfĆ̃k(yT}S2&o!k׉7|w衇~GўD```0 tDK!k:Ä/B5.UUxr:u%~kSv `EZ K/)ȘC(@N4@HFpmQ\_p{ݶ Z_*`ڎE%``Ν|w~?}ώDD```0v!~u?Q3IZ߫<t%pV;@ qP!ӈ^+7}h-\B_ZD= + ':ԋ.t"A6*@Dܹr]w?ݳ{u# \@``0 ƌM ^9+|bXIKJ-S+Kh%I7&|N'.r_\69`#>}*h"&넺O!88H`"ωt۷_?s?c?(HMX`0X`0 }K=S \4ͻu_W{u5!E*k<.Z6f x=4%jS*nU2=C RUٛ7Kp0): (69=H{)`=""mq?|G9<=rFF]pmCJ2̗$~fnx:t'4qYd!w8`-=8_/e9ϲzM9Y~6ѯs}f;=Xoچ V>ٵN;Wuu.~7QB?nq*ehIИ㒆n9~}mS z6φáM_p0F)٭^}};'R"  q _,>:<}J4QnS&p^?&y9 ѱݐeze7o"U~v^E %LW/]?~}&J}:,QEQ)qhԝ(#TM ٧=noGlPH` \q=I+\ϔ6+X^Zb-zm gF 2(E~%+,Qʏ^WFDyU4Dx7 Gg>?}dDA"`09U_Nظ&6B bR'!nvDp=YTef]ɫvCq@(RxDG<{ׯK{UwO5.W 5|^2hCH<J4QmP8)9M$3GppڬPFm5-?&^xt&Jt JXabeeEܹRGDX$@mצ3ZqAuoW?w~MM7LJkuk[l``0 FZ p&X6T\!a.2;0.iȂ>q=yϷh¬#ʅ^(T-FJSh=zKsJ;&/\.K}LYAd{MM; 0]7Te {W@WbP")S },MIy3&wE5mZG&TAwEq`bE-XYWWŮ]Ν;?wV5D |OW0Fès PmNLWj4~+`|| "`0M{&BV.DDڴn~L ӻ1R=}9 4gH| LD/C&L9v!%Zr]ޜGWz5竉^$Fp@#z=&~JUN|!GMlSNʁPMMZiνBk~8 w!#[@ƖN[S 3;N(*Ÿ 76#7yh8ww@6E`02x_1z-HՂ)"4 OD͓-Ih* @ue) M)): F+ӘھD8~֨cS*Pq \ ұz+aI>e_[ҮvzCȤ3(k/ 8(&Ѕ <O+0jz^zI9sF:}רShA`߾*b1 |Kƺ,1RU* 0 믿w Fѧ%  `X?O~ ӷO_k"2  `PHJ)94` TE JE;DPzDVV!p ª5(dެ7dY+" c @%Hm&u|G|@QIR,qjO#<6+R[vPYA@`K5v2)P%t- te'xB>soU:\E +"@wTp-P{j__X`0X`0 cf 8G?2GH';, sJN9tGfZ4 !l#xJ@JssԘ6 ZeCD M#k> ͊//y=k5Fh@x6MϦm` WNe(j!aRJ~ǒa3uB^4#5>cUڽ{U\wukuu6$ԕ'DevDD`]4-qطoo//E@]pmCJ%s^)5~>tН 5` )i;&ʾj&BQ@ ּ8H?cp"@(j/I!-8Q+A]aExIy`IA<#J@c64g\1sۻscW)#DRcmV?O{qާEsͲٿ00mlR꿫96Uiĺ@ x'#>*2/J}ޓ~_i#Xutۥo~s7DyC ,`0z(o, X zmȘ¢ҏs}T`Kѡ@f0{Ĥ.z({Dhsa÷&@p_x ={$$j+x!D\˦^!ZAx9F(zaȺ1,si:>H<ƴAp0d}]wLjF4cȪ4$o>%F "dL 7VwCC}1J `XY7zđ vCCv(B@D4/}J(b0TǿQ ={JXZZ(/; XE[Q"h4ڷ[N?~/g&I_rnl ,0%ԷL-#1\T/ O][?{XP}.֤aP{DGSސ0@W*U6]wۀXjW] !)ݐ}$ p~?:vuI#+HG;T!m"(\^OO-U .=.Vf_תȀRMҲȀ`RU0 vLGួ{=~:viE``#JYǵϕA iS$1ʮ2d5nIHaCtۂ>O, uMȜmvO߫v ׅ#}p<euߓR_ "*^8N@tD@TPQ6#5%HUp7z )f[-߫=x2|ψt :”մMFӈ[punֵ/~O+X`0X``0=q!J88= LT |Fo"]hħ133?e1cce@jl"%ۘ $p2T<_hwU^ /c;# !) N'.A7"eZ2_CAbЄשc G4"AQs3iq…*E@pldI}Wt`sϞ=oK_ҩ .[`!`JDʟͬQ!]lX\(]9 Q'y(^^w}+$ ;iAVKߖ^zȚCz"%(Aoq:z AB~P;FH 8K/]BB@NAk&X 7bM&zKKp* @9~ xꩧ(m۶iBO1t{9q뭷~sЧ:@`UY`0X``0&! lCy4{=8R@uVJ f8ܣ% H($jX&MNdLɾEӧ˯,-o upzw>1EOdsq8)B67$?5 &`?F1`  pJSO?%oU۷B0=pΝo՗_~׾>"d~"qU[' R$u'$ZJo!UX KKTRWVbqbL 6 -I?R9t׮l킱G0N)à"pC!CJE``$7-q?Www=`C++4IpRCqjrE3<#|i{SB7e?KY`0X``0 GD' @t=G[l:]. xZa h6NmXlB}uBe2ȓO%I>Af)??̿ yO},sR9< ܕĽB,RH/0}B ,+#恆:K0u0D<2 ` ekdR O?L@;v#7~./ ,0k1!bw. 8@@ M+ E|/A$HS>  h3o!SdYG<H8 ˣWܟ_Z0eع)! '2 UQO L鲂 m(UrP8k0UD"(z応o?xh8Cu|cǎ_-H ,0 F PbC}iĹ;RMk9ınL" !,g}=.}@ FiwSQЄ5v\#'pdn@މ{|ˆ ?:*+ `@,^wp)3(M` .]T<XZZ9Fuض}]w᝻vҗ# d`aVa0+h&Dsw^@!Jbw5̛ܗZW2!#vDaWq:pSrPXÄX[6]ڟS ^/<ӿ“Z|C (NJUz\ yBmW/_4¶) "Cay P/Wk.UUfmWU۷ɿ'_f,0w`0QZW Bs~Px[ ;4`?J/YH*uq8 ۑկ-\ŏW쪮ߔ19!o@ngfxmb(7 Ȑj\P w9}N=E >Q(  iK~T4 &-=O#T(;'(ڼd 9('@z-kU/~s0(dں(ʢ:"'zRlT6qOx$3 ƂjsaہӏRosUFW!봃_}E۽lƶo^~ކwB) &+mY=_K jBKe 0@p @W?" wSL):;|V`P6Uj/xNCEH4wqŋp4;o߳oᆪǎ_k^a``$I@yð } ܉j=HяTTN!0aB,!H\o8M % pOCKjbOo͐׶ OHB9n,m|nܒ^v*B@ JٮFL?ӥϟ?_ +++dZ{D9g  ɊNhlDžA=`B6A `# s;?s) qMev=$JAx b@RO{ ""PiOďsX‰JOGl܌XP ݓhǶW,('qC+xGN>sY`0X``0޺8x OYnkۨ.Dn:@ALFp[t&*'*`Y`_>gC%r|"+0n#qKP2D\lH[9$@2R u|*Z(?-)O'hN)x,k!J㥋EY8n>sO=""Best eA [*.`"ۖHAqh޵ßl~Wх)D <-'n͔gkdnk\HG _8i.% أ_)P1SY`䶗64>.mʀٯ2`Q-۷mݶ|gO~ߺ0e"ppItUE<S.U2.P{Ceen"Un!߾Ǫy_z^Uv冓{'N ĄԊ>@vۓ~O@w]@`^ }Coe +~H+T~Md..]4^]]=nܳϞzoDeE`0 @"hh@dh"*"Azlq!Y /I[/:$H˲T}NO*p.lW)~P W5YD&(1kD]*r/۫d[ymO(3pg/-ךhP왒袰˿=GuRϠǞZ*e)'C.}=xi3㋍bf'IޞE1d}b  qt].,lDg' tKT7Nym8= *TM%dS |%!h!!)NI@f:UH'ފrl{:t^zE5j-4xmFOW9DD@X`F(Ռ!fnjL*ΎQ/Md.^Gﯲ``0ƧBc3:9?&㢞 0_B@0^]T}EѶX 2+3:|?bɺ (RGE(W-m*DB1Gw>&)aTC ^rB_\IDo=6q储D > `)"x*^s6}|Q*7>ăz~k:_iE:0 +.vu߻~]?}Y`0X`0  ?|0FUHY-5'A/s^D^TMxEwjN2$g>e:!'"̚p΃2)!Ch˸gpdDU(dWCzT0}uL5T}BJ !Cenlg2Z 7uxFy*k!ݢ9fQ Uk=@Oև+++?𶷿};|2@B,0X`0 *b$zE1@E"ZC4 ,KC~N9)Tdhmm\oT~. Ⱥ/R"D%]$4D"0tB#QH`SY}la$ Ë1oV 57ߟ^W^hyz#ߓI` JHM‰7\D`uuַ?_#ob,0 HG:1  jc@MR;?M1_XG=E?'Ns@{DUDJ@rDD}EAtĉ4έz5@zo{=H`EV=XHEm# 8O(t0օ6 /ʣ%+:BMrA)A }G5SZ}HetP@ݻWG˟Snd0X`0 #"_)"x5Jp6=`~#")`6m0 H)qBz >? P6L@zkkg;K+'Hڰ} "K^Aa8NtEbgLJ{IO0*@tQh_:h1BJd`Y:`ڥsmtǗ3EJne``0 "BEJaDy"1b! xLH8wøH>"aDkRFJP V1Im#]oWö:#]eF"] t@\P+8$5R wlʤ#8W}V E@XtqMWJ>F!;9ӟF l-_/夬Brz m.-۷~ܳHW  XTr/<^H ~JP|@c0H@?:GUx@B"1fT;»;n}Bt e 9WcAB3fj/1qx @_d&"NPX]"Y!@5WBX?id`=ոn;t/]>oL7}iP9E]`0Z04+U0U"p{\ ` :s[$Ƭ#sJF .g=Z)D ̡XK*2=Op;! G6F0G}AQؐP :Zk8БCkny/+yW)O̭Cf0s >`b)$W<`^zA]KSaK}DvՏ}g:d4PIw℻GvaoP@1vu>8a9;D"t} pGqQIAFQȂ/ڈO3([ Fu++;WVvl?~fz۾= ) W`0 #,mp˂-vܮ64Dp̜ʳGGc(wlΠ-7Ρpbvbdh*!YBBtwA{ceREܼoETJt f'eIt2/xe9?9% s4!G$W5W~%]0], aFO.{Kϧu)vۿ-XE1e4%]&`&ɤNG ,-o|VO2`0:?+B1?BmX^-] $[Ri ͸8PԺ6M>Tr.)VYRb.-Hg0\wHS.q>3tG}O9Rr UMDY`  MMiUVeUb@u;ʲSDLI}u#M@Yj!V%ƣg{r O76E{0 ڃ^{ƽ;g=o;q]v0~d>:Il(OlS*0 =}X-juFn`s=@0)PGƅ}hېߵƁ"A@t7 HN9F<pA&|i?T/J;@6}CT1e=঩`S 7oL+Rc6LmۖWnwO}htӑ  `3]M*0[rU \(^怴`]K%sc EĀf D.`RnCװ/g\A;LBg MC?)S[=|/wm$K=ҁS@ Qƴh xm߾[n9zhMs cM,0 1q1B>^=J*a';+,Rt@K`2*4?Gq~~c)d4B(Y)M:PG^ @p |? !(E*GH%$Bɕ}ѴDQ͗l]p&[K{p tA_׾}{6&T>"cQ 6"koXPˤ\tNXH"}GSDc=@?@z]~Fjet?|M6˭ŀDOi1% 9 $T{ĜzNutS¦2Jp!o+@51$i=1JYVQDl -.]eRʉ>P7Ƴ>7/ ܴw`0)ۮ)`˓&ĀU0S% .TjV L.BI-,(1]$Œ!1рi _c | :3'D}7r@E A*.@0h//\Mr M@}?2澵&Hb[Z40) {{=O</\|9D%lS@6d,8`0.b(_ȃ6/F:&rE9xQ^S] ;ry|qQֻ/P+@Q` hRg ;{}Y>KJ,l=Rl2XRϊNLf6Dr"2+3ƚ`@2@D3,@lψ,&&&3.6ׯ 4œ~#IjjdC{쫭˒LY1VyAGn׷|ȁ;Oя51 ȿDYnKtyZ>{c@Xuh\uj i1)ۦԌIan2x 7@6QᖂZU1Big$=!uAZBJ7 ?W2ڵtP{AE oGҝ`w |~>ܡnIs0훙U,LG3KKKʻ_l0'F M;`=ѶC~$?B _Xtմ ,sϜ0mkTURu*h`=uDw`gcmNՙ:uiT9j Ӥ Ȫe4)FtfN?-R#R+M[rFW>vY[Q}I ic(4`P&n>vPt(`ݻvu_}cOvk6L;U(j5=NCZuX O [lL ]w(uym{\=:)uѭ{&$ -O)Uv}Cu 9k),)GLVFUL-,DzUOV폯!@B?3N$b&kl47ߝ_m@^/Wht(HG ( ʊ>㏯oe!DSS, Gn?eQ@Z*P\nM+CùK H.w…-sVLo{*[䘚ar+%<5Wc@,:}8`]"EŽ(%ԁ|nYHt`(M)~wߕ)Dx9&"JȊU|Q}Ww'72hKK˃{y?_'v/(ƩB*,A*gLaU`q&߈^L1PKiq43.O&")=" Z*n.;mbb<9i&RmNPtOR3m3'F@I#o!Fe}8.w3+" +M&8"D9_In >{TH V b]5Vas`#%vM~L4\K̀ZpEOz4@\sp)Ƃ5O˨Pe "Bʶ~*Dzv3y7$\`vlQ< O>-|9:/ކC2'ͱAY6xZ |/Sv*@#Q0JP4BQ[v(C[[̓1`  &9'^#o} Y 9@f]S>/[zA.u@6ЂtYUKsLd@VT) 鎋L2B"RP:nȲ,fUP)4-YiK0>-$H|{w߽O PWu`g C`v횸zb}}}Z6,_Ep([?BL+yy>^͹h WnHiyGR)Ԛm'+lUN)ذ0kc]]R6V~n%gfRWE%6/*ߡ2F@i.JV`gkffkJD73LG!pH =S5fXFC\*6}_[nj޽_W.*W>^˗7UqH_fkk[[[Gu~xdmof,c f]HYe[¿ u+(2 %AnW&E$ˎ"(xmU-o/ܑ E stF@[a&a v[Q*h@iA)k>=TDF@Y?io8sCFD j2:A#:n#j"Q |RQLqq>Go<=ῼrGM2d (7&\~}[_)巷>㡆VY8Y~XllMP5?to׋#Sd2[/"dPhn$U4ʋ& \5YPULBc_c 'Eb@xady PW4!У&!4Hr qwMi!# EGdy~%B~$EsmwXϲ2 @Y~LCs5CGdwnf=s7 · @hX9_}0;'ɽe)?_H?7-.LOQ Q:ji2q HijzUE%oUTA ]F )zX}k]O8J Bî3yiVݴ(^7B8n{;y:kVMSRfu*SLkYwXkۘ 7ΑQ` @WEN69c@G<$. PL|TY(E}N3RVٞ (-`dd OJKY}**˸AtY4ֱزrdr_Ύ-$+0qkK)}Jj10."Ra}2eN~Zȥhs&:J Pz&}Rܛ!9Û徲b㎏?Oo^/D_ӘTѫzU_ ^|PS@l=ZG7`ep͊WHf"n5SI (1UĄ՛n)9f l@% \S?S}c@ )CEHfBr?w v߯ជ[++K9GW!4TG R.-X-GޗTgZ-4wc{?5Yע͋6qo'O >PFC^t"`4BOR  ["|z^uk ĊXƊ&Rӫ_ QiK]Q!c8'sʬg<--cƿNc5:vӲO->-*aYдϬĿi8,k%}clXz$A5qСxo + @av6W_,8z8c_ Mo?mPE~qb93gķO Pf@g߇ⷩIPH?5am6x2I\⿴U5::=3W1 l(7r$C~_=bT ǂMy 2}͋Xt'ēOMǖ0kHṮV9MSc8F@JJ<c:}*V)~ Ew #-iy  v=5}1LQbK9EM BJ^8fYP]vOW_d1P0`ltzÒuGN@H[C;V„V$5F@R- H_X8 v b Te(+Du`\HL FI6lA?ʏgO7E`XcpQ}`d:ԩCwz:k™3/f(YT[c@FW9we~4 +'6怸nW&2' SW:P~u l7=TOi&sb8mZ "bmhs~zs͝{\?ߨtwdoo;XS_YowwϞ| V yiY}p67?vLlq3f}SmDo9># 1z22t@Im_$ B˾>~OvU{yBU] XA52#6LsS61W‡\gpsH as+SDDw ̚U Ť71Ɔ~..t(YlSB׼_? 24w:ȧ66> {Ũ@#f9+`th^bQ ebu8upJ&m }n'grF2] dY嬼vmh]!jkLf!Pg) p耚}ziƸpRPEfg^M!iL r{jYI %#=?izCY/E i$H9X&cٳw]/FV }گ?m;HcǏx@|yqg]`To4@H2I[0h,$@=,Y3  *FcF@96k`1GB3UR YnI@άJ 2I)zQݛ"{S3ش vk9/,'>_ؽ{-yV/;s`u?s欸;NΣ>G o R&xzC sȪr!M3fh̷8Jf9 Iɤ`gD98E$($|sbgv-ۚ&`c0Uip@'m'f@MP8E&%`\!g"+9:TJ ?? *)Q[`0lߖr5?!sՃSOpxW}[2Skj*482Y`(EC>G~cM1fq;A?~x^a .S{_-AojL M綠2>H-KrF-BfZD$%jx̣l`"rAPw')vDtkps;Vo>L /^e!"\(@y9g KE?xXieE$@yLB,-/zǝw<;04[54ϝ?8sl8-|{^~ i4IֵC+W+c\׼n"9lr0PCfv"}[ _1@UnɟSfZe4gn G@ϯZ>)ǥ)R"ʂbMv䑏|c˴` p!\zi8etn4\ "NF@XS+("nUWO 0u&\ =6O_(7*> ǓBu٨FYQFmrK#@Xm&MCXN >V_-:IKRP U`"~h@;N ǸW  @w/# ER4 Om] "3?ը|> @2P`l;)/ND(W.d_H @Gv{>#ݨ7#vqQV7bj XMt@%7JXyV*;b_y\E p=|d]D (v.ZAkc T]tqϙ-#cӄ97e֭ѽByw@!S4C(uaFVX:7l $? ܁WaPsf0@,80v;/(v":<[U!;]S}׍aR|&7ZRbRRȩP,hHkAۜaѝ3pݕCI `JO8Aً)rYE9Mozf9zJ)ȳ,/IZ3 02n}jcDp`sq#,ܶsne4dxоw}h [00XSSHy3F,{1B'R61h76!,WC$@S x;]kguP*y\8s,+Q&I(Z/nWF[oW̲A9~v޽{>껶\ 2i 7:/935@(JP 1cf#8Wg7VS)B2paI1ڮS# KEJ'5neI p LH6JZnE]*inkSWZ2{Z1omS0LvDvgpt]n?8pC9~\GpK0Op`Sm舀/ 4sI!7uw"ۙAq\+[ 3saE]aL ݻ7Z( NjAc[S4^?^9WlN$y#mE" Ue,TJGWN.V|4|6z뭇6Q@j[Z3Q}Cxgıo@HMro~~gA ƢR NXݚFҫU{w׽sVIEn1`MqSYWeY?p2kE<#pWHHWbp&=#^,C)FPE#̲W}s{HʈO(*tuuc3g6fVbfli/8?akMh*wqэ*;"\FpEZC!MAۜ"_ `]=՘wN&w'Ҏ<<|Q1@ -3F?GQ,|p! Ωlnyh%oE Ckchi֍/H6GbiG R֊[-^wH{rDp:cj.]t }Q BΠVaUѼwbmi@q̊r 9` d7b׮]ÿ˿tcp'(AO=©X;-@\y9֪SBνDhWiJf8TTaOYXs+&C}U(w'cX[ʊ)g":# eu /@j#dv!HI LY& EX{/!Q]{Cqѡ͢e; SH7~, YGHE<:%3yEV**n`Ε d8z]ؤ Аʝ2$ePܕ!@̀-X2#E8ÎK+N!Dpo߳!R 03ib ]A… 3%ik@G`/ٻG'|P@j<@.rCBm/(ւ®ڟuӦmȫe8-)gUba 2REqcBrANMqY1q"_YuZ;, Fi_9U.u?{ͼN` ѭ>{B2]|HpWIi׀B]Mx ̴CCimBF?n]irFy.v~2sBiZ ~'"DB Q8;@vgǐ 4ϯ|p᪰ʀos`N/|@ N=&6xcYضAP0f"V|pX>D.ѝݤ V{?C@5fg^9@M)_Ua7]o"?fߍRiD@1[]hJN?PJȆ# kYin;x}O>"^G-Ы뛛 .:}:>.|7e߽/L0+L?: g>3p$ 4 5-`'1Z ϴZSt.2̅n4;sIIA=?b]V|n4)YzQ R.98U;B4mK޺~Ũ@b@Џ6`pj}u2]S(Uo,kSXzdtӪY-"k42meuU: `t[T""c-iRrˁ_{]O-Eˇ4`r3gNBtZVRxUju:ciQ\H kfڵ\tU_m%bT[\2YPusjMfFg2bB9O "@so/9M(`8lnn9L.._E`@N>7䥘ͪ !Cb~Xm(H} h@&gP#sI)#Shc2@g o`㤅3c̀" >awD ]/:`訛|p)7F,)?Ev?v|]q?C4- x UYWR/iD@9/ف S *RfsR V2m`%  \^^emmMSR|@?ohBo)uC@c3.D,k)C4T=&hy@v AV ÄȀsK-欔y"O h~"v}#+q( ee_j2,]#7('+n}4l*pF̀tCa VVKӑ'Cjv*% +Biϸ 45@V &4C}-G뮰"yʢJqh]bJdZ:vt@o߾w{{E};} L{[g>sq€5]T&)d((;5OLx}^8;7j 75 hZBEvϪr=i&_# v p]w6guuummmn H0dҥU`7u-U}xf_@p~q;LyA YeKQIM Dۺnv+9;JJw ԀbRh4%,]vEz˙lRoPMLqP~'3x##IPW/8A ~aC} {}_~ >@y_f%z)ګ>;Q+ڵk#7:Jq_G<@WI2F/:5bQzjpG[jWjNt?QTۈɗt6Y!p !ZC\ *SIVO1 %wh".%k;[n{=.1*ULHc.^?n!CO?3(W;O|gjV6O^#-1U{gl+q\u9+ˀ%:|霟*$~u 0:&cHG+xR9L`QѮҚ@%qreye߁wS@\Μ9 a:@{_EXtT|NŅW^ N^I?pf] VϤJmn%ȵo*|!VvCa P3T{(4 f.3 t.ѹKOa ^3MmO{( Wd/C^>wN`M] ̿:QvO/M\K bU %Z<'bT9f JRn$Y!Mq3n@$F0MG\EijlG\K>FOr-x{sOadI @9  n蔀TC p<"@ Lh*dIJ @' y4bCL@;(HI/ZzY0簪@3 B?Ut(#TPEiwiϞw~wfJhlt,(8u4lǹ#&@C9rSRp:]` ZL(Cu *Z~Sk'"J] M_F@(]ظ[AXAX[6)ქ]oϯ_>X@`  ₊ЩdRk7@Ω8u&K5>ч+z'hHʉ?.3&uY|x*~%phdK0ٻG{Lw!X|?v:5@:"ҥ?VK[yXJi\KU] qke75]:Ok 1NSuL(ȍHˠQ ZЋ $~'cjۻg]^|pB̳`q9B;]g~1ouZ@ vdQ:W :i}:|l\+#@mA? pEt=v=T59"_T.@ݽyp˔* #&޽{. |DX g` @관Nuj옺PX@Ӑtz愬/k&HIR4^kAn*{EZ@8e#֨D`-rc.N)Ɇ0C?6O?N\ ,)]w (`E ;\$ D"6Zk(yۡ86\rLQcpFF'טK\ AgϞ;?vpC:`qYqu8hGXu2SPv8!6ԄP?c{ ĠdYVvbϝh:CI#L~sEɨB(Q \Z_#Pe}ڹ@WB o:ºwU[_&&@M __[p bCq򕉚Nfn-V})"4<\z(@+ڦ$6&ʶdҸb7&CGm u"b=2eU! P]ѧ޽J 5up7صkKmD?K<#oߓw G+sz )1 f&@eaȨx6}2.7} l@0XlP1_%yi[fzgoصkׁD `9x- [[P&`Nlm]Qt\i"wziN ] *xk1T/k ѹ>A"x;VAAZHP`Kg[+++{=yQOX3N RǞv+6ᶁd.JTp](Ǎ.M`]~F pƍ;3NYHHf7ÌD]|jJll2b|(uUzF'Nڽ;۷-~]= (`|p3\LW$[h7t eY )}}:۶tu`/&^XEۛuuM!suuCq\dD /9A9a%q8sa(q^7 z" .Ab7Vj+%[݃0H̀F&AU @ @~hn]ʫ0#ߟ$w4TJe1] LN0("&bod.@j_+ ր k,Y7[LĔ|zޫ++nee]ֽ @?'(pOׯR9[~%|pd⑅cWF@8ƒۥcPAc6P"' ;? SpVЎqt; dp@.T.:@%@#@p8{Z <7U3NmRRS1vu?t[">* L?7/~G\x啩ߦMM&UujWN""U_u/~x:S0unb xt RT z 4 ́sQ`fϵkװ=@IL컩i5 HNp,SzK_à"T@ʚ#O7DQ+$e>j)E })z!L_?`18zzN8_̏ŭׁ"wDX91?f}HoHPV[`2}Q˷;ڏ1U`|~͆Cηˏ#tneyeE;1y]Rolly!Vk#@ӷ>:w#N!CcjhĒ,yBi1h:)>1*oZD<`ee PحC%k.L0{67 zxg ~}vĉ|vH}9XۿaB9܍  FLO=>2`@v};# ,ib^ª@?s J`yeyݻo͛n{_Aq@ T8<09rDǹD >M ^qt/³׮cyu'`ڽR j1*eI&Pָc1 teߚn1HYͳ} VWW?GE:~[]`砅?BGh#_̢ `i3O;1s4YV /*sGQEZ.-3]`5]'`f&rs?4h}2 9M p>T?426ϫ *r:@r=w:L0}P0x?nST?} 7º[s B'"I (}~I;JDS56v[%/^ WgI; 0Q\*׽L쇵Wg]N 2jy؝t=Z@J95W1r8c#' (8p`}1 \y}19 MdS-`/12͜)v7!fZ|q,b ! %n,/u߾[ϙ9`f W}15 FBۧ a-*O,Nu^.Uh FBa@ X^Yٳ[F>=o|Blo&C-nc@l5yb+6@2iκNN>cҋ$Raiiwuu0u ('y 6+wמkX\O)S9 탚5R 5f<騈P>sY(w`!2!J leރ,3CV`A?`k1$lY,Lo!߸@۳,Ϩn~OVǍV0gg 1TF?WFΦdL~@! 3?yRlle<:Eaѹo9aջ‘3(p4˓  @1FQ:. vM`+)` _maF7# hގŹ RQ7:ޫ',nY8 zS/@ֈ@z\1 vTy>>Ng 곹/޻qPW͋?m$z=u/tZ ʩ'O( *  F m w}n(C2 υsT2rUQ7"헗v\[-`ـ>|V#i,M0Hfa8#zE*=FL1LT@&1?+n>}3 -Rz A簴[oq  <0@hN_SMFx≹ۼ˕+ =vH!Q6?W'`FY7p5|Ցb\S37K Fwp-Ү=~ l`_ `  D?Om )DCbIE lll^/W,]R@ZTa$)#ЌЊ?]oێ" :t`xfB-WVVVWE`PC6?`N:]tUYGC'<\?Zhc* '+U} >FLݵok&픀 I-"]KjLkHt,۵kـ35UψiuX__:[.7nr~4|x -/c^PFTRާߡ&.C^kS]gp!)׶5;CEOMȠ 2MHPW% [`cX?̝sjN}BX?)PG#=$N8~mܞXvu恻\MO"]ep!ˈY.@Ǒc(uDW\pA^km7Z5NX^^Y"m 0Aܑ"RHgv5Jlܬ֨z%_{t<_;Ms2M#7]3!Ne$Rb#,y!Bí;1d%Hhm4XZ뮻| Ht#9bә,ܙTm焎=8utׯG{,~Bp1拓_o*V'6 tq5vwED;1:-^LIhz]]w}8T):.K>@hb00vW"c<+gΞǎA?`gF&+PF^h=K嫷4`' 4'RLm0``pSukԔs<zP[ Vo;xp?z&H~&?vLpO=Ln/1Y}eʚ## <|?PjGr HgTE[i'v5 1,pM⋰$c8XX[ :00֥v" }3+ħn\@Q]Q &^J F*ą`E Rd` svV[?gA0b,[5 A`UjMȪNZO[@ګ^<,V:@]4"pE4H[vegjY)ܪPF[ʕ @m/Cyl0X{՚Ӏ ` W~R_o~V7F`fy@nYE q^oL@Ydo\C RpiJJ6E Ủ[ּ?5wg<m%0`|Y fwI,i1~33,+xO*KnԸ豵|95׌bBlcFXhz@{@]8J4 W3*𘔀`w>LD2t^nn1uss(m| +A!^7%=ܿ'%5hMߥyP,AύS+dU".-/-ٻgi0]P[ O:ϻs~3꿆O]c#E+[&CUΤW5(#VMQ@f0b{\XH]Cdf,- K  A `yu<$6|ʓM6UH 1Y ݅05^F='DwlvrD! 't|2l0Xn!g`v"׮^ 掋o^l˻zLEa|з>W- hR9)TyRzGF"f@Vk ]< !|)fs,ݻk0݂mJd:O7 D0FWJAj>1:z:W]3'%TRPP1.t D?R&u*YMiN l<0՟szwMp#8E,qL/Z :q4žD]C.=1!U=g>$3K3/ KG0+ܢ$:{]zn EN" )?'i*-UD$@ ' 7@`™3:ޝYwn1RH/tqp$"BAqD4`2@ rU `+mR~X^"CW93q5U|`I3"TH0t ktNR Ke/0]>sɡG͡qPE 6nXcP]@ aq*R2N:]c@/Dnm2shE}M'e@鍿;ަM_+!PsU`{cweH tA @x}s3߅~qCi4k&% $q31m?I` 1'/veCcd`R.;lmm&@0$k&m%tXuAޅ oD pR\&?\+Br`  @h7CY)nZC`b?m蠫к`4Μa^{5 PS7J\c ЮQIm6Џ ҋpsh̼j> 8`rh}7Fǡu`Sy@cb/"KI`nUjHFwS'/hkA_zj0zvdtgޗe  t@mN ɓ D §hZ4nMJ[Ǟ>G;E}|T&h>_ j2.g{f;bca{ Itj{?8/O[F/mU iPgĶ-;q0~"|%}S j+U 朗ϝˍP[9S)7KoGui]#{ͯ`+8+}`>}}k&Ί>,P Z58kC5*c`zkHËM4d('B ; ϋ.M!Pl>n`R * 0+L4j Mj4e`Ģ פ }u}sek<ڿ_@;ylG%/L~0w6YDpaFG@*"+!KiuFAFaWbY2k" *&6V`T@gű*A@Vb !4N 7a6 [9+B~[C骽r^v0fO8 hKP.]?xb{n['g+q9JB҇)3~^:E[5|jH3\sF_,+@M%Z AyF:}zM e ~(@&Ap`kʙFk$YQ_Eܪ<ש'=AG.(rCL0l Hb7&.pܮi(1t fNv-9@)v vToNTs:-('%0`6 )(wQ  5B- Ua`*cFT7m)bw(0vA0 hn N]`_q]W]VT@l?D =FtIĎU~~aW)v*_y] %!R ^IBU߼@w66PxpAg&P p"(x@uY?]A tE55 B_}_p&}&0 _[@LpAXFkThkd5"zqDyh* oncr_"MG1:A:}:#%Xa9-ԀENm+'TS-L 4[sk0:EGH %s@U0-JOQ"l}n1l ܁N&nM]TXt5).383T*/L1`Ç1&ПVZp[JR wS@Hb.nw.2 bnR+a,:%`~Y':v:b) i}5uEsm %NA+@f~MUWP2ɋx^ƀ) H J#.U r sCv c) V pE<%fivD{Jq `E@*oqx00]t4 *Boݧq(-tsM6+\{1'؅ /`iS uR"T΀*m\Z3Q}] ll ::%=n(_=g Qy*Gx$A~? BfC[́f/n!FJNr 0KL [o^} `دM`!t8zښ8Ch.YP-n߶zq.Mqtdl^W-IG#WF!@?yYqٓDdؽb/7r==1!d_9- nt  ك@7/կc2卭=?sϋ_{ᆴ oG=+& C!(͓'NbH3:kOzknu_&g | FM`m#: ] @8qP'OGu+S\k2tVaWD7t / ?roZ3hB&P #(sCͩZ,ɢp`Ƨ6rAGS;贀~R˟j41m|sQ'Nܛ9'"gCjIwy?xj\tavBEnz9ᮂ=W#@sFN^G@Oi0s>(/tmokK/(?3g.hIš(~_ `Rl7$@ KS'^{۝VH2%MZO@u7B<3;C@ OX@U v@U zvqRfiXX= #h ?/^̋hb1! j"n 74ճ'@ @;EsNLkʿ!@f}ku- G.ȝآ.$iQvIPd10&G5f4:~b0>^ _\Dc€>k?1PBZҚtuQ"5 `hU;yD5ߡ"wHOƺLI K+wp+"P0Q[[F]#@=SC? |0-tQ@-T;eMa*IM`@8 бׂ,720 ct,Mͫ ̯ E˗d%ܕo&` @$2!Cd>}ZGXTU3D1ԛyCr2("률vZi^1zEAW@GL8uqto'LZ@&˖T\4 Aփ'V Q0; 9>n̂$p Қ#arQy͇bΘBuT_p&o^8}g[n4ou W p+cG)')[a ϑ:Y͂]#!.Ϥ<d ;h`Zhu4̱sAM/_*=`O(H@^wM G1߉1RZ8*`DOFkk&P:?qwMR0tťR@o'E|FD$PmI!PB vc:gA&׾δ0&WC-N;dd{"-(ȊW8s+`nV;uSFgIdžls7k̵o`W1;K/O}~wiTmpBN!CkXU<6 gmdIo}}mqO#+>/>E1 s^`G#>*ONAn?`_8u֪>/W$Ь>GWFI6}t;&}g)&Aƍ>K(Ws.Ce,yc  NEcwJH̛ >MCoΞq/[vW+tYk@z$J(j<&Fy41<>,#$cB a Tﭷ 0OԴL]7|Ud"-s ꖀIjA4 #C?'!ۭs W@ >`I֨a5(`v2?\}-jA=LSOKlqH{\ {NTVm#T'1 +z+A ,D c^ P^38p~(SbW 穧Xm€n@KXVWvC?ݫFsf`;V1>$ZK[C5rX0Aaj0{ZNmzQ{@Xc8^:mE3m輕11'p0t 㧟A}.z䮁"sK` )ǭ10@f az횿Ӧ4MҴɹc\8qQt{u SC] aNBEiQE'SLх뛛@{4-@&@t՞ |HS f@ &t˭u<8cܜ~!V61p`ã-`ںAHD;'cHGhmU N*Lt<Ӏ$dhxw w557DH"?D?5Z*k׮a 0y̙)iYǦp]ѯٿ+p{]gh8!X|=5B̍im`@]Aϛo^ 5ҝr4uXڹIbU B?A Egq1 P|b^Xō{< w̺sL} k"`Q8wi5iG_rŶ#Խ\!AFTGfeNcQnvutz^7/^l#ݮv&N:sl;B\Uqy0|]]=#RŋHhWpR09ز/=YWTo"cR $>X0h=GStA+i^VܿYOehe8oB&6v(A+a/A z1Wa܇sk ĎU8#dn0`TCLHo]׶"_MoK#Bߣ0@٭f&ǎkt%Vu `\6|]v IK`tC]0`2T-$QThAW 89ž1lyƀnf%y&6&&=ןza'4 mw5Ap HDCϢL<`@*@y0@c=2.ͭјOGfJOB06vѶ9UD6"m)v(YH[jR"]tKbk X*@\DɊ*Z,. ˕)d RSEK4jfxp7y`BE?}~3}`Zc3>=m<~_?s+?w!j& 'O NQW|0ͷ ['A/LeEJ^>ߞ9s_~~x۽4ӧ:R ^Kw6E]pzF?[:S<Ѣ_vsCtXk26'!sy^ډVnQD1[zGM{a bJ@lL[%؝P %hXau\){R6(ohG_bDڍRFlly){5$U6 BHTGtDov_ruL8rU׈m3_዗GMحj}'!mcssEhX!b `VP+ *v뾊 L׮ @t[~VP_h}]ӝLMS-V#5ႀ`xY{^٢ͲK.Vc_g8cs3")MO)d3=A )%c6}Ejin Wj]>tó'|zh3-_w{E-P/e*Uho~b(`&>MׯE^7@"h'gbBv<ty Ε>tCԲ^ =cjea~3{B ){}hycϦ6Ԛ2 FVXmtCC3Cw}9 ]d@43p2@U K.VzpW = @ ˧d } !s[QքjenUr劋 t%4E\v;5*tomoۦQAJn}oVW?6;%Dy}e%[^Zrl%hG f<=m<~_?sXqcU$/.c[yqo9AO)"9eӓǝ-T3goڏO_vϕn&[Ɖ8/O /_y䡇0V~VW<EMɌxAxʮ=qE"+56|'8)agwW:Fq-ceqC+r5ۮvϻ `R'F{]R0`|3*GUWeAF81_YMA!W\q*(-ߦ}l@]NJ}ne~mQjI=~Z)*_M׮^- `} 投 ?}.]-V8qՏJyk]NP]qUmN8̵aDdoxEm*ᴚ0軮X)x!jیKIHTӭ[97u^@0"b@6|k{CY`Tը"ڢXEXjZ^Zm hz[}؏:ҮMl+2= P5I^?ʢ  x@Sk(p*\NqwD~u\S3c[D X6sq7eq5zjqw@Ej@V^.ZE:Dh@R] ]2*a}PQ=iy:㞝NemﱢJfTߨui (Mn{/S Hv('wj^lu-EgDMH9my)@WGV.$T5;;[yn)Gwl T֥?fyiɅbe qg#5A@bw^;k`ՕЍR`#o~䂁n=u*b @㣚^H?v/d %{Ol:Ɵ{[ m)U-k\vä+Yb7QM>nTްaQߺk ԩ؍91$l `q*.{^^^^RRy[;w.MgD}T-);5}Gn:p㯿_:*6 OQ[h`e ճ"T\Q[ؽ^k{MStF4m֩*B)I *<@UM &a@4F=5*vgggP@@0a=,=i)$pD{a 4V+ɋ:)Iܴ @H3TFWDtG)s*R4W m1 {V즸&-b6(*FY_PrMҜ8@@*1 ŞMN ru[^H `gws$ $Ku+vϥ9Nl甄ү9Tb@mu+v/ZuDp͓nn HLALF.b](Nκ&7J罿c6_=鷭YP"i[n@H(f hn0h@ݸ&) Ms )4ޞk)׭MrBts,׭Mq@lڲ R9}.R b75I5bcscTG)¨4^=kU(`c,mj[b7ֈlio8)Iؘ.%aTyQ;.bS M4{B@hBywRFgĴ (@FW )mmmuN˭VTK[r:GhfVm8at\_Y{):JR%R=) uJ_LO$*u? 'vMxOM* G=1NCqm%@uEaWJY.[ Iu? Ֆ88FXY9 tC .vu:5AESR=1Nm* ?۾f%Psi֩=ELjXt ?f3g;av-:_LB1 }[z]uyō 9؆ jVvlϖ<(. ;Zg ѵ3k%@0V> B3gf,.*aU@Ab,ŞNU+W~ޙf7@@>[ͱ{?n!BCgҜ=nj]n-' 6pJ#OpNX[ DaWs\_Y}׮ `div~ͱQ_,U {O`n;U bx ReGt `JB(?l?V3\p1;yev0̍U i삳A_sN1pq;W~^j튀=N$2pHW1ɓǕȣ!JuܔUA@l SM7CL@cb@ M]qrA@Ԁqm?oպ8>;Qფ!Abƅm3V{AZ4NMbu6&䛝&OOW&M4e9ic;&l~a~b_vatM S#I6qk}oVW?r!f%hG f<=m<~_?si(xmwg3؍=yş!.À].@5}={/ۿ{Y{=o=^o\fP8=VcNaL!iQ0-/-eO1[^^6F+OG+"u{ N| B2v!x>E=D!@ccz7HuZced(0DL/Z@R ϱO(۸bK+o'x ͝[eLq<xʊ Cqtst8B[MAP_qģD vYؘ0=q`ԏ;(k@ 6("%w?s@0"i~8u*̢c<ʩ"i9^"4ZZ7{ԏDm1 jq/@0FO`667;?ﲋX}HA$ 8"0VG -(GtpcEhaOopOp%t&#b%ivA@~z ࠀ Xq}H+3 (W~^{ߋ»J Fq?D@t4N% GU `U{?(K0*7_`$U~{QQ,~ع79}@Zђ]E1vR0i1`~~>[y3[[)( ߞ={_~~x۽]/{*Ū{UXv`3E'vތ4TYܯsu&/ , @lVUnG@3@ A@7vX*? @h~}%]|Q`1i{f[[0/xĉo~y`ꂀP(#P1J@_/ wG1AbrLh_mk7ofkk7+{?T;??yVS/&G˭VHӝ#q `cC `bnpҎvT!=ylyyiA*$ 奥A8/\` <~sc @@UZA@ @q|gsss#|AB+ A@!x:}j-uCy @q`$2X s?vX1K@]E@L @@ @  p @ @ @  @ @@ J3e{3.y54@@ @@ @  @  HK$mooe_}U#eǏ$珯sX_~({ѡ>Dž ksԩ쭷NK-,* ²gt̙l-V>…Qmj,( 06Quy qBCպ*O oΝѣG#46嗏 iK]\\l} `kK?j1m}}G ;^tJm/r cQyb_/:O1XLa {Bf w_m@5Ҳ xUL(*'hTe(yg@пX/j? )CbT Ue0Q^rl )~? v*QF@y)ݻWx_6|+#$QvBh_-1q\| quu^t9{S.bl;6 ƍBC.b _`lFe?Ue0iv0%jq/--kNL("(B? p)_Dg$4( ;zxf{r_A@ݸQN.]j ( yN?;wֳGqǏ>C"#o!w_ v{e䏋"/m3"W?(t@ }Ք~ b_/2…Vy+*0h5r[j*kPCq_'V XqP9пECj`yT@ "s3Yb_/"&)FƵ B"vJ.LNaW??myDǁc!.2J` bvhu@ XпK.gouEbQNG?Hƍ yܛ om@@ܹ=zh䏋V ؘX?Pv޿q1oiiп8C41bz}:E10`Ѳ_~ QjW_uӢuh^=@TڸQ{ =k@Pq@M? j"V_{Bſ5 FuL$?:玹tԩ^t!ھ>…n߷DU.njKlGp? yy{x|w`}:{˯ۏO_vϕn&[@ @ @ K@=G T"6~; r~S#`^/5;8'z .̌yx+0>pE_Cy'^sy ?9ߓF<eY${333  =}m'!xvOH@{Y֣.L7xR@پ`þaNv豙̐ǑG_=d}޺(^Ojxm?{󾽏ABl\F|b3<ۋ'Gh??ʞ/5(3~+_?tmfN}^v ; Qy&8tP@] ~E `>@1` Wϟ{i  }Wy? y *-$o^}o xRi F ^u3P}7o?RQ[G@Bh ](9-lf̀_>0i)G)r|.>#S\ˀ.i*G~=(H# pДPU W3OoW#.AS` Eu (GGiX'?%0*P#(]j IENDB`kiwix-desktop-2.4.1/resources/icons/kiwix/scalable/000077500000000000000000000000001473106011000223375ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/kiwix/scalable/kiwix-desktop.svg000066400000000000000000000034201473106011000256610ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/menu.svg000077500000000000000000000004121473106011000211230ustar00rootroot00000000000000icon / menukiwix-desktop-2.4.1/resources/icons/minimize.svg000077500000000000000000000003111473106011000217760ustar00rootroot00000000000000icon / minimizekiwix-desktop-2.4.1/resources/icons/more-vertical.svg000066400000000000000000000004521473106011000227310ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/more.svg000077500000000000000000000004141473106011000211230ustar00rootroot00000000000000icon / more 2kiwix-desktop-2.4.1/resources/icons/new-tab-icon.svg000066400000000000000000000011421473106011000224400ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/icons/open-file.svg000066400000000000000000000023231473106011000220350ustar00rootroot00000000000000 Created by potrace 1.15, written by Peter Selinger 2001-2017 kiwix-desktop-2.4.1/resources/icons/pause-button.png000066400000000000000000000025711473106011000225770ustar00rootroot00000000000000PNG  IHDR22?bKGD pHYsodtIME&[IDAThklU[6M[HZxhKD1~ j b"M|E>*J:`QRO@ P |1PTP6Їl'3pٝ=wsg2 vˀr%p8 0Z e;z`-pKm@j"@,۩^:@?%tFiS T7pp0Cڟ^>KP,"x(&v`襈ϫr xhݔY < ځF_@FgV3 IJNdȴlXfI{cFIlg(V}SJ-۩ʀ}JŴXSfS=0`V{5FD)~Kf"+ Vw+"ψx}rp-&__[/VQfdrBf+9Vv*BlgA;8hͳ_ ) Pr%Ѫc[$gD O,jrΈNZN!8:ǝĶ5ĬJHRNOQG#sW_픥B9qIc&^EΖ"`u vn8_CfnGFY8pe;W]|NiVuA@>5 Rxk\'i$냀}~]7Z O 2,3RD=lGK A@Aۜidr Xh'H7ߚ${]?@|JJ$X=FbZS@ h5d^\ h"vSؖylkXVG6OHVfXqw" gxn`glp~}+!},`VVyq^`? Iv㡅r ҳg17$^ύ8yh<Ȯ A <+@ۄΕlyȑp@6vjr0͸0P23Uؾ258.,'vVV]HDŽ?-a1v6M1 : GÖfof?nNhuR⋥Gq Kn|6Zt}K\.hI~&1 xh\_d/![lʒ k@icon / pause-downloadkiwix-desktop-2.4.1/resources/icons/pictures.svg000077500000000000000000000005311473106011000220170ustar00rootroot00000000000000icon / pictureskiwix-desktop-2.4.1/resources/icons/placeholder-icon.png000066400000000000000000000076441473106011000233670ustar00rootroot00000000000000PNG  IHDRxx9d6gAMA a cHRMz&u0`:pQ<tIME;탱>bKGDIDATx Pe_.Zv٫XٸZN(*(W墀 1%"$` *$AH@PAssC6Y?̋xow};c$D"H$D"H$D)2PΜ5|ܹcϟoeŋ?t) ,hcc3a޼yVg϶9s٬YիW3k]b*睝yxx8Go |(,,m۶,,,/$$$;000/vss[boo{O\gGG5x? [l/o޼9n{xxAlllSʾ}}YY_HҩSƆI:bfLcT(/8KLHAddq-Kܦ{Ϗ*~ Y[[/_A}9(((?>>`qtGR].ia>KptjPv*>..$8x|l)!dkZ"> O]ו{{`ו+Z`9(n}Cg=.]Q'iiQQQA -^fP t{[tq=hܛȒ`a(3#!,:`vh#9}8'';g)A$IbG|uuWuٳȾso:B;]K/F!,22;%% EaNΎ{2PXP}w6B4EAHyN7C'ÿ11A~'<_hZ݌ݾ>\7(F8/6B>x.uiz~N-v{јx6@2܃w%CB!L^SS  ^eQ.v6;̂Qy<w/။oofX^E&3D{@_ .o(1#]qΟgL<]_o*`}&` Y:;qkO r!GS0*V):x KIIy(???r{A# VYc332v4=kW˞RT*9VbF//Ą/djݸ"tdX*;;(~SB4砟>IC#%K,wDDl,++3̓xV6nd.m'O4,gyVDI%KL >{l| w pX9ڂ\lLLkgG$'D/i%Fg;fggߐ;o3dA}%UR<000t}VkwX`Elݺu۷G0%!`\ÃlժUSN})՗YK!,EYB>DU0zo  fFDD;wN\7>*V rrr __bȕ^OpV5k֌ssuݔ0.34w *@<1䷢;.JrǝojlU|}|xhshhhm]m)Yp|D 8'7:qnྫྷC,? %{{7luKICvbQ iwmmmǢ!9)I)2A 6*@|'U v·m4IvhWvVlܕ_ڴ@57ܱå즜+<)G)Vٯ]k{.[2'd@EEE<|ZNV LO(e_mEyV%p?--'6&uxP` UvMrRSӧ%~5CX t6Ψh;L Ynxgԥ_'^lN$q)$s&aPጪb E)F>*wPkE`S& +bZ3jݒV.IrK;`\J  s6~ I;kܒMY+uEk-,6 &@02@nzOĎ2itF- OLeqNy R`j mc&7!j$3\D{r' @QHKBm} ],RX@Z$!sT@.!J,⨭WBnNL@S:D2E1Ch*, r3`>l# L[V) bZVT@ԓK%K灷QgbhkC[ ZUQ2x7_ gԱT@bi9K2f;>rmdq[J(F9L@{mB{Dçقmf8 [%O-\qK,տz`:p{Ah' Y,QE G@JǗ~$!>sFrF5!,gR֔ЪW 1znuF 4:ꀧ/WY* H8 uJ8sEj&S=3BWz{室 I[ \gTm6G3&hث6\iߏyDh9iVE `Y0Vs`Z+KΘ.Ψ!C!SDZu^EY^Ym@Ng$%qq]V&?0(2$JG$'er% Yu%"М8(-'$~~IENDB`kiwix-desktop-2.4.1/resources/icons/print.svg000077500000000000000000000010361473106011000213160ustar00rootroot00000000000000icon / printkiwix-desktop-2.4.1/resources/icons/random.svg000077500000000000000000000011131473106011000214360ustar00rootroot00000000000000 icon / random kiwix-desktop-2.4.1/resources/icons/reading-list-active.svg000077500000000000000000000016331473106011000240200ustar00rootroot00000000000000icon / reading-list-activekiwix-desktop-2.4.1/resources/icons/reading-list.svg000077500000000000000000000015461473106011000225520ustar00rootroot00000000000000icon / reading-listkiwix-desktop-2.4.1/resources/icons/search-filter.svg000077500000000000000000000005321473106011000227120ustar00rootroot00000000000000icon / search-filterkiwix-desktop-2.4.1/resources/icons/search-inactive.svg000077500000000000000000000004661473106011000232350ustar00rootroot00000000000000icon / search-inactivekiwix-desktop-2.4.1/resources/icons/search-toc.svg000077500000000000000000000011301473106011000222050ustar00rootroot00000000000000icon / search-tockiwix-desktop-2.4.1/resources/icons/search.svg000077500000000000000000000044701473106011000214340ustar00rootroot00000000000000 image/svg+xml icon / search icon / search kiwix-desktop-2.4.1/resources/icons/search_backward.svg000066400000000000000000000033361473106011000232670ustar00rootroot00000000000000 image/svg+xml icon / back icon / back kiwix-desktop-2.4.1/resources/icons/search_forward.svg000066400000000000000000000033441473106011000231540ustar00rootroot00000000000000 image/svg+xml icon / back icon / back kiwix-desktop-2.4.1/resources/icons/settings.svg000077500000000000000000000011751473106011000220260ustar00rootroot00000000000000icon / settingskiwix-desktop-2.4.1/resources/icons/share.svg000077500000000000000000000006101473106011000212610ustar00rootroot00000000000000icon / sharekiwix-desktop-2.4.1/resources/icons/sidebar.svg000077500000000000000000000006061473106011000215750ustar00rootroot00000000000000icon / sidebarkiwix-desktop-2.4.1/resources/icons/star-active.svg000077500000000000000000000004601473106011000224040ustar00rootroot00000000000000icon / star-activekiwix-desktop-2.4.1/resources/icons/star.svg000077500000000000000000000004511473106011000211330ustar00rootroot00000000000000icon / starkiwix-desktop-2.4.1/resources/icons/stop-circle.svg000066400000000000000000000004141473106011000224020ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/icons/tick.svg000077500000000000000000000004071473106011000211150ustar00rootroot00000000000000icon / tickkiwix-desktop-2.4.1/resources/icons/toc.svg000077500000000000000000000011601473106011000207450ustar00rootroot00000000000000icon / tockiwix-desktop-2.4.1/resources/icons/xmark-solid.svg000066400000000000000000000010371473106011000224120ustar00rootroot00000000000000 kiwix-desktop-2.4.1/resources/js.qrc000066400000000000000000000001411473106011000174420ustar00rootroot00000000000000 js/headerAnchor.js kiwix-desktop-2.4.1/resources/js/000077500000000000000000000000001473106011000167375ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/js/headerAnchor.js000066400000000000000000000031141473106011000216570ustar00rootroot00000000000000function isHeaderElement(elem) { return elem.nodeName.match(/^H\d+$/) && elem.textContent; } function getDOMElementsPreorderDFS(elem, pred) { var result = []; if (pred(elem)) result.push(elem); for ( const child of elem.children) result = result.concat(getDOMElementsPreorderDFS(child, pred)); return result; } function anchorHeaderElements(headers) { return Array.from(headers, function(elem, i) { const text = elem.textContent.trim().replace(/"/g, '\\"'); const level = parseInt(elem.nodeName.substr(1)); const anchor = `kiwix-toc-${i}`; const anchorElem = document.createElement("a"); anchorElem.id = anchor; /* Mark header content with something we can reference. */ elem.insertAdjacentElement("afterbegin", anchorElem); return { text, level, anchor }; }); } function getHeadersJSONStr() { const headerInfo = { url: window.location.href.replace(location.hash,""), headers: [] }; if (document.body !== undefined) { const headers = getDOMElementsPreorderDFS(document.body, isHeaderElement); headerInfo.headers = anchorHeaderElements(headers); } return JSON.stringify(headerInfo); } new QWebChannel(qt.webChannelTransport, function(channel) { var kiwixObj = channel.objects.kiwixChannelObj; kiwixObj.sendHeadersJSONStr(getHeadersJSONStr()); kiwixObj.navigationRequested.connect(function(url, anchor) { if (window.location.href.replace(location.hash,"") == url) document.getElementById(anchor).scrollIntoView(); }); }); kiwix-desktop-2.4.1/resources/kiwix.qrc000066400000000000000000000056471473106011000202010ustar00rootroot00000000000000 icons/input-number.svg icons/minimize.svg icons/download.svg icons/checkbox.svg icons/history-left.svg icons/history-right.svg icons/help.svg icons/tick.svg icons/menu.svg icons/more.svg icons/add.svg icons/exit.svg icons/donate.svg icons/star.svg icons/search.svg icons/close.svg icons/copy.svg icons/star-active.svg icons/search-inactive.svg icons/checkbox-indeterminate.svg icons/add-to-reading-list.svg icons/checkbox-active.svg icons/pictures.svg icons/search-filter.svg icons/pause-download.svg icons/folder.svg icons/sidebar.svg icons/share.svg icons/blank.svg icons/print.svg icons/random.svg icons/full-screen-exit.svg icons/full-screen-enter.svg icons/search-toc.svg icons/downloading.svg icons/toc.svg icons/settings.svg icons/filter.svg icons/reading-list.svg icons/reading-list-active.svg icons/kiwix/scalable/kiwix-desktop.svg fonts/Selawik/LICENSE.txt fonts/Selawik/selawkb.ttf fonts/Selawik/selawkl.ttf fonts/Selawik/selawksb.ttf fonts/Selawik/selawksl.ttf fonts/Selawik/selawk.ttf texts/about.html icons/search_backward.svg icons/search_forward.svg icons/kiwix-app-icons-square.svg icons/play-button.png icons/pause-button.png icons/cancel-button.png icons/new-tab-icon.svg icons/open-file.svg icons/placeholder-icon.png icons/caret-down-solid.svg icons/caret-right-solid.svg icons/caret-up-solid.svg icons/kiwix-logo.svg icons/check-solid.svg icons/xmark-solid.svg icons/home-button.svg icons/more-vertical.svg icons/caret-left-solid.svg icons/stop-circle.svg icons/drop-down.svg kiwix-desktop-2.4.1/resources/org.kiwix.desktop-mime.xml000066400000000000000000000007421473106011000233660ustar00rootroot00000000000000 ZIM archive kiwix-desktop-2.4.1/resources/org.kiwix.desktop.appdata.xml000066400000000000000000000032121473106011000240450ustar00rootroot00000000000000 org.kiwix.desktop Kiwix View offline content The Kiwix Foundation

Kiwix is an offline reader - meaning that it allows you to check text or video that is normally only available on the internet.

We turn various online educational contents (such as Wikipedia, for example) into ZIM files, and these can be opened by Kiwix even if you have no connectivity whatsoever.

org.kiwix.desktop.desktop CC0-1.0 GPL-3.0+ https://github.com/kiwix/kiwix-desktop https://www.kiwix.org/support/ https://www.kiwix.org/faq/ https://www.kiwix.org/ contact_AT_kiwix.org https://upload.wikimedia.org/wikipedia/commons/3/38/Kiwix-desktop_showing_its_local_Library.png https://upload.wikimedia.org/wikipedia/commons/c/cd/Kiwix-desktop_showing_the_remote_Library.png https://upload.wikimedia.org/wikipedia/commons/3/3e/Kiwix_desktop_reading_a_TED_ZIM_file.png
kiwix-desktop-2.4.1/resources/org.kiwix.desktop.desktop000066400000000000000000000003231473106011000233050ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Kiwix Comment=View offline content Icon=kiwix-desktop Exec=kiwix-desktop %F Terminal=false MimeType=application/org.kiwix.desktop.x-zim; Keywords=zim; Categories=Education; kiwix-desktop-2.4.1/resources/settingsmanager.qrc000066400000000000000000000001471473106011000222270ustar00rootroot00000000000000 css/_settingsManager.css kiwix-desktop-2.4.1/resources/style.qrc000066400000000000000000000004471473106011000201770ustar00rootroot00000000000000 css/style.css css/popup.css css/localServer.css css/messageBox.css css/contentmanagerside.css css/choiceBox.css kiwix-desktop-2.4.1/resources/texts/000077500000000000000000000000001473106011000174725ustar00rootroot00000000000000kiwix-desktop-2.4.1/resources/texts/about.html000066400000000000000000000026451473106011000215010ustar00rootroot00000000000000

{{KIWIX_DESKTOP_TITLE}}

{{KIWIX_DESKTOP_DESCRIPTION}}

{{LEARN_MORE_ABOUT_KIWIX}}

{{RELEASE}}

{{SOURCE_CODE}}

{{VERSION_TXT}}

{{REPORTING_PROBLEM}}

{{REPORT_ISSUE}}

{{REPORT_ISSUE_2}}

{{LIBRARIES}}

kiwix-desktop-2.4.1/resources/translations.qrc000066400000000000000000000043051473106011000215550ustar00rootroot00000000000000 i18n/ar.json i18n/bcl.json i18n/bn.json i18n/br.json i18n/ca.json i18n/cs.json i18n/da.json i18n/de.json i18n/diq.json i18n/en.json i18n/eo.json i18n/es.json i18n/fa.json i18n/fi.json i18n/fr.json i18n/gsw.json i18n/he.json i18n/hi.json i18n/hy.json i18n/ia.json i18n/id.json i18n/ie.json i18n/io.json i18n/it.json i18n/ja.json i18n/ko.json i18n/ku-latn.json i18n/lb.json i18n/mk.json i18n/ms.json i18n/my.json i18n/nb.json i18n/nl.json i18n/nqo.json i18n/or.json i18n/pl.json i18n/pt-br.json i18n/pt.json i18n/qqq.json i18n/ro.json i18n/roa-tara.json i18n/ru.json i18n/sc.json i18n/scn.json i18n/sdc.json i18n/se.json i18n/sk.json i18n/skr-arab.json i18n/sl.json i18n/sms.json i18n/sq.json i18n/sr-ec.json i18n/sro.json i18n/sv.json i18n/ta.json i18n/te.json i18n/th.json i18n/tr.json i18n/uk.json i18n/zgh.json i18n/zh-hans.json i18n/zh-hant.json kiwix-desktop-2.4.1/scripts/000077500000000000000000000000001473106011000160005ustar00rootroot00000000000000kiwix-desktop-2.4.1/scripts/pkg-config-wrapper.py000066400000000000000000000043661473106011000220650ustar00rootroot00000000000000#!/usr/bin/env python # On Windows, static libraries are using "foo.lib" naming. # On Unix, they are in the form of "libfoo.a" # On Windows, "foo.lib" can also the definition of symbols in a foo.dll. # So you can link to "foo.lib", whatever you are doing static or dynamic linking and you are good. # However, meson is always creating static library as "libfoo.a" # 'to avoid a potential name clash with shared libraries which also generate import libraries with a lib suffix.' [1] # On top of that, qmake is replacing all `-lfoo` in LIBS by `foo.lib` (on Windows). # So at the end, we try to link with `foo.lib` but we have `libfoo.a` # Solution could be : # - Rename `libfoo.a` to `foo.lib`, but it would mean modify deps libraries on the FS # - Don't use LIBS and directly set QMAKE_LFLAGS but we would have to handle different command line option format # between g++/clang and msvc # - Update meson build system of each projet to explicitly set the library naming. # - Replace `-lfoo` with absolute path to static library. This is what meson is doing internally and what # we are doing here # # Any `-lfoo` is replace with absolute path to static library (`libfoo.a`) if we found one. # Else, it is keep unchanged. # # [1] https://mesonbuild.com/Reference-manual_functions.html#library_name_suffix import sys, subprocess from pathlib import Path def forward_to_pkg_config(): completeProcess = subprocess.run( ["pkg-config", *sys.argv[1:]], capture_output=True, check=True, text=True ) return completeProcess.stdout def search_static_lib(lib_name, search_paths): for path in search_paths: lib_path = path / f"lib{lib_name}.a" if lib_path.exists(): return str(lib_path) return None def replace_static_lib(pkg_output): search_paths = [] for option in pkg_output.split(): if option.startswith("-L"): search_paths.append(Path(option[2:])) yield option if option.startswith("-l"): static_lib = search_static_lib(option[2:], search_paths) if static_lib: yield static_lib else: yield option if __name__ == "__main__": pkg_output = forward_to_pkg_config() print(" ".join(replace_static_lib(pkg_output))) kiwix-desktop-2.4.1/src/000077500000000000000000000000001473106011000151005ustar00rootroot00000000000000kiwix-desktop-2.4.1/src/about.cpp000066400000000000000000000025711473106011000167230ustar00rootroot00000000000000#include "about.h" #include "ui_about.h" #include "kiwixapp.h" About::About(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); auto htmlText = ui->aboutText->toHtml(); htmlText = htmlText.replace("{{KIWIX_DESKTOP_TITLE}}", gt("about-kiwix-desktop-title")); htmlText = htmlText.replace("{{KIWIX_DESKTOP_DESCRIPTION}}", gt("about-kiwix-desktop-description")); htmlText = htmlText.replace("{{LEARN_MORE_ABOUT_KIWIX}}", gt("about-learn-more-about-kiwix")); htmlText = htmlText.replace("{{RELEASE}}", gt("about-release-title")); htmlText = htmlText.replace("{{SOURCE_CODE}}", gt("about-source-code")); htmlText = htmlText.replace("{{VERSION_TXT}}", gt("about-version")); htmlText = htmlText.replace("{{REPORTING_PROBLEM}}", gt("about-reporting-problem-title")); htmlText = htmlText.replace("{{REPORT_ISSUE}}", gt("about-report-issue")); htmlText = htmlText.replace("{{REPORT_ISSUE_2}}", gt("about-report-issue-2")); htmlText = htmlText.replace("{{LIBRARIES}}", gt("about-libraries-title")); htmlText = htmlText.replace("{{GITHUB_URL}}", "https://github.com/kiwix/kiwix-desktop"); htmlText = htmlText.replace("{{VERSION}}", version); htmlText = htmlText.replace("{{TRACKER_URL}}", "https://github.com/kiwix/kiwix-desktop/issues"); ui->aboutText->setHtml(htmlText); } About::~About() { delete ui; } kiwix-desktop-2.4.1/src/about.h000066400000000000000000000003771473106011000163720ustar00rootroot00000000000000#ifndef ABOUT_H #define ABOUT_H #include namespace Ui { class AboutDialog; } class About : public QDialog { Q_OBJECT public: explicit About(QWidget *parent = 0); ~About(); private: Ui::AboutDialog *ui; }; #endif // ABOUT_H kiwix-desktop-2.4.1/src/blobbuffer.cpp000066400000000000000000000001761473106011000177200ustar00rootroot00000000000000#include "blobbuffer.h" BlobBuffer::BlobBuffer(zim::Blob blob) : m_blob(blob) { setData(blob.data(), blob.size()); } kiwix-desktop-2.4.1/src/blobbuffer.h000066400000000000000000000004151473106011000173610ustar00rootroot00000000000000#ifndef BLOBBUFFER_H #define BLOBBUFFER_H #include #include class BlobBuffer : public QBuffer { Q_OBJECT public: BlobBuffer(zim::Blob m_blob); virtual ~BlobBuffer() = default; private: zim::Blob m_blob; }; #endif // BLOBBUFFER_H kiwix-desktop-2.4.1/src/choiceitem.cpp000066400000000000000000000014021473106011000177120ustar00rootroot00000000000000#include "choiceitem.h" #include "ui_choiceitem.h" #include #include #include "kiwixapp.h" ChoiceItem::ChoiceItem(QString key, QString value, QWidget *parent) : QWidget(parent), ui(new Ui::ChoiceItem), m_key(key), m_value(value) { ui->setupUi(this); this->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/choiceBox.css")); ui->itemLabel->setText(key); ui->itemLabel->setToolTip(key); connect(ui->closeButton, &QPushButton::clicked, [=](){ emit(closeButtonClicked(ui->itemLabel->text())); }); ui->closeButton->setCursor(Qt::PointingHandCursor); } ChoiceItem::~ChoiceItem() { delete ui; } void ChoiceItem::mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); return; } kiwix-desktop-2.4.1/src/choiceitem.h000066400000000000000000000010521473106011000173600ustar00rootroot00000000000000#ifndef CHOICEITEM_H #define CHOICEITEM_H #include namespace Ui { class ChoiceItem; } class ChoiceItem : public QWidget { Q_OBJECT public: explicit ChoiceItem(QString key, QString value, QWidget *parent = nullptr); ~ChoiceItem(); QString getKey() { return m_key; } QString getValue() { return m_value; } protected: void mousePressEvent(QMouseEvent *event) override; private: Ui::ChoiceItem *ui; QString m_key; QString m_value; signals: void closeButtonClicked(QString); }; #endif // CHOICEITEM_H kiwix-desktop-2.4.1/src/choiceitem.ui000066400000000000000000000073611473106011000175570ustar00rootroot00000000000000 ChoiceItem 0 0 119 35 0 0 0 30 Form 0 0 0 0 0 0 16777215 16777215 QFrame::StyledPanel QFrame::Raised 3 3 3 3 0 0 16777215 16777215 TextLabel true 0 0 0 0 10 16777215 :/icons/xmark-solid.svg:/icons/xmark-solid.svg 10 20 true kiwix-desktop-2.4.1/src/contentmanager.cpp000066400000000000000000001070041473106011000206130ustar00rootroot00000000000000#include "contentmanager.h" #include "kiwixapp.h" #include #include #include #include #include #include #include #include "contentmanagermodel.h" #include #include #include #include "contentmanagerdelegate.h" #include "node.h" #include "rownode.h" #include "descriptionnode.h" #include "kiwixmessagebox.h" #include #include "contentmanagerheader.h" #include #ifndef QT_NO_DEBUG #define DBGOUT(X) qDebug().nospace() << "DBG: " << X #else #define DBGOUT(X) #endif namespace { SettingsManager* getSettingsManager() { return KiwixApp::instance()->getSettingsManager(); } // Opens the directory containing the input file path. // parent is the widget serving as the parent for the error dialog in case of // failure. void openFileLocation(QString path, QWidget *parent = nullptr) { QFileInfo fileInfo(path); QDir dir = fileInfo.absoluteDir(); bool dirOpen = dir.exists() && dir.isReadable() && QDesktopServices::openUrl(dir.absolutePath()); if (!dirOpen) { QString failedText = gt("couldnt-open-location-text"); failedText = failedText.replace("{{FOLDER}}", "" + dir.absolutePath() + ""); showInfoBox(gt("couldnt-open-location"), failedText, parent); } } } // unnamed namespace ContentManager::ContentManager(Library* library) : DownloadManager(library), mp_library(library), mp_remoteLibrary(kiwix::Library::create()), m_remoteLibraryManager() { // mp_view will be passed to the tab who will take ownership, // so, we don't need to delete it. mp_view = new ContentManagerView(); managerModel = new ContentManagerModel(this); updateModel(); auto treeView = mp_view->getView(); treeView->setModel(managerModel); treeView->show(); auto header = new ContentManagerHeader(Qt::Orientation::Horizontal, treeView); treeView->setHeader(header); header->setSectionResizeMode(0, QHeaderView::Fixed); header->setSectionResizeMode(1, QHeaderView::Stretch); header->setSectionResizeMode(2, QHeaderView::Fixed); header->setSectionResizeMode(3, QHeaderView::Fixed); header->setSectionResizeMode(4, QHeaderView::Fixed); header->setDefaultAlignment(Qt::AlignLeft); header->setStretchLastSection(false); header->setSectionsClickable(true); header->setHighlightSections(true); treeView->setWordWrap(true); treeView->resizeColumnToContents(4); treeView->setColumnWidth(0, 70); treeView->setColumnWidth(5, 120); // TODO: set width for all columns based on viewport treeView->setAllColumnsShowFocus(true); setCurrentLanguage(getSettingsManager()->getLanguageList()); setCurrentCategoryFilter(getSettingsManager()->getCategoryList()); setCurrentContentTypeFilter(getSettingsManager()->getContentType()); connect(mp_library, &Library::booksChanged, this, [=]() {emit(this->booksChanged());}); connect(this, &ContentManager::filterParamsChanged, this, &ContentManager::updateLibrary); connect(this, &ContentManager::booksChanged, this, [=]() { updateModel(); }); connect(&m_remoteLibraryManager, &OpdsRequestManager::requestReceived, this, &ContentManager::updateRemoteLibrary); connect(mp_view->getView(), SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenu(const QPoint &))); connect(this, &ContentManager::pendingRequest, mp_view, &ContentManagerView::showLoader); connect(treeView, &QTreeView::doubleClicked, this, &ContentManager::openBookWithIndex); connect(&m_remoteLibraryManager, &OpdsRequestManager::languagesReceived, this, &ContentManager::updateLanguages); connect(&m_remoteLibraryManager, &OpdsRequestManager::categoriesReceived, this, &ContentManager::updateCategories); setCategories(); setLanguages(); connect(this, &DownloadManager::downloadUpdated, this, &ContentManager::updateDownload); connect(this, &DownloadManager::downloadCancelled, this, &ContentManager::downloadWasCancelled); connect(this, &DownloadManager::downloadDisappeared, this, &ContentManager::downloadDisappeared); connect(this, &DownloadManager::error, this, &ContentManager::handleError); if ( DownloadManager::downloadingFunctionalityAvailable() ) { startDownloadUpdaterThread(); } connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ContentManager::asyncUpdateLibraryFromDir); } void ContentManager::updateModel() { const auto bookIds = getBookIds(); BookInfoList bookList; QStringList keys = {"title", "tags", "date", "id", "size", "description", "favicon"}; for (auto bookId : bookIds) { auto mp = getBookInfos(bookId, keys); bookList.append(mp); } const DownloadManager& downloadMgr = *this; managerModel->setBooksData(bookList, downloadMgr); } void ContentManager::onCustomContextMenu(const QPoint &point) { QModelIndex index = mp_view->getView()->indexAt(point); if (!index.isValid()) return; QMenu contextMenu("optionsMenu", mp_view->getView()); auto bookNode = static_cast(index.internalPointer()); const auto id = bookNode->getBookId(); QAction menuDeleteBook(gt("delete-book"), this); QAction menuOpenBook(gt("open-book"), this); QAction menuDownloadBook(gt("download-book"), this); QAction menuPauseBook(gt("pause-download"), this); QAction menuResumeBook(gt("resume-download"), this); QAction menuCancelBook(gt("cancel-download"), this); QAction menuOpenFolder(gt("open-folder"), this); QAction menuPreviewBook(gt("preview-book-in-web-browser"), this); const auto bookState = getBookState(id); switch ( bookState ) { case BookState::DOWNLOAD_PAUSED: if ( getDownloadState(id)->getStatus() == DownloadState::PAUSED ) { contextMenu.addAction(&menuResumeBook); contextMenu.addAction(&menuCancelBook); } contextMenu.addAction(&menuPreviewBook); break; case BookState::DOWNLOADING: if ( getDownloadState(id)->getStatus() == DownloadState::DOWNLOADING ) { contextMenu.addAction(&menuPauseBook); contextMenu.addAction(&menuCancelBook); } contextMenu.addAction(&menuPreviewBook); break; case BookState::AVAILABLE_LOCALLY_AND_HEALTHY: case BookState::ERROR_MISSING_ZIM_FILE: case BookState::ERROR_CORRUPTED_ZIM_FILE: { const auto book = mp_library->getBookById(id); auto bookPath = QString::fromStdString(book.getPath()); if ( bookState == BookState::AVAILABLE_LOCALLY_AND_HEALTHY ) { contextMenu.addAction(&menuOpenBook); } contextMenu.addAction(&menuDeleteBook); contextMenu.addAction(&menuOpenFolder); connect(&menuOpenFolder, &QAction::triggered, [=]() { openFileLocation(bookPath, mp_view); }); break; } case BookState::AVAILABLE_ONLINE: contextMenu.addAction(&menuDownloadBook); contextMenu.addAction(&menuPreviewBook); break; default: break; } connect(&menuDeleteBook, &QAction::triggered, [=]() { eraseBook(id); }); connect(&menuOpenBook, &QAction::triggered, [=]() { openBook(id); }); connect(&menuDownloadBook, &QAction::triggered, [=]() { downloadBook(id); }); connect(&menuPauseBook, &QAction::triggered, [=]() { pauseBook(id, index); }); connect(&menuCancelBook, &QAction::triggered, [=]() { cancelBook(id); }); connect(&menuResumeBook, &QAction::triggered, [=]() { resumeBook(id, index); }); connect(&menuPreviewBook, &QAction::triggered, [=]() { openBookPreview(id); }); contextMenu.exec(mp_view->getView()->viewport()->mapToGlobal(point)); } void ContentManager::setLocal(bool local) { if (local == m_local) { return; } m_local = local; emit(filterParamsChanged()); setCategories(); setLanguages(); } QStringList ContentManager::getTranslations(const QStringList &keys) { QStringList translations; for(auto& key: keys) { translations.append(KiwixApp::instance()->getText(key)); } return translations; } void ContentManager::setCategories() { QStringList categories; if (m_local) { auto categoryData = mp_library->getKiwixLibrary()->getBooksCategories(); for (auto category : categoryData) { auto categoryName = QString::fromStdString(category); categories.push_back(categoryName); } m_categories = categories; emit(categoriesLoaded(m_categories)); return; } m_remoteLibraryManager.getCategoriesFromOpds(); } void ContentManager::setLanguages() { LanguageList languages; if (m_local) { auto languageData = mp_library->getKiwixLibrary()->getBooksLanguages(); for (auto language : languageData) { auto langCode = QString::fromStdString(language); auto selfName = QString::fromStdString(kiwix::getLanguageSelfName(language)); languages.push_back({selfName, langCode}); } m_languages = languages; emit(languagesLoaded(m_languages)); return; } m_remoteLibraryManager.getLanguagesFromOpds(); } namespace { QString getBookTags(const kiwix::Book& b) { QStringList tagList = QString::fromStdString(b.getTags()).split(';'); QMap displayTagMap; for(auto tag: tagList) { if (tag[0] == '_') { auto splitTag = tag.split(":"); displayTagMap[splitTag[0]] = splitTag[1] == "yes" ? true:false; } } QStringList displayTagList; if (displayTagMap["_videos"]) displayTagList << QObject::tr("Videos"); if (displayTagMap["_pictures"]) displayTagList << QObject::tr("Pictures"); if (!displayTagMap["_details"]) displayTagList << QObject::tr("Introduction only"); return displayTagList.join(", "); } QString getFaviconUrl(const kiwix::Book& b) { std::string url; try { auto item = b.getIllustration(48); url = item->url; } catch (...) { } return QString::fromStdString(url); } QByteArray getFaviconData(const kiwix::Book& b) { QByteArray qdata; try { // Try to obtain favicons only from local books (otherwise // kiwix::Book::Illustration::getData() attempts to download the image // on its own, whereas we want that operation to be performed // asynchronously by ThumbnailDownloader). if ( b.isPathValid() ) { const auto illustration = b.getIllustration(48); const std::string data = illustration->getData(); qdata = QByteArray::fromRawData(data.data(), data.size()); qdata.detach(); // deep copy } } catch ( ... ) { return QByteArray(); } return qdata; } QVariant getFaviconDataOrUrl(const kiwix::Book& b) { const QByteArray data = getFaviconData(b); return !data.isNull() ? QVariant(data) : QVariant(getFaviconUrl(b)); } QVariant getBookAttribute(const kiwix::Book& b, const QString& a) { if ( a == "id" ) return QString::fromStdString(b.getId()); if ( a == "path" ) return QString::fromStdString(b.getPath()); if ( a == "title" ) return QString::fromStdString(b.getTitle()); if ( a == "description" ) return QString::fromStdString(b.getDescription()); if ( a == "date" ) return QString::fromStdString(b.getDate()); if ( a == "url" ) return QString::fromStdString(b.getUrl()); if ( a == "name" ) return QString::fromStdString(b.getName()); if ( a == "favicon") return getFaviconDataOrUrl(b); if ( a == "size" ) return QString::number(b.getSize()); if ( a == "tags" ) return getBookTags(b); return QVariant(); } ContentManager::BookState getStateOfLocalBook(const kiwix::Book& book) { if ( !book.isPathValid() ) { return ContentManager::BookState::ERROR_MISSING_ZIM_FILE; } // XXX: When a book is detected to be corrupted, information about that // XXX: has to be recorded somewhere so that we can return // XXX: ERROR_CORRUPTED_ZIM_FILE here return ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY; } } // unnamed namespace ContentManager::BookInfo ContentManager::getBookInfos(QString id, const QStringList &keys) { const kiwix::Book* b = nullptr; try { b = &mp_library->getBookById(id); if ( ! b->getDownloadId().empty() ) { // The book is still being downloaded and has been entered into the // local library for technical reasons only. Get the book info from // the remote library. b = nullptr; } } catch (...) {} if ( !b ) { try { QMutexLocker locker(&remoteLibraryLocker); b = &mp_remoteLibrary->getBookById(id.toStdString()); } catch(...) {} } BookInfo values; for(auto& key: keys){ values.insert(key, b ? getBookAttribute(*b, key) : ""); } return values; } ContentManager::BookState ContentManager::getBookState(QString bookId) { if ( const auto downloadState = DownloadManager::getDownloadState(bookId) ) { return downloadState->getStatus() == DownloadState::PAUSED ? BookState::DOWNLOAD_PAUSED : BookState::DOWNLOADING; // TODO: a download may be in error state } try { const kiwix::Book& b = mp_library->getBookById(bookId); return b.getDownloadId().empty() ? getStateOfLocalBook(b) : BookState::DOWNLOADING; } catch (...) {} try { QMutexLocker locker(&remoteLibraryLocker); const kiwix::Book& b = mp_remoteLibrary->getBookById(bookId.toStdString()); return !b.getUrl().empty() ? BookState::AVAILABLE_ONLINE : BookState::METADATA_ONLY; } catch (...) {} return BookState::INVALID; } void ContentManager::openBookWithIndex(const QModelIndex &index) { auto bookNode = static_cast(index.internalPointer()); const QString bookId = bookNode->getBookId(); if ( getBookState(bookId) == BookState::AVAILABLE_LOCALLY_AND_HEALTHY ) { openBook(bookId); } } void ContentManager::openBook(const QString &id) { QUrl url("zim://"+id+".zim/"); try { KiwixApp::instance()->openUrl(url, true); } catch (const std::exception& e) { auto tabBar = KiwixApp::instance()->getTabWidget(); tabBar->closeTab(1); auto text = gt("zim-open-fail-text"); text = text.replace("{{ZIM}}", QString::fromStdString(mp_library->getBookById(id).getPath())); auto title = gt("zim-open-fail-title"); KiwixApp::instance()->showMessage(text, title, QMessageBox::Warning); mp_library->removeBookFromLibraryById(id); tabBar->setCurrentIndex(0); emit(booksChanged()); } } void ContentManager::openBookPreview(const QString &id) { try { QMutexLocker locker(&remoteLibraryLocker); const std::string &downloadUrl = mp_remoteLibrary->getBookById(id.toStdString()).getUrl(); locker.unlock(); /* Extract the Zim name from the book's download URL */ const auto zimNameStartIndex = downloadUrl.find_last_of('/') + 1; const std::string& zimName = downloadUrl.substr( zimNameStartIndex, downloadUrl.find(".zim", zimNameStartIndex) - zimNameStartIndex); const QUrl previewUrl = getRemoteLibraryUrl() + "/viewer#" + zimName.c_str(); QDesktopServices::openUrl(previewUrl); } catch (...) {} } void ContentManager::removeDownload(QString bookId) { DownloadManager::removeDownload(bookId); managerModel->setDownloadState(bookId, nullptr); } void ContentManager::downloadDisappeared(QString bookId) { removeDownload(bookId); kiwix::Book bCopy; try { bCopy = mp_library->getBookById(bookId); } catch ( const std::out_of_range& ) { // If the download has disappeared as a result of some // obscure chain of events, the book may have disappeared too. return; } bCopy.setDownloadId(""); mp_library->getKiwixLibrary()->addOrUpdateBook(bCopy); mp_library->save(); emit(mp_library->booksChanged()); } void ContentManager::downloadCompleted(QString bookId, QString path) { removeDownload(bookId); kiwix::Book bCopy(mp_library->getBookById(bookId)); bCopy.setPath(QDir::toNativeSeparators(path).toStdString()); bCopy.setDownloadId(""); bCopy.setPathValid(true); // removing book url so that download link in kiwix-serve is not displayed. bCopy.setUrl(""); mp_library->getKiwixLibrary()->addOrUpdateBook(bCopy); mp_library->save(); mp_library->bookmarksChanged(); if (!m_local) { emit(oneBookChanged(bookId)); } else { emit(mp_library->booksChanged()); } } void ContentManager::updateDownload(QString bookId, const DownloadInfo& downloadInfo) { const auto downloadState = DownloadManager::getDownloadState(bookId); if ( downloadState ) { const auto downloadPath = downloadInfo["path"].toString(); if ( downloadInfo["status"].toString() == "completed" ) { downloadCompleted(bookId, downloadPath); } else { mp_library->updateBookBeingDownloaded(bookId, downloadPath); downloadState->update(downloadInfo); managerModel->updateDownload(bookId); } } } void ContentManager::handleError(QString errSummary, QString errDetails) { showErrorBox(KiwixAppError(errSummary, errDetails), mp_view); } void ContentManager::downloadBook(const QString &id) { kiwix::Book book = getRemoteOrLocalBook(id); const auto downloadPath = getSettingsManager()->getDownloadDir(); try { DownloadManager::checkThatBookCanBeDownloaded(book, downloadPath); } catch ( const KiwixAppError& err ) { showErrorBox(err, mp_view); return; } mp_library->addBookBeingDownloaded(book, downloadPath); mp_library->save(); DownloadManager::addRequest(DownloadState::START, id); const auto downloadState = DownloadManager::getDownloadState(id); managerModel->setDownloadState(id, downloadState); } // This function is called asynchronously in a worker thread processing all // download operations. The call is initiated in downloadBook(). void ContentManager::startDownload(QString id) { kiwix::Book book = getRemoteOrLocalBook(id); const auto downloadPath = getSettingsManager()->getDownloadDir(); // downloadPath may be different from the value used in // downloadBook(). This may happen in the following scenario: // // 1. aria2c is stuck because of having to save to // slow storage (and the fact that it is a single-threaded // application). This may result in startDownload() being // called with significant delay after downloadBook(). // // 2. The user changes the download directory after starting // a download. // // That's why the checkThatBookCanBeDownloaded() check is repeated here. std::string downloadId; try { DownloadManager::checkThatBookCanBeDownloaded(book, downloadPath); downloadId = DownloadManager::startDownload(book, downloadPath); } catch ( const KiwixAppError& err ) { emit error(err.summary(), err.details()); return; } book.setDownloadId(downloadId); mp_library->addBookBeingDownloaded(book, downloadPath); mp_library->save(); emit(oneBookChanged(id)); } const kiwix::Book& ContentManager::getRemoteOrLocalBook(const QString &id) { try { QMutexLocker locker(&remoteLibraryLocker); return mp_remoteLibrary->getBookById(id.toStdString()); } catch (...) { return mp_library->getBookById(id); } } QString ContentManager::getRemoteLibraryUrl() const { auto host = m_remoteLibraryManager.getCatalogHost(); auto port = m_remoteLibraryManager.getCatalogPort(); return port == 443 ? "https://" + host : "http://" + host + ":" + QString::number(port); } static const char MSG_FOR_PREVENTED_RMSTAR_OPERATION[] = R"( BUG: Errare humanum est. BUG: Kiwix developers are human, but we try to ensure that our mistakes BUG: don't cause harm to our users. BUG: If we didn't detect this situation we could have erased a lot of files BUG: on your computer. )"; void ContentManager::eraseBookFilesFromComputer(const std::string& bookPath, bool moveToTrash) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) Q_UNUSED(moveToTrash); #endif const std::string dirPath = kiwix::removeLastPathElement(bookPath); const std::string fileGlob = kiwix::getLastPathElement(bookPath) + "*"; if ( fileGlob == "*" ) { std::cerr << MSG_FOR_PREVENTED_RMSTAR_OPERATION << std::endl; return; } QDir dir(QString::fromStdString(dirPath), QString::fromStdString(fileGlob)); for(const QString& file: dir.entryList()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) if (moveToTrash) QFile::moveToTrash(dir.filePath(file)); else #endif dir.remove(file); // moveToTrash will always be false here, no check required. } } QString formatText(QString text) { QString finalText = "

"; finalText += text; finalText += ""; return finalText; } void ContentManager::reallyEraseBook(const QString& id, bool moveToTrash) { auto tabBar = KiwixApp::instance()->getTabWidget(); tabBar->closeTabsByZimId(id); eraseBookFilesFromComputer(mp_library->getBookFilePath(id), moveToTrash); mp_library->removeBookFromLibraryById(id); mp_library->save(); emit mp_library->bookmarksChanged(); if (m_local) { emit(bookRemoved(id)); } else { emit(oneBookChanged(id)); } getSettingsManager()->deleteSettings(id); emit booksChanged(); } void ContentManager::eraseBook(const QString& id) { auto text = gt("delete-book-text"); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) const auto moveToTrash = getSettingsManager()->getMoveToTrash(); #else const auto moveToTrash = false; // we do not support move to trash functionality for qt versions below 5.15 #endif if (moveToTrash) { text += formatText(gt("move-files-to-trash-text")); } else { text += formatText(gt("perma-delete-files-text")); } text = text.replace("{{ZIM}}", QString::fromStdString(mp_library->getBookById(id).getTitle())); showConfirmBox(gt("delete-book"), text, mp_view, [=]() { reallyEraseBook(id, moveToTrash); }); } void ContentManager::pauseBook(const QString& id, QModelIndex index) { DownloadManager::addRequest(DownloadState::PAUSE, id); managerModel->triggerDataUpdateAt(index); } void ContentManager::resumeBook(const QString& id, QModelIndex index) { DownloadManager::addRequest(DownloadState::RESUME, id); managerModel->triggerDataUpdateAt(index); } void ContentManager::cancelBook(const QString& id) { auto text = gt("cancel-download-text"); text = text.replace("{{ZIM}}", QString::fromStdString(mp_library->getBookById(id).getTitle())); showConfirmBox(gt("cancel-download"), text, mp_view, [=]() { DownloadManager::addRequest(DownloadState::CANCEL, id); }); } void ContentManager::downloadWasCancelled(const QString& id) { removeDownload(id); // incompleted downloaded file should be perma deleted eraseBookFilesFromComputer(mp_library->getBookFilePath(id), false); mp_library->removeBookFromLibraryById(id); mp_library->save(); emit(oneBookChanged(id)); } void ContentManager::setCurrentLanguage(FilterList langPairList) { QStringList languageList; for (auto &langPair : langPairList) { languageList.append(langPair.second); } languageList.sort(); for (auto &language : languageList) { if (language.length() == 2) { try { language = QString::fromStdString( kiwix::converta2toa3(language.toStdString())); } catch (std::out_of_range&) {} } } auto newLanguage = languageList.join(","); if (m_currentLanguage == newLanguage) return; m_currentLanguage = newLanguage; getSettingsManager()->setLanguage(langPairList); emit(currentLangChanged()); emit(filterParamsChanged()); } void ContentManager::setCurrentCategoryFilter(QStringList categoryList) { categoryList.sort(); if (m_categoryFilter == categoryList.join(",")) return; m_categoryFilter = categoryList.join(","); getSettingsManager()->setCategory(categoryList); emit(filterParamsChanged()); } void ContentManager::setCurrentContentTypeFilter(FilterList contentTypeFiltersPairList) { QStringList contentTypeFilters; for (auto &ctfPair : contentTypeFiltersPairList) { contentTypeFilters.append(ctfPair.second); } m_contentTypeFilters = contentTypeFilters; getSettingsManager()->setContentType(contentTypeFiltersPairList); emit(filterParamsChanged()); } void ContentManager::updateLibrary() { if (m_local) { emit(pendingRequest(false)); emit(booksChanged()); return; } try { emit(pendingRequest(true)); m_remoteLibraryManager.doUpdate(m_currentLanguage, m_categoryFilter); } catch (std::runtime_error&) {} } void ContentManager::updateRemoteLibrary(const QString& content) { (void) QtConcurrent::run([=]() { QMutexLocker locker(&remoteLibraryLocker); mp_remoteLibrary = kiwix::Library::create(); kiwix::Manager manager(mp_remoteLibrary); manager.readOpds(content.toStdString(), getRemoteLibraryUrl().toStdString()); emit(this->booksChanged()); emit(this->pendingRequest(false)); }); } void ContentManager::updateLanguages(const QString& content) { auto languages = kiwix::readLanguagesFromFeed(content.toStdString()); LanguageList tempLanguages; for (auto language : languages) { auto code = QString::fromStdString(language.first); auto title = QString::fromStdString(language.second); tempLanguages.push_back({title, code}); } m_languages = tempLanguages; emit(languagesLoaded(m_languages)); } void ContentManager::updateCategories(const QString& content) {; auto categories = kiwix::readCategoriesFromFeed(content.toStdString()); QStringList tempCategories; for (auto catg : categories) { tempCategories.push_back(QString::fromStdString(catg)); } m_categories = tempCategories; emit(categoriesLoaded(m_categories)); } void ContentManager::setSearch(const QString &search) { m_searchQuery = search; emit(booksChanged()); } QStringList ContentManager::getBookIds() { kiwix::Filter filter; std::vector acceptTags, rejectTags; for (auto &contentTypeFilter : m_contentTypeFilters) { acceptTags.push_back(contentTypeFilter.toStdString()); } filter.acceptTags(acceptTags); filter.rejectTags(rejectTags); filter.query(m_searchQuery.toStdString()); if (m_currentLanguage != "") filter.lang(m_currentLanguage.toStdString()); if (m_categoryFilter != "") filter.category(m_categoryFilter.toStdString()); if (m_local) { filter.local(true); filter.valid(true); return mp_library->listBookIds(filter, m_sortBy, m_sortOrderAsc); } else { filter.remote(true); QMutexLocker locker(&remoteLibraryLocker); auto bookIds = mp_remoteLibrary->filter(filter); mp_remoteLibrary->sort(bookIds, m_sortBy, m_sortOrderAsc); QStringList list; for(auto& bookId:bookIds) { list.append(QString::fromStdString(bookId)); } return list; } } void ContentManager::setSortBy(const QString& sortBy, const bool sortOrderAsc) { if (sortBy == "unsorted") { m_sortBy = kiwix::UNSORTED; } else if (sortBy == "title") { m_sortBy = kiwix::TITLE; } else if (sortBy == "size") { m_sortBy = kiwix::SIZE; } else if (sortBy == "date") { m_sortBy = kiwix::DATE; } m_sortOrderAsc = sortOrderAsc; emit(booksChanged()); } //////////////////////////////////////////////////////////////////////////////// // Directory monitoring stuff //////////////////////////////////////////////////////////////////////////////// void ContentManager::setMonitoredDirectories(QStringSet dirList) { for (auto path : m_watcher.directories()) { m_watcher.removePath(path); } m_knownZimsInDir.clear(); MonitoredZimFileInfo libraryZimFileInfo; libraryZimFileInfo.status = MonitoredZimFileInfo::ADDED_TO_THE_LIBRARY; for (auto dir : dirList) { if (dir != "") { auto& zimsInDir = m_knownZimsInDir[dir]; for ( const auto& fname : mp_library->getLibraryZimsFromDir(dir) ) { zimsInDir.insert(fname, libraryZimFileInfo); } m_watcher.addPath(dir); asyncUpdateLibraryFromDir(dir); } } } void ContentManager::asyncUpdateLibraryFromDir(QString dir) { (void) QtConcurrent::run([=]() { updateLibraryFromDir(dir); }); } void ContentManager::handleDisappearedZimFiles(const QString& dirPath, const QStringSet& fileNames) { const auto kiwixLib = mp_library->getKiwixLibrary(); auto& zimsInDir = m_knownZimsInDir[dirPath]; for (const auto& file : fileNames) { const auto bookPath = QDir::toNativeSeparators(dirPath + "/" + file); try { DBGOUT("directory monitoring: file disappeared: " << bookPath); const auto book = kiwixLib->getBookByPath(bookPath.toStdString()); if ( handleDisappearedBook(QString::fromStdString(book.getId())) ) { zimsInDir.remove(file); } } catch (const std::exception& err) { DBGOUT("directory monitoring: " "error while dropping the disappeared book: " << err.what()); // the book was removed by the user via the UI zimsInDir.remove(file); } } } size_t ContentManager::handleNewZimFiles(const QString& dirPath, const QStringSet& fileNames) { size_t countOfSuccessfullyAddedZims = 0; for (const auto& file : fileNames) { const bool addedToLib = handleZimFileInMonitoredDirLogged(dirPath, file); countOfSuccessfullyAddedZims += addedToLib; } return countOfSuccessfullyAddedZims; } namespace { #ifndef QT_NO_DEBUG // indexed by MonitoredZimFileInfo::ZimFileStatus enum const char* monitoredDirZimFileHandlingMsgs[] = { "", "it is being downloaded by us, ignoring...", "the file was added to the library", "the file could not be added to the library", "it is an unchanged known bad zim file", "deferring the check of an updated bad zim file", "bad zim file was updated but a deferred request to check it is pending" }; #endif } // unnamed namespace bool ContentManager::handleZimFileInMonitoredDirLogged(QString dir, QString fileName) { DBGOUT("ContentManager::handleZimFileInMonitoredDir(" << dir << ", " << fileName << ")"); const int status = handleZimFileInMonitoredDir(dir, fileName); DBGOUT("\t" << monitoredDirZimFileHandlingMsgs[status]); return status == MonitoredZimFileInfo::ADDED_TO_THE_LIBRARY; } bool ContentManager::MonitoredZimFileInfo::fileKeepsBeingModified() const { // A file is considered stable if it has stayed unchanged for at least // this long. const qint64 FILE_STABILITY_DURATION_MS = 1000; const QDateTime now = QDateTime::currentDateTime(); return this->lastModified > now.addMSecs(-FILE_STABILITY_DURATION_MS); } void ContentManager::MonitoredZimFileInfo::updateStatus(const MonitoredZimFileInfo& prevInfo) { Q_ASSERT(prevInfo.status != ADDED_TO_THE_LIBRARY); if ( this->lastModified == prevInfo.lastModified ) { this->status = UNCHANGED_KNOWN_BAD_ZIM_FILE; } else if ( prevInfo.status == PROCESS_LATER ) { this->status = DEFERRED_PROCESSING_ALREADY_PENDING; } else if ( this->fileKeepsBeingModified() ) { this->status = PROCESS_LATER; } else { this->status = PROCESS_NOW; } } ContentManager::MonitoredZimFileInfo ContentManager::getMonitoredZimFileInfo(QString dir, QString fileName) const { const auto bookPath = QDir::toNativeSeparators(dir + "/" + fileName); MonitoredZimFileInfo zimFileInfo; zimFileInfo.lastModified = QFileInfo(bookPath).lastModified(); const auto& zimsInDir = m_knownZimsInDir[dir]; const auto fileInfoEntry = zimsInDir.constFind(fileName); if ( fileInfoEntry != zimsInDir.constEnd() ) { zimFileInfo.updateStatus(fileInfoEntry.value()); } return zimFileInfo; } int ContentManager::handleZimFileInMonitoredDir(QString dir, QString fileName) { const auto bookPath = QDir::toNativeSeparators(dir + "/" + fileName); if ( mp_library->isBeingDownloadedByUs(bookPath) ) { return MonitoredZimFileInfo::BEING_DOWNLOADED_BY_US; } MonitoredZimFileInfo zfi = getMonitoredZimFileInfo(dir, fileName); if ( zfi.status == MonitoredZimFileInfo::PROCESS_LATER ) { deferHandlingOfZimFileInMonitoredDir(dir, fileName); } else if ( zfi.status == MonitoredZimFileInfo::PROCESS_NOW ) { kiwix::Manager manager(mp_library->getKiwixLibrary()); const bool addedToLib = manager.addBookFromPath(bookPath.toStdString()); zfi.status = addedToLib ? MonitoredZimFileInfo::ADDED_TO_THE_LIBRARY : MonitoredZimFileInfo::COULD_NOT_BE_ADDED_TO_THE_LIBRARY; m_knownZimsInDir[dir].insert(fileName, zfi); } return zfi.status; } ContentManager::QStringSet ContentManager::getLibraryZims(QString dirPath) const { QStringSet zimFileNames; const auto& zimsInDir = m_knownZimsInDir[dirPath]; for ( auto it = zimsInDir.begin(); it != zimsInDir.end(); ++it ) { if ( it.value().status == MonitoredZimFileInfo::ADDED_TO_THE_LIBRARY ) zimFileNames.insert(it.key()); } return zimFileNames; } void ContentManager::updateLibraryFromDir(QString dirPath) { QMutexLocker locker(&m_updateFromDirMutex); const QDir dir(dirPath); const QStringSet zimsPresentInLib = getLibraryZims(dirPath); QStringSet zimsInDir; for (const auto &file : dir.entryList({"*.zim"})) { zimsInDir.insert(file); } const QStringSet zimsNotInLib = zimsInDir - zimsPresentInLib; const QStringSet removedZims = zimsPresentInLib - zimsInDir; handleDisappearedZimFiles(dirPath, removedZims); const auto countOfAddedZims = handleNewZimFiles(dirPath, zimsNotInLib); if (!removedZims.empty() || countOfAddedZims != 0) { mp_library->save(); emit(booksChanged()); } } void ContentManager::handleZimFileInMonitoredDirDeferred(QString dir, QString fileName) { QMutexLocker locker(&m_updateFromDirMutex); DBGOUT("ContentManager::handleZimFileInMonitoredDirDeferred(" << dir << ", " << fileName << ")"); m_knownZimsInDir[dir][fileName].status = MonitoredZimFileInfo::PROCESS_NOW; if ( handleZimFileInMonitoredDirLogged(dir, fileName) ) { mp_library->save(); emit(booksChanged()); } } void ContentManager::deferHandlingOfZimFileInMonitoredDir(QString dir, QString fname) { const qint64 DEBOUNCING_DELAY_MILLISECONDS = 1000; m_knownZimsInDir[dir][fname].status = MonitoredZimFileInfo::PROCESS_LATER; QTimer::singleShot(DEBOUNCING_DELAY_MILLISECONDS, this, [=]() { handleZimFileInMonitoredDirDeferred(dir, fname); }); } bool ContentManager::handleDisappearedBook(QString bookId) { if ( KiwixApp::instance()->getTabWidget()->getTabZimIds().contains(bookId) ) return false; mp_library->removeBookFromLibraryById(bookId); return true; } kiwix-desktop-2.4.1/src/contentmanager.h000066400000000000000000000162571473106011000202710ustar00rootroot00000000000000#ifndef CONTENTMANAGER_H #define CONTENTMANAGER_H #include #include "library.h" #include "contentmanagerview.h" #include "opdsrequestmanager.h" #include "contenttypefilter.h" #include "contentmanagermodel.h" #include "downloadmanagement.h" class ContentManager : public DownloadManager { Q_OBJECT Q_PROPERTY(bool isLocal MEMBER m_local READ isLocal WRITE setLocal NOTIFY localChanged) public: // types typedef QList> LanguageList; typedef QList> FilterList; typedef ContentManagerModel::BookInfo BookInfo; typedef ContentManagerModel::BookInfoList BookInfoList; typedef Library::QStringSet QStringSet; enum class BookState { // Nothing known about a book with that id INVALID, // Only (some) metadata is available for the book, however neither a // ZIM-file nor a URL is associated with it. METADATA_ONLY, // No ZIM file is associated with the book but a URL is provided. AVAILABLE_ONLINE, // The book is being downloaded. DOWNLOADING, // The book started downloading, but the download is currently paused. DOWNLOAD_PAUSED, // The book started downloading but the download was stopped due to // errors. DOWNLOAD_ERROR, // A valid ZIM file path is associated with the book and no evidence // about any issues with that ZIM file has so far been obtained. AVAILABLE_LOCALLY_AND_HEALTHY, // A ZIM file path is associated with the book but no such file seems // to exist (may be caused by missing read permissions for the directory // containing the ZIM file). ERROR_MISSING_ZIM_FILE, // A ZIM file is associated with the book but it cannot be opened // due to issues with its content. ERROR_CORRUPTED_ZIM_FILE }; public: // functions ContentManager(Library* library); ContentManagerView* getView() { return mp_view; } void setLocal(bool local); void setCurrentLanguage(FilterList languageList); void setCurrentCategoryFilter(QStringList categoryList); void setCurrentContentTypeFilter(FilterList contentTypeFilter); bool isLocal() const { return m_local; } QStringList getCategories() const { return m_categories; } LanguageList getLanguages() const { return m_languages; } void setMonitoredDirectories(QStringSet dirList); signals: void filterParamsChanged(); void booksChanged(); void oneBookChanged(const QString&); void bookRemoved(const QString&); void downloadsChanged(); void currentLangChanged(); void pendingRequest(const bool); void categoriesLoaded(QStringList); void languagesLoaded(LanguageList); void localChanged(const bool); public slots: QStringList getTranslations(const QStringList &keys); BookInfo getBookInfos(QString id, const QStringList &keys); BookState getBookState(QString id); void openBook(const QString& id); void openBookPreview(const QString& id); void downloadBook(const QString& id); void updateLibrary(); void setSearch(const QString& search); void setSortBy(const QString& sortBy, const bool sortOrderAsc); // eraseBook() asks for confirmation (reallyEraseBook() doesn't) void eraseBook(const QString& id); void updateRemoteLibrary(const QString& content); void updateLanguages(const QString& content); void updateCategories(const QString& content); void pauseBook(const QString& id, QModelIndex index); void resumeBook(const QString& id, QModelIndex index); void cancelBook(const QString& id); void onCustomContextMenu(const QPoint &point); void openBookWithIndex(const QModelIndex& index); void updateDownload(QString bookId, const DownloadInfo& downloadInfo); void downloadWasCancelled(const QString& id); void handleError(QString errSummary, QString errDetails); private: // types struct MonitoredZimFileInfo { enum ZimFileStatus { // try to add this file to the library right away PROCESS_NOW, // the file is known to be downloaded by our own download manager BEING_DOWNLOADED_BY_US, // the file was added to the library successfully ADDED_TO_THE_LIBRARY, // the attempt to add the file to the library failed COULD_NOT_BE_ADDED_TO_THE_LIBRARY, // the file couldn't be added to the library earlier and hasn't // changed since then UNCHANGED_KNOWN_BAD_ZIM_FILE, // try to add this file to the library at a later time PROCESS_LATER, // this file is known to be enqueued for later processing DEFERRED_PROCESSING_ALREADY_PENDING }; bool fileKeepsBeingModified() const; void updateStatus(const MonitoredZimFileInfo& prevInfo); ZimFileStatus status = PROCESS_NOW; QDateTime lastModified; }; typedef QMap ZimFileName2InfoMap; private: // functions QStringList getBookIds(); // reallyEraseBook() doesn't ask for confirmation (unlike eraseBook()) void reallyEraseBook(const QString& id, bool moveToTrash); void eraseBookFilesFromComputer(const std::string& bookPath, bool moveToTrash); void updateModel(); void setCategories(); void setLanguages(); QStringSet getLibraryZims(QString dirPath) const; void asyncUpdateLibraryFromDir(QString dir); void updateLibraryFromDir(QString dir); void handleDisappearedZimFiles(const QString& dirPath, const QStringSet& fileNames); size_t handleNewZimFiles(const QString& dirPath, const QStringSet& fileNames); bool handleZimFileInMonitoredDirLogged(QString dirPath, QString fileName); int handleZimFileInMonitoredDir(QString dirPath, QString fileName); MonitoredZimFileInfo getMonitoredZimFileInfo(QString dir, QString fileName) const; void deferHandlingOfZimFileInMonitoredDir(QString dir, QString fileName); void handleZimFileInMonitoredDirDeferred(QString dirPath, QString fileName); bool handleDisappearedBook(QString bookId); // Get the book with the specified id from // the remote or local library (in that order). const kiwix::Book& getRemoteOrLocalBook(const QString &id); QString getRemoteLibraryUrl() const; void startDownload(QString bookId) override; void removeDownload(QString bookId); void downloadDisappeared(QString bookId); void downloadCompleted(QString bookId, QString path); private: // data Library* mp_library; kiwix::LibraryPtr mp_remoteLibrary; OpdsRequestManager m_remoteLibraryManager; ContentManagerView* mp_view; bool m_local = true; QString m_currentLanguage; QString m_searchQuery; QString m_categoryFilter = "all"; QStringList m_contentTypeFilters; kiwix::supportedListSortBy m_sortBy = kiwix::UNSORTED; bool m_sortOrderAsc = true; LanguageList m_languages; QStringList m_categories; ContentManagerModel *managerModel; QMutex remoteLibraryLocker; QFileSystemWatcher m_watcher; QMutex m_updateFromDirMutex; QMap m_knownZimsInDir; }; #endif // CONTENTMANAGER_H kiwix-desktop-2.4.1/src/contentmanagerdelegate.cpp000066400000000000000000000234451473106011000223140ustar00rootroot00000000000000#include "contentmanagerdelegate.h" #include #include #include #include #include "kiwixapp.h" #include #include "rownode.h" #include "descriptionnode.h" #include "portutils.h" #include "css_constants.h" ContentManagerDelegate::ContentManagerDelegate(QObject *parent) : QStyledItemDelegate(parent), baseButton(new QPushButton) { baseButton->setStyleSheet("background-color: #00000000;" "border: 0;" "font-weight: bold;" "font-family: Selawik;" "color: blue;" "margin: 4px;"); } namespace { void createPauseSymbol(QPainter *painter, const QRect& buttonRect) { QPen pen; pen.setWidth(3); QPainterPath path; const int x = buttonRect.left() + 12.5; const int y = buttonRect.top() + 10; pen.setColor("#3366cc"); path.moveTo(x, y); path.lineTo(x, y + 10); painter->strokePath(path, pen); path.moveTo(x + 5, y); path.lineTo(x + 5, y + 10); painter->strokePath(path, pen); } void createResumeSymbol(QPainter *painter, const QRect& buttonRect) { QPen pen; pen.setWidth(3); QPainterPath path; const int x = buttonRect.left() + 12.5; const int y = buttonRect.top() + 8; pen.setColor("#3366cc"); path.moveTo(x, y); path.lineTo(x, y + 15); path.lineTo(x + 10, y + 8); path.lineTo(x, y); painter->setRenderHint(QPainter::Antialiasing); painter->strokePath(path, pen); } void createArc(QPainter *painter, int startAngle, int spanAngle, QRect rectangle, QPen pen) { painter->setRenderHint(QPainter::Antialiasing); int arcX = rectangle.x(); int arcY = rectangle.y(); int arcW = rectangle.width(); int arcH = rectangle.height(); QPainterPath path; path.moveTo(arcX + arcW, arcY + arcH/2); path.arcTo(rectangle, startAngle, spanAngle); painter->strokePath(path, pen); } void createCancelButton(QPainter *painter, const QRect& r) { QPen p; p.setWidth(3); p.setColor("#dd3333"); createArc(painter, 0, 360, r, p); painter->setPen(p); auto oldFont = painter->font(); auto bFont = oldFont; bFont.setBold(true); painter->setFont(bFont); painter->drawText(r, Qt::AlignCenter | Qt::AlignJustify, "X"); painter->setFont(oldFont); } void createDownloadStats(QPainter *painter, QRect box, QString downloadSpeed, QString completedLength) { QPen pen; int x = box.x(); int y = box.y(); int w = box.width(); int h = box.height(); pen.setColor("#666666"); painter->setPen(pen); auto oldFont = painter->font(); painter->setFont(QFont("Selawik", 8)); QRect nRect(x - 20, y - 10, w, h); painter->drawText(nRect,Qt::AlignCenter | Qt::AlignJustify, downloadSpeed); QRect fRect(x - 20, y + 10, w, h); painter->drawText(fRect,Qt::AlignCenter | Qt::AlignJustify, completedLength); painter->setFont(oldFont); } struct DownloadControlLayout { QRect pauseResumeButtonRect; QRect cancelButtonRect; }; DownloadControlLayout getDownloadControlLayout(QRect box) { const int x = box.left(); const int y = box.top(); const int w = box.width(); const int h = box.height(); const int buttonW = w - 90; const int buttonH = h - 40; DownloadControlLayout dcl; dcl.pauseResumeButtonRect = QRect(x + w/2 + 10, y + 20, buttonW, buttonH); dcl.cancelButtonRect = QRect(x + w/2 - 40, y + 20, buttonW, buttonH); return dcl; } void showDownloadProgress(QPainter *painter, QRect box, const DownloadState& downloadInfo) { const DownloadControlLayout dcl = getDownloadControlLayout(box); double progress = (double) (downloadInfo.progress) / 100; progress = -progress; auto completedLength = downloadInfo.completedLength; auto downloadSpeed = downloadInfo.getDownloadSpeed(); if (downloadInfo.getStatus() == DownloadState::PAUSED) { createResumeSymbol(painter, dcl.pauseResumeButtonRect); createCancelButton(painter, dcl.cancelButtonRect); } else if (downloadInfo.getStatus() == DownloadState::DOWNLOADING) { createPauseSymbol(painter, dcl.pauseResumeButtonRect); createDownloadStats(painter, box, downloadSpeed, completedLength); } QPen pen; pen.setWidth(3); painter->setPen(pen); painter->setRenderHint(QPainter::Antialiasing); pen.setColor("#dadce0"); createArc(painter, 0, 360, dcl.pauseResumeButtonRect, pen); int startAngle = 0; int spanAngle = progress * 360; pen.setColor("#3366cc"); createArc(painter, startAngle, spanAngle, dcl.pauseResumeButtonRect, pen); } } // unnamed namespace void ContentManagerDelegate::paintButton(QPainter *p, const QRect &r, QString t) const { QStyleOptionButton button; button.rect = r; button.state = QStyle::State_Enabled; button.text = t; baseButton->style()->drawControl( QStyle::CE_PushButton, &button, p, baseButton.data()); } void ContentManagerDelegate::paintBookState(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const { const QRect r = opt.rect; if (opt.state & QStyle::State_MouseOver) { // don't paint over the line separator const auto cellInternalArea = r.adjusted(0, 0, 0, -1); p->fillRect(cellInternalArea, QBrush("#eaecf0")); } const auto node = static_cast(index.internalPointer()); const auto id = node->getBookId(); switch ( KiwixApp::instance()->getContentManager()->getBookState(id) ) { case ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY: return paintButton(p, r, gt("open")); case ContentManager::BookState::AVAILABLE_ONLINE: return paintButton(p, r, gt("download")); case ContentManager::BookState::DOWNLOADING: case ContentManager::BookState::DOWNLOAD_PAUSED: case ContentManager::BookState::DOWNLOAD_ERROR: return showDownloadProgress(p, r, *node->getDownloadState()); default: return; } } void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (isDescriptionIndex(index)) return QStyledItemDelegate::paint(painter, option, index); QStyleOptionViewItem eOpt = option; if (index.column() == 1) { auto bFont = painter->font(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) bFont.setWeight(60); #else bFont.setWeight(QFont::DemiBold); #endif eOpt.font = bFont; } QStyledItemDelegate::paint(painter, eOpt, index); if (index.column() == 5) { paintBookState(painter, eOpt, index); } } bool ContentManagerDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { Q_UNUSED(model); if(event->type() == QEvent::MouseButtonRelease ) { QMouseEvent * e = (QMouseEvent *)event; if (e->button() == Qt::MiddleButton && index.column() != 5) { KiwixApp::instance()->getContentManager()->openBookWithIndex(index); return true; } const QPoint clickPoint(portutils::getX(*e), portutils::getY(*e)); if ( index.column() == 5 && option.rect.contains(clickPoint, true) ) handleLastColumnClicked(index, e, option); } return true; } void ContentManagerDelegate::handleLastColumnClicked(const QModelIndex& index, QMouseEvent *mouseEvent, const QStyleOptionViewItem &option) { const auto node = static_cast(index.internalPointer()); const auto id = node->getBookId(); const auto downloadState = node->getDownloadState(); const int clickX = portutils::getX(*mouseEvent); const int clickY = portutils::getY(*mouseEvent); const QPoint clickPoint(clickX, clickY); const DownloadControlLayout dcl = getDownloadControlLayout(option.rect); ContentManager& contentMgr = *KiwixApp::instance()->getContentManager(); switch ( contentMgr.getBookState(id) ) { case ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY: return contentMgr.openBook(id); case ContentManager::BookState::AVAILABLE_ONLINE: return contentMgr.downloadBook(id); case ContentManager::BookState::DOWNLOADING: if ( downloadState->getStatus() == DownloadState::DOWNLOADING ) { if ( dcl.pauseResumeButtonRect.contains(clickPoint) ) { contentMgr.pauseBook(id, index); } } return; case ContentManager::BookState::DOWNLOAD_PAUSED: if ( downloadState->getStatus() == DownloadState::PAUSED ) { if ( dcl.cancelButtonRect.contains(clickPoint) ) { contentMgr.cancelBook(id); } else if ( dcl.pauseResumeButtonRect.contains(clickPoint) ) { contentMgr.resumeBook(id, index); } } return; default: return; } } QSize ContentManagerDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { if (isDescriptionIndex(index)) { const auto treeView = KiwixApp::instance()->getContentManager()->getView()->getView(); const int width = treeView->header()->length() - 2*treeView->indentation(); const int verticalPadding = CSS::ContentManagerCSS::QTreeView::padding; const int horizontalPadding = CSS::ContentManagerCSS::QTreeView::padding; QRect descRect(0, 0, width - 2 * horizontalPadding, 0); /* Based on the rectangle and text, find the best fitting size. */ QFontMetrics fm(option.font); const QString text = index.data().toString(); const auto format = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap; const int textHeight = fm.boundingRect(descRect, format, text).height(); return QSize(width, std::max(textHeight + verticalPadding, 70)); } return QSize(50, 70); } kiwix-desktop-2.4.1/src/contentmanagerdelegate.h000066400000000000000000000017741473106011000217620ustar00rootroot00000000000000#ifndef CONTENTMANAGERDELEGATE_H #define CONTENTMANAGERDELEGATE_H #include #include #include class ContentManagerDelegate : public QStyledItemDelegate { Q_OBJECT public: ContentManagerDelegate(QObject *parent=0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: // functions void paintBookState(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const; void paintButton(QPainter *p, const QRect &r, QString t) const; private: QScopedPointer baseButton; void handleLastColumnClicked(const QModelIndex& index, QMouseEvent *event, const QStyleOptionViewItem &option); }; #endif // CONTENTMANAGERDELEGATE_H kiwix-desktop-2.4.1/src/contentmanagerheader.cpp000066400000000000000000000010761473106011000217660ustar00rootroot00000000000000#include "contentmanagerheader.h" #include ContentManagerHeader::ContentManagerHeader(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent) {} ContentManagerHeader::~ContentManagerHeader() {} void ContentManagerHeader::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const { // This is required so that the sort indicator icon is not shown in first column if (logicalIndex == 0) return; painter->save(); QHeaderView::paintSection(painter, rect, logicalIndex); painter->restore(); } kiwix-desktop-2.4.1/src/contentmanagerheader.h000066400000000000000000000006461473106011000214350ustar00rootroot00000000000000#ifndef CONTENTMANAGERHEADER_H #define CONTENTMANAGERHEADER_H #include class ContentManagerHeader : public QHeaderView { Q_OBJECT public: explicit ContentManagerHeader(Qt::Orientation orientation, QWidget *parent = nullptr); ~ContentManagerHeader(); protected: void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const override; }; #endif // CONTENTMANAGERHEADER_H kiwix-desktop-2.4.1/src/contentmanagermodel.cpp000066400000000000000000000201171473106011000216330ustar00rootroot00000000000000#include "contentmanagermodel.h" #include "node.h" #include "rownode.h" #include "descriptionnode.h" #include #include #include "kiwixapp.h" #include ContentManagerModel::ContentManagerModel(ContentManager *contentMgr) : QAbstractItemModel(contentMgr) , m_contentMgr(*contentMgr) { connect(&td, &ThumbnailDownloader::oneThumbnailDownloaded, this, &ContentManagerModel::updateImage); } ContentManagerModel::~ContentManagerModel() { } int ContentManagerModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return static_cast(parent.internalPointer())->columnCount(); return rootNode->columnCount(); } namespace { QIcon makeIcon(const QByteArray& iconData) { QPixmap pix; pix.loadFromData(iconData); return QIcon(pix); } QIcon createPlaceholderIcon() { QImage placeholderIconFile(":/icons/placeholder-icon.png"); QByteArray iconData; QBuffer buffer(&iconData); buffer.open(QIODevice::WriteOnly); placeholderIconFile.save(&buffer, "png"); return makeIcon(iconData); } QIcon getIcon(const QByteArray& iconData) { static QIcon placeholderIcon = createPlaceholderIcon(); return iconData.isNull() ? placeholderIcon : makeIcon(iconData); } } // unnamed namespace QVariant ContentManagerModel::data(const QModelIndex& index, int role) const { if ( ! index.isValid() ) return QVariant(); const auto col = index.column(); const bool isThumbnailRequest = !isDescriptionIndex(index) && col == 0 && role == Qt::DecorationRole; const bool isDescriptionRequest = isDescriptionIndex(index) && col == 0 && role == Qt::DisplayRole; const bool otherDataRequest = col != 0 && role == Qt::DisplayRole; if ( !isThumbnailRequest && !otherDataRequest && !isDescriptionRequest ) return QVariant(); const auto item = static_cast(index.internalPointer()); QVariant r = item->data(col); if ( !isThumbnailRequest ) return r; r = getThumbnail(r); if ( r.userType() == QMetaType::QByteArray ) return getIcon(r.toByteArray()); const QString faviconUrl = r.toString(); if ( !faviconUrl.isEmpty() ) td.addDownload(faviconUrl, item->getBookId()); return QVariant(); } Qt::ItemFlags ContentManagerModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if (isDescriptionIndex(index)) { return defaultFlags & ~Qt::ItemIsDropEnabled & ~Qt::ItemIsDragEnabled & ~Qt::ItemIsSelectable & ~Qt::ItemIsEditable & ~Qt::ItemIsUserCheckable; } return defaultFlags; } QModelIndex ContentManagerModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); RowNode* parentItem; if (!parent.isValid()) { parentItem = rootNode.get(); } else { parentItem = static_cast(parent.internalPointer()); } auto childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem.get()); return QModelIndex(); } QModelIndex ContentManagerModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); auto childItem = static_cast(index.internalPointer()); auto parentItem = childItem->parentItem(); if (!parentItem || parentItem == rootNode) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem.get()); } int ContentManagerModel::rowCount(const QModelIndex &parent) const { const auto node = parent.isValid() ? static_cast(parent.internalPointer()) : rootNode.get(); return node->childCount(); } QVariant ContentManagerModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) return QVariant(); switch (section) { case 1: return "Name"; case 2: return "Date"; case 3: return "Size"; case 4: return "Content Type"; default: return QVariant(); } } void ContentManagerModel::setBooksData(const BookInfoList& data, const DownloadManager& downloadMgr) { rootNode = std::shared_ptr(new RowNode({tr("Icon"), tr("Name"), tr("Date"), tr("Size"), tr("Content Type"), tr("Download")}, "", std::weak_ptr())); beginResetModel(); bookIdToRowMap.clear(); for (auto bookItem : data) { const auto rowNode = createNode(bookItem); // Restore download state during model updates (filtering, etc) rowNode->setDownloadState(downloadMgr.getDownloadState(rowNode->getBookId())); bookIdToRowMap[bookItem["id"].toString()] = rootNode->childCount(); rootNode->appendChild(rowNode); } endResetModel(); emit dataChanged(QModelIndex(), QModelIndex()); } // Returns either data of the thumbnail (as a QByteArray) or a URL (as a // QString) from where the actual data can be obtained. QVariant ContentManagerModel::getThumbnail(const QVariant& faviconEntry) const { if ( faviconEntry.userType() == QMetaType::QByteArray ) return faviconEntry; const auto faviconUrl = faviconEntry.toString(); return m_iconMap.contains(faviconUrl) ? m_iconMap[faviconUrl] : faviconEntry; } std::shared_ptr ContentManagerModel::createNode(BookInfo bookItem) const { QString id = bookItem["id"].toString(); const QVariant bookIcon = getThumbnail(bookItem["favicon"]); std::weak_ptr weakRoot = rootNode; auto rowNodePtr = std::shared_ptr(new RowNode({bookIcon, bookItem["title"], bookItem["date"], QString::fromStdString(kiwix::beautifyFileSize(bookItem["size"].toULongLong())), bookItem["tags"] }, id, weakRoot)); std::weak_ptr weakRowNodePtr = rowNodePtr; const auto descNodePtr = std::make_shared(DescriptionNode(bookItem["description"].toString(), weakRowNodePtr)); rowNodePtr->appendChild(descNodePtr); return rowNodePtr; } bool ContentManagerModel::hasChildren(const QModelIndex &parent) const { auto item = static_cast(parent.internalPointer()); if (item) return item->childCount() > 0; return true; } void ContentManagerModel::sort(int column, Qt::SortOrder order) { if (column == 0 || column == 4 || column == 5) return; QString sortBy = ""; switch(column) { case 1: sortBy = "title"; break; case 2: sortBy = "date"; break; case 3: sortBy = "size"; break; default: sortBy = "unsorted"; } m_contentMgr.setSortBy(sortBy, order == Qt::AscendingOrder); } RowNode* ContentManagerModel::getRowNode(size_t row) { return static_cast(rootNode->child(row).get()); } void ContentManagerModel::updateImage(QString bookId, QString url, QByteArray imageData) { const auto it = bookIdToRowMap.constFind(bookId); if ( it == bookIdToRowMap.constEnd() ) return; const size_t row = it.value(); const auto item = getRowNode(row); item->setIconData(imageData); m_iconMap[url] = imageData; triggerDataUpdateAt( this->index(row, 0) ); } void ContentManagerModel::updateDownload(QString bookId) { const auto it = bookIdToRowMap.constFind(bookId); if ( it != bookIdToRowMap.constEnd() ) { const size_t row = it.value(); triggerDataUpdateAt( this->index(row, 5) ); } } void ContentManagerModel::triggerDataUpdateAt(QModelIndex index) { emit dataChanged(index, index); } void ContentManagerModel::setDownloadState(QString bookId, std::shared_ptr ds) { const auto it = bookIdToRowMap.constFind(bookId); if ( it == bookIdToRowMap.constEnd() ) return; const size_t row = it.value(); getRowNode(row)->setDownloadState(ds); triggerDataUpdateAt( this->index(row, 5) ); } kiwix-desktop-2.4.1/src/contentmanagermodel.h000066400000000000000000000045321473106011000213030ustar00rootroot00000000000000#ifndef CONTENTMANAGERMODEL_H #define CONTENTMANAGERMODEL_H #include #include #include #include #include "thumbnaildownloader.h" #include "rownode.h" #include "downloadmanagement.h" #include class ContentManager; class RowNode; class Node; class DescriptionNode; class ContentManagerModel : public QAbstractItemModel { Q_OBJECT public: // types typedef QMap BookInfo; typedef QList BookInfoList; public: // functions explicit ContentManagerModel(ContentManager* contentMgr); ~ContentManagerModel(); QVariant data(const QModelIndex &index, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; void setBooksData(const BookInfoList& data, const DownloadManager& downloadMgr); bool hasChildren(const QModelIndex &parent) const override; void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; std::shared_ptr createNode(BookInfo bookItem) const; public slots: void updateImage(QString bookId, QString url, QByteArray imageData); void triggerDataUpdateAt(QModelIndex index); void setDownloadState(QString bookId, std::shared_ptr ds); void updateDownload(QString bookId); private: // functions // Returns either data of the thumbnail (as a QByteArray) or a URL (as a // QString) from where the actual data can be obtained. QVariant getThumbnail(const QVariant& faviconEntry) const; RowNode* getRowNode(size_t row); private: // data ContentManager& m_contentMgr; std::shared_ptr rootNode; mutable ThumbnailDownloader td; QMap bookIdToRowMap; QMap m_iconMap; }; inline bool isDescriptionIndex(const QModelIndex& index) { return index.parent().isValid(); } #endif // CONTENTMANAGERMODEL_H kiwix-desktop-2.4.1/src/contentmanagerside.cpp000066400000000000000000000113521473106011000214600ustar00rootroot00000000000000#include "contentmanagerside.h" #include "ui_contentmanagerside.h" #include "kiwixapp.h" #include "kiwixchoicebox.h" #include #include #include "klistwidgetitem.h" #include ContentManagerSide::ContentManagerSide(QWidget *parent) : QWidget(parent), mp_ui(new Ui::contentmanagerside) { setFocusPolicy(Qt::FocusPolicy::StrongFocus); mp_ui->setupUi(this); this->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/contentmanagerside.css")); mp_ui->buttonGroup->setId(mp_ui->allFileButton, CatalogButtonId::ALL); mp_ui->buttonGroup->setId(mp_ui->localFileButton, CatalogButtonId::LOCAL); connect(mp_ui->buttonGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) { const auto id = mp_ui->buttonGroup->id(btn); mp_contentManager->setLocal(id == CatalogButtonId::LOCAL); }); connect(mp_ui->allFileButton, &QRadioButton::toggled, this, [=](bool checked) { mp_ui->allFileButton->setStyleSheet( checked ? "*{font-weight: bold}" : "");}); connect(mp_ui->localFileButton, &QRadioButton::toggled, this, [=](bool checked) { mp_ui->localFileButton->setStyleSheet( checked ?"*{font-weight: bold}" : "");}); mp_ui->allFileButton->setText(gt("online-files")); mp_ui->localFileButton ->setText(gt("local-files")); mp_categories = mp_ui->categories; mp_categories->setType("category"); mp_languages = mp_ui->languages; mp_languages->setType("language"); mp_contentType = mp_ui->contentType; mp_contentType->setType("content-type"); auto searcher = mp_ui->searcher; searcher->setPlaceholderText(gt("search-files")); QIcon searchIcon = QIcon(":/icons/search.svg"); searcher->addAction(searchIcon, QLineEdit::LeadingPosition); connect(searcher, &QLineEdit::textChanged, [searcher](){ KiwixApp::instance()->getContentManager()->setSearch(searcher->text()); }); FilterList contentTypeList = { {gt("pictures"), "_pictures:yes"}, {gt("no-pictures"), "_pictures:no"}, {gt("videos"), "_videos:yes"}, {gt("no-videos"), "_videos:no"}, {gt("details"), "_details:yes"}, {gt("no-details"), "_details:no"} }; mp_contentType->setSelections(contentTypeList, KiwixApp::instance()->getSettingsManager()->getContentType()); setCategories(KiwixApp::instance()->getContentManager()->getCategories()); setLanguages(KiwixApp::instance()->getContentManager()->getLanguages()); connect(KiwixApp::instance()->getContentManager(), &ContentManager::categoriesLoaded, this, &ContentManagerSide::setCategories); connect(KiwixApp::instance()->getContentManager(), &ContentManager::languagesLoaded, this, &ContentManagerSide::setLanguages); } ContentManagerSide::~ContentManagerSide() { delete mp_ui; } void ContentManagerSide::setContentManager(ContentManager *contentManager) { mp_contentManager = contentManager; const auto isLocal = mp_contentManager->isLocal(); const auto checkedButton = mp_ui->buttonGroup->button(isLocal == CatalogButtonId::LOCAL); checkedButton->setChecked(true); checkedButton->setStyleSheet("*{font-weight: bold}"); connect(mp_languages, &KiwixChoiceBox::choiceUpdated, this, [=](FilterList values) { mp_contentManager->setCurrentLanguage(values); }); connect(mp_categories, &KiwixChoiceBox::choiceUpdated, this, [=](FilterList values) { QStringList categoryList; for (const auto& pair : values) categoryList.append(pair.second); mp_contentManager->setCurrentCategoryFilter(categoryList); }); connect(mp_contentType, &KiwixChoiceBox::choiceUpdated, this, [=](FilterList values) { mp_contentManager->setCurrentContentTypeFilter(values); }); } namespace { KiwixChoiceBox::SelectionList getCategorySelectionList(QStringList categoryList) { const auto lang = QLocale().name().split('_')[0].toStdString(); KiwixChoiceBox::SelectionList sList; for (const auto &category : categoryList) { const auto translation = QString::fromStdString(kiwix::translateBookCategory(lang, category.toStdString())); sList.append({translation, category}); } return sList; } } void ContentManagerSide::setCategories(QStringList categories) { auto categorySelections = getCategorySelectionList(categories); auto defaultSelections = getCategorySelectionList( KiwixApp::instance()->getSettingsManager()->getCategoryList()); mp_categories->setSelections(categorySelections, defaultSelections); } void ContentManagerSide::setLanguages(ContentManager::LanguageList langList) { mp_languages->setSelections(langList, KiwixApp::instance()->getSettingsManager()->getLanguageList()); } kiwix-desktop-2.4.1/src/contentmanagerside.h000066400000000000000000000017211473106011000211240ustar00rootroot00000000000000#ifndef CONTENTMANAGERSIDE_H #define CONTENTMANAGERSIDE_H #include #include #include #include "contentmanager.h" #include "contenttypefilter.h" namespace Ui { class contentmanagerside; } class KiwixChoiceBox; using FilterList = ContentManager::FilterList; class ContentManagerSide : public QWidget { Q_OBJECT public: enum CatalogButtonId { ALL = 0, LOCAL = 1 }; explicit ContentManagerSide(QWidget *parent = 0); ~ContentManagerSide(); void setContentManager(ContentManager* contentManager); private: Ui::contentmanagerside *mp_ui; ContentManager* mp_contentManager; KiwixChoiceBox *mp_categories; KiwixChoiceBox *mp_languages; KiwixChoiceBox *mp_contentType; QCheckBox* mp_contentTypeButton; QStringList m_contentTypeFilters; public slots: void setCategories(QStringList); void setLanguages(ContentManager::LanguageList); }; #endif // CONTENTMANAGERSIDE_H kiwix-desktop-2.4.1/src/contentmanagerside.ui000066400000000000000000000143511473106011000213150ustar00rootroot00000000000000 contentmanagerside 0 0 300 386 0 0 250 0 Form true QLayout::SetNoConstraint 0 0 0 0 true true 0 0 298 384 9 0 0 PointingHandCursor All Files buttonGroup 0 0 0 0 PointingHandCursor Local Files true buttonGroup 0 0 true 0 0 true 0 0 0 0 PointingHandCursor QFrame::NoFrame QFrame::Sunken 0 0 0 0 Qt::Vertical QSizePolicy::Expanding 20 0 KiwixChoiceBox QWidget
src/kiwixchoicebox.h
1
kiwix-desktop-2.4.1/src/contentmanagerview.cpp000066400000000000000000000050601473106011000215050ustar00rootroot00000000000000#include "contentmanagerview.h" #include #include "kiwixapp.h" #include "contentmanagerdelegate.h" #include #include "ui_contentmanagerview.h" ContentManagerView::ContentManagerView(QWidget *parent) : QWidget(parent), mp_ui(new Ui::contentmanagerview) { mp_ui->setupUi(this); mp_ui->m_view->setSortingEnabled(true); mp_ui->m_view->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/_contentManager.css")); mp_ui->m_view->setContextMenuPolicy(Qt::CustomContextMenu); auto managerDelegate = new ContentManagerDelegate(); mp_ui->m_view->setItemDelegate(managerDelegate); mp_ui->m_view->setCursor(Qt::PointingHandCursor); loader = new KiwixLoader(mp_ui->loading); mp_ui->stackedWidget->setCurrentIndex(0); connect(mp_ui->m_view, &QTreeView::clicked, this, &ContentManagerView::onClicked); connect(mp_ui->m_view, &QTreeView::expanded, this, &ContentManagerView::onExpanded); connect(this, &ContentManagerView::sizeHintChanged, managerDelegate, &QStyledItemDelegate::sizeHintChanged); // Needed to reveal the situation with downloads not being updated timely // (due to aria2c becoming unresponsive when saving to slow storage) QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, [this]() { this->update(); }); timer->start(1000); } ContentManagerView::~ContentManagerView() { } void ContentManagerView::showLoader(bool show) { mp_ui->stackedWidget->setCurrentIndex(show); if (show) { loader->startAnimation(); } else { loader->stopAnimation(); } } void ContentManagerView::onClicked(QModelIndex index) { if (index.column() == (mp_ui->m_view->model()->columnCount() - 1)) return; auto zeroColIndex = index.siblingAtColumn(0); if (mp_ui->m_view->isExpanded(zeroColIndex)) { mp_ui->m_view->collapse(zeroColIndex); } else { mp_ui->m_view->expand(zeroColIndex); } } void ContentManagerView::onExpanded(QModelIndex index) { if (!mp_ui->m_view->isFirstColumnSpanned(0, index)) mp_ui->m_view->setFirstColumnSpanned(0, index, true); } /** * @brief Notify delegate to update size hint of the visible description rows. */ void ContentManagerView::updateSizeHint() { auto view = this->getView(); if (!view->isVisible()) return; auto visibleIndex = view->indexAt(view->rect().topLeft()); while (visibleIndex.isValid()) { if (isDescriptionIndex(visibleIndex)) emit sizeHintChanged(visibleIndex); visibleIndex = view->indexBelow(visibleIndex); } } kiwix-desktop-2.4.1/src/contentmanagerview.h000066400000000000000000000013031473106011000211460ustar00rootroot00000000000000#ifndef CONTENTMANAGERVIEW_H #define CONTENTMANAGERVIEW_H #include #include "ui_contentmanagerview.h" #include "kiwixloader.h" namespace Ui { class contentmanagerview; } class ContentManagerView : public QWidget { Q_OBJECT public: explicit ContentManagerView(QWidget *parent = nullptr); ~ContentManagerView(); QTreeView* getView() { return mp_ui->m_view; } public slots: void showLoader(bool show); void onClicked(QModelIndex index); void onExpanded(QModelIndex index); void updateSizeHint(); signals: void sizeHintChanged(const QModelIndex& index); private: Ui::contentmanagerview *mp_ui; KiwixLoader *loader; }; #endif // CONTENTMANAGERVIEW_H kiwix-desktop-2.4.1/src/contentmanagerview.ui000066400000000000000000000024111473106011000213350ustar00rootroot00000000000000 contentmanagerview 0 0 400 300 Form 0 0 kiwix-desktop-2.4.1/src/contenttypefilter.cpp000066400000000000000000000016141473106011000213700ustar00rootroot00000000000000#include "contenttypefilter.h" #include "kiwixapp.h" ContentTypeFilter::ContentTypeFilter(QString name, QWidget *parent) : QCheckBox(parent), m_name(name) { setTristate(true); m_states[Qt::Unchecked] = gt("no-filter"); m_states[Qt::PartiallyChecked] = gt("yes"); m_states[Qt::Checked] = gt("no"); setText(gt(m_name) + " : " + m_states[checkState()]); setStyleSheet("* { color: #666666; }"); #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) connect(this, &QCheckBox::checkStateChanged, this, &ContentTypeFilter::onStateChanged); #else connect(this, &QCheckBox::stateChanged, this, &ContentTypeFilter::onStateChanged); #endif } void ContentTypeFilter::onStateChanged(int state) { setText(gt(m_name) + " : " + m_states[static_cast(state)]); setStyleSheet((state == 0) ? "*{color: #666666;}" : "*{font-weight: bold; color: black;}"); } kiwix-desktop-2.4.1/src/contenttypefilter.h000066400000000000000000000007301473106011000210330ustar00rootroot00000000000000#ifndef CONTENTTYPEFILTER_H #define CONTENTTYPEFILTER_H #include #include class ContentTypeFilter : public QCheckBox { Q_OBJECT public: explicit ContentTypeFilter(QString name, QWidget *parent = nullptr); virtual ~ContentTypeFilter() {} QString getName() { return m_name; } public slots: void onStateChanged(int state); private: QString m_name; QMap m_states; }; #endif // CONTENTTYPEFILTER_H kiwix-desktop-2.4.1/src/css_constants.h000066400000000000000000000031661473106011000201430ustar00rootroot00000000000000#ifndef CSS_CONSTANTS_H #define CSS_CONSTANTS_H /** * @brief The need for this file is due to the lack of support to retrieve CSS * values of Qt Widgets. Such deficiency means every code that depend on a CSS * values need to be updated on change to that value. This file makes it so that * a dependent CSS value only need to be updated here instead of its every use. * * - The CSS values in this file should create appropriate namespaces similar to * a CSS hierarchy. * - The classes are defined in resources/style.css unless specified. * - Naming convention should follow Javascript's style naming. * - Comments should be added to the duplicated css properties in css files. */ namespace CSS { namespace QTabBar { namespace tab { const int padding = 4; const int border = 1; } } namespace SearchBar{ const int margin = 2; const int border = 1; } namespace MultiZimButton { namespace QListWidget { namespace item { const int paddingHorizontal = 5; const int border = 1; } const int paddingVertical = 5; } namespace QScrollBar { const int width = 5; } } namespace ZimItemWidget { namespace QLabel { const int lineHeight = 24; } } namespace TopWidget { namespace QToolButton { namespace backButton { const int marginLeft = 6; } } } /* In _contentManager.css */ namespace ContentManagerCSS { namespace QTreeView { const int padding = 4; } } /* In popup.css */ namespace PopupCSS { namespace QHeaderView { namespace section { const int marginTop = 5; const int lineHeight = 24; const int paddingVertical = 5; const int paddingLeft = 10; } } } } #endif // CSS_CONSTANTS_H kiwix-desktop-2.4.1/src/descriptionnode.cpp000066400000000000000000000016561473106011000210050ustar00rootroot00000000000000#include "descriptionnode.h" #include "rownode.h" DescriptionNode::DescriptionNode(QString desc, std::weak_ptr parent) : m_desc(desc), m_parentItem(parent) {} DescriptionNode::~DescriptionNode() {} std::shared_ptr DescriptionNode::parentItem() { std::shared_ptr temp = m_parentItem.lock(); if (!temp) return nullptr; return temp; } QString DescriptionNode::getBookId() const { std::shared_ptr temp = m_parentItem.lock(); if (!temp) return QString(); return temp->getBookId(); } int DescriptionNode::childCount() const { return 0; } int DescriptionNode::columnCount() const { return 1; } QVariant DescriptionNode::data(int column) { if (column == 0) return m_desc; return QVariant(); } int DescriptionNode::row() const { std::shared_ptr temp = m_parentItem.lock(); if (!temp) return 0; return temp->row(); } kiwix-desktop-2.4.1/src/descriptionnode.h000066400000000000000000000011031473106011000204350ustar00rootroot00000000000000#ifndef DESCRIPTIONNODE_H #define DESCRIPTIONNODE_H #include #include "node.h" class RowNode; class DescriptionNode : public Node { public: DescriptionNode(QString desc, std::weak_ptr parent); ~DescriptionNode(); std::shared_ptr parentItem() override; int childCount() const override; int columnCount() const override; QVariant data(int column) override; int row() const override; QString getBookId() const override; private: QString m_desc; std::weak_ptr m_parentItem; }; #endif // DESCRIPTIONNODE_H kiwix-desktop-2.4.1/src/downloadmanagement.cpp000066400000000000000000000310671473106011000214570ustar00rootroot00000000000000#include "downloadmanagement.h" #include "kiwixapp.h" #include "kiwixmessagebox.h" #include #include //////////////////////////////////////////////////////////////////////////////// // DowloadState //////////////////////////////////////////////////////////////////////////////// namespace { QString convertToUnits(double bytes) { QStringList units = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB"}; int unitIndex = 0; while (bytes >= 1024 && unitIndex < units.size()) { bytes /= 1024; unitIndex++; } const auto preciseBytes = QString::number(bytes, 'g', 3); return preciseBytes + " " + units[unitIndex]; } DownloadState::Status getDownloadStatus(QString status) { if ( status == "active" ) return DownloadState::DOWNLOADING; if ( status == "paused" ) return DownloadState::PAUSED; if ( status == "waiting" ) return DownloadState::WAITING; if ( status == "error" ) return DownloadState::DOWNLOAD_ERROR; return DownloadState::UNKNOWN; } } // unnamed namespace bool DownloadState::isLateUpdateInfo(const DownloadInfo& info) const { if ( ! stateChangeHasBeenRequested() ) return false; const auto updateRequestTime = info["updateRequestTime"].toDouble(); return updateRequestTime < lastUpdated.time_since_epoch().count(); } void DownloadState::update(const DownloadInfo& info) { const auto completedBytes = info["completedLength"].toDouble(); const double percentage = completedBytes / info["totalLength"].toDouble(); progress = QString::number(100 * percentage, 'g', 3).toDouble(); completedLength = convertToUnits(completedBytes); downloadSpeed = convertToUnits(info["downloadSpeed"].toDouble()) + "/s"; if ( !isLateUpdateInfo(info) ) { status = getDownloadStatus(info["status"].toString()); } lastUpdated = std::chrono::steady_clock::now(); } double DownloadState::timeSinceLastUpdate() const { typedef std::chrono::duration Seconds; const auto dt = std::chrono::steady_clock::now() - lastUpdated; return std::chrono::duration_cast(dt).count(); } QString DownloadState::getDownloadSpeed() const { return timeSinceLastUpdate() > 2.0 ? "---" : downloadSpeed; } void DownloadState::changeState(Action action) { const auto oldStatus = status; if ( action == PAUSE ) { if ( status == DOWNLOADING ) { status = PAUSE_REQUESTED; } } else if ( action == RESUME ) { if ( status == PAUSED ) { status = RESUME_REQUESTED; } } else if ( action == CANCEL ) { if ( status == DOWNLOADING || status == PAUSED ) { status = CANCEL_REQUESTED; } } if ( status != oldStatus ) { lastUpdated = std::chrono::steady_clock::now(); } } //////////////////////////////////////////////////////////////////////////////// // DowloadManager //////////////////////////////////////////////////////////////////////////////// namespace { kiwix::Downloader* createDownloader() { try { return new kiwix::Downloader(getDataDirectory().toStdString()); } catch (std::exception& e) { QMessageBox::critical(nullptr, gt("error-downloader-window-title"), gt("error-downloader-launch-message") + "

" + e.what()); return nullptr; } } } // unnamed namespace DownloadManager::DownloadManager(const Library* lib) : mp_library(lib) , mp_downloader(createDownloader()) { restoreDownloads(); } DownloadManager::~DownloadManager() { if ( mp_downloadUpdaterThread ) { QThread* t = mp_downloadUpdaterThread; mp_downloadUpdaterThread = nullptr; // tell the thread to terminate // At this point the thread may be stuck waiting for data. // Let's wake it up. m_requestQueue.enqueue({DownloadState::UPDATE, ""}); t->wait(); } } bool DownloadManager::downloadingFunctionalityAvailable() const { return mp_downloader.get() != nullptr; } void DownloadManager::processDownloadActions() { while ( mp_downloadUpdaterThread != nullptr ) { const Request req = m_requestQueue.dequeue(); if ( !req.bookId.isEmpty() ) { switch ( req.action ) { case DownloadState::START: startDownload(req.bookId); break; case DownloadState::PAUSE: pauseDownload(req.bookId); break; case DownloadState::RESUME: resumeDownload(req.bookId); break; case DownloadState::CANCEL: cancelDownload(req.bookId); break; case DownloadState::UPDATE: updateDownload(req.bookId); break; } } } } void DownloadManager::startDownloadUpdaterThread() { // so that DownloadInfo can be copied across threads qRegisterMetaType("DownloadInfo"); mp_downloadUpdaterThread = QThread::create([=]() { processDownloadActions(); }); mp_downloadUpdaterThread->start(); QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, [this]() { if ( m_requestQueue.isEmpty() ) { for ( const auto& bookId : m_downloads.keys() ) { addRequest(DownloadState::UPDATE, bookId); } } }); timer->start(1000); } void DownloadManager::restoreDownloads() { for ( const auto& bookId : mp_library->getBookIds() ) { const kiwix::Book& book = mp_library->getBookById(bookId); if ( ! book.getDownloadId().empty() ) { const auto newDownload = std::make_shared(); m_downloads.set(bookId, newDownload); } } } void DownloadManager::updateDownload(QString bookId) { const auto updateRequestTime = std::chrono::steady_clock::now(); DownloadInfo downloadInfo; try { downloadInfo = getDownloadInfo(bookId); } catch ( ... ) { emit downloadDisappeared(bookId); return; } downloadInfo["updateRequestTime"] = double(updateRequestTime.time_since_epoch().count()); emit downloadUpdated(bookId, downloadInfo); } namespace { QString downloadStatus2QString(kiwix::Download::StatusResult status) { switch(status){ case kiwix::Download::K_ACTIVE: return "active"; case kiwix::Download::K_WAITING: return "waiting"; case kiwix::Download::K_PAUSED: return "paused"; case kiwix::Download::K_ERROR: return "error"; case kiwix::Download::K_COMPLETE: return "completed"; case kiwix::Download::K_REMOVED: return "removed"; default: return "unknown"; } } } // unnamed namespace DownloadInfo DownloadManager::getDownloadInfo(QString bookId) const { auto& b = mp_library->getBookById(bookId); const auto d = mp_downloader->getDownload(b.getDownloadId()); d->updateStatus(true); return { { "status" , downloadStatus2QString(d->getStatus()) }, { "completedLength" , QString::number(d->getCompletedLength()) }, { "totalLength" , QString::number(d->getTotalLength()) }, { "downloadSpeed" , QString::number(d->getDownloadSpeed()) }, { "path" , QString::fromStdString(d->getPath()) } }; } namespace { void throwDownloadUnavailableError() { throw KiwixAppError(gt("download-unavailable"), gt("download-unavailable-text")); } uint64_t getMaxFileSize(const QStorageInfo& storageInfo) { const uint64_t GiB = 1024UL*1024UL*1024UL; // Maximum file size limits of filesystems that are expected to be // encountered in practice and cause problems should be entered below static const QMap problematicFileSystems = { // The output of QStorageInfo::fileSystemType() is platform dependent #ifdef _WIN32 // XXX: find out the real name for FAT32 as reported under Windows { "FAT32", 4*GiB - 1 } #else { "vfat", 4*GiB - 1 } #endif }; const uint64_t virtuallyNoLimit = std::numeric_limits::max(); const auto fsType = storageInfo.fileSystemType(); return problematicFileSystems.value(fsType, virtuallyNoLimit); } void checkThatBookCanBeSaved(const kiwix::Book& book, QString targetDir) { const QFileInfo targetDirInfo(targetDir); if ( !targetDirInfo.isDir() ) { throw KiwixAppError(gt("download-storage-error"), gt("download-dir-missing")); } // XXX: This may lie under Windows // XXX: (see https://doc.qt.io/qt-5/qfile.html#platform-specific-issues) if ( !targetDirInfo.isWritable() ) { throw KiwixAppError(gt("download-storage-error"), gt("download-dir-not-writable")); } QStorageInfo storage(targetDir); auto bytesAvailable = storage.bytesAvailable(); if (bytesAvailable == -1 || book.getSize() > (unsigned long long) bytesAvailable) { throw KiwixAppError(gt("download-storage-error"), gt("download-storage-error-text")); } if ( book.getSize() > getMaxFileSize(storage) ) { throw KiwixAppError(gt("download-storage-error"), gt("download-exceeds-max-file-size")); } } } // unnamed namespace void DownloadManager::checkThatBookCanBeDownloaded(const kiwix::Book& book, const QString& downloadDirPath) { if ( ! DownloadManager::downloadingFunctionalityAvailable() ) throwDownloadUnavailableError(); checkThatBookCanBeSaved(book, downloadDirPath); } std::string DownloadManager::startDownload(const kiwix::Book& book, const QString& downloadDirPath) { const std::string& url = book.getUrl(); const QString bookId = QString::fromStdString(book.getId()); std::string downloadId; try { const auto d = mp_downloader->startDownload(url, downloadDirPath.toStdString()); downloadId = d->getDid(); } catch (std::exception& e) { throwDownloadUnavailableError(); } return downloadId; } void DownloadManager::addRequest(Action action, QString bookId) { if ( action == DownloadState::START ) { m_downloads.set(bookId, std::make_shared()); } if ( const auto downloadState = getDownloadState(bookId) ) { m_requestQueue.enqueue({action, bookId}); if ( action != DownloadState::UPDATE ) { downloadState->changeState(action); } } } void DownloadManager::pauseDownload(const QString& bookId) { const auto downloadId = mp_library->getBookById(bookId).getDownloadId(); if ( downloadId.empty() ) { // Completion of the download has been detected (and its id was reset) // before the pause-download action was triggered (most likely through // the context menu which can stay open for an arbitrarily long time, // or, unlikely, through the ⏸ button during the last milliseconds of // the download progress). return; } auto download = mp_downloader->getDownload(downloadId); if (download->getStatus() == kiwix::Download::K_ACTIVE) { try { download->pauseDownload(); } catch (const kiwix::AriaError&) { // Download has completed before the pause request was handled. // Most likely the download was already complete at the time // when ContentManager::pauseBook() started executing, but its // completion was not yet detected (and/or handled) by the download // updater thread. } } } void DownloadManager::resumeDownload(const QString& bookId) { auto& b = mp_library->getBookById(bookId); auto download = mp_downloader->getDownload(b.getDownloadId()); if (download->getStatus() == kiwix::Download::K_PAUSED) { download->resumeDownload(); } } void DownloadManager::cancelDownload(const QString& bookId) { const auto downloadId = mp_library->getBookById(bookId).getDownloadId(); if ( downloadId.empty() ) { // Completion of the download has been detected (and its id was reset) // before the confirmation to cancel the download was granted. return; } auto download = mp_downloader->getDownload(downloadId); try { download->cancelDownload(); } catch (const kiwix::AriaError&) { // Download has completed before the cancel request was handled. // Most likely the download was already complete at the time // when ContentManager::reallyCancelBook() started executing, but // its completion was not yet detected (and/or handled) by the // download updater thread (letting the code pass past the empty // downloadId check above). return; } emit downloadCancelled(bookId); } void DownloadManager::removeDownload(QString bookId) { m_downloads.remove(bookId); } kiwix-desktop-2.4.1/src/downloadmanagement.h000066400000000000000000000117051473106011000211210ustar00rootroot00000000000000#ifndef DOWNLOADMANAGEMENT_H #define DOWNLOADMANAGEMENT_H #include #include #include #include #include #include #include #include #include #include #include #include "library.h" typedef QMap DownloadInfo; template class ThreadSafePriorityQueue { public: void enqueue(const T& x) { const QMutexLocker threadSafetyGuarantee(&m_mutex); m_queue.push(x); m_queueIsNotEmpty.wakeAll(); } T dequeue() { const QMutexLocker threadSafetyGuarantee(&m_mutex); if ( m_queue.empty() ) m_queueIsNotEmpty.wait(&m_mutex); const T ret = m_queue.top(); m_queue.pop(); return ret; } bool isEmpty() const { const QMutexLocker threadSafetyGuarantee(&m_mutex); return m_queue.empty(); } private: // data mutable QMutex m_mutex; std::priority_queue m_queue; QWaitCondition m_queueIsNotEmpty; }; class DownloadState { public: // types enum Action { UPDATE, START, PAUSE, RESUME, CANCEL }; enum Status { UNKNOWN, WAITING, DOWNLOAD_ERROR, DOWNLOADING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED, CANCEL_REQUESTED }; public: // data double progress = 0; QString completedLength; public: // functions void update(const DownloadInfo& info); QString getDownloadSpeed() const; Status getStatus() const { return status; } void changeState(Action action); bool stateChangeHasBeenRequested() const { return status == PAUSE_REQUESTED || status == RESUME_REQUESTED || status == CANCEL_REQUESTED; } bool isLateUpdateInfo(const DownloadInfo& info) const; // time in seconds since last update double timeSinceLastUpdate() const; private: // data Status status = UNKNOWN; QString downloadSpeed; std::chrono::steady_clock::time_point lastUpdated; }; class DownloadManager : public QObject { Q_OBJECT public: // types typedef std::shared_ptr DownloadStatePtr; typedef DownloadState::Action Action; private: // BookId -> DownloadState map class Downloads { private: typedef QMap ImplType; public: void set(const QString& id, DownloadStatePtr d) { const QMutexLocker threadSafetyGuarantee(&mutex); impl[id] = d; } DownloadStatePtr value(const QString& id) const { const QMutexLocker threadSafetyGuarantee(&mutex); return impl.value(id); } QList keys() const { const QMutexLocker threadSafetyGuarantee(&mutex); return impl.keys(); } void remove(const QString& id) { const QMutexLocker threadSafetyGuarantee(&mutex); impl.remove(id); } private: ImplType impl; mutable QMutex mutex; }; public: // functions explicit DownloadManager(const Library* lib); virtual ~DownloadManager(); bool downloadingFunctionalityAvailable() const; void startDownloadUpdaterThread(); DownloadInfo getDownloadInfo(QString bookId) const; void restoreDownloads(); void addRequest(Action action, QString bookId); // Throws a KiwixAppError in case of any foreseeable problem preventing a // successful download void checkThatBookCanBeDownloaded(const kiwix::Book& book, const QString& downloadDirPath); void removeDownload(QString bookId); DownloadStatePtr getDownloadState(QString bookId) const { return m_downloads.value(bookId); } signals: void error(QString errSummary, QString errDetails); void downloadUpdated(QString bookId, const DownloadInfo& ); void downloadCancelled(QString bookId); void downloadDisappeared(QString bookId); protected: // returns the download id std::string startDownload(const kiwix::Book& book, const QString& downloadDirPath); private: // types struct Request { Action action; QString bookId; bool operator<(const Request& other) const { return this->action < other.action; } }; typedef ThreadSafePriorityQueue RequestQueue; private: // functions void processDownloadActions(); virtual void startDownload(QString bookId) = 0; void pauseDownload(const QString& bookId); void resumeDownload(const QString& bookId); void updateDownload(QString bookId); void cancelDownload(const QString& bookId); private: // data const Library* const mp_library; const std::unique_ptr mp_downloader; Downloads m_downloads; QThread* mp_downloadUpdaterThread = nullptr; RequestQueue m_requestQueue; }; #endif // DOWNLOADMANAGEMENT_H kiwix-desktop-2.4.1/src/findinpagebar.cpp000066400000000000000000000034341473106011000204010ustar00rootroot00000000000000#include "findinpagebar.h" #include "ui_findinpagebar.h" #include "kiwixapp.h" FindInPageBar::FindInPageBar(QWidget *parent) : QFrame(parent), mp_ui(new Ui::FindInPageBar) { mp_ui->setupUi(this); mp_findLineEdit = mp_ui->findEdit; connect(mp_ui->hideButton, &QPushButton::released, this, &FindInPageBar::findClose); connect(mp_ui->fNextButton, &QPushButton::released, this, &FindInPageBar::findNext); connect(mp_ui->fPreviousButton, &QPushButton::released, this, &FindInPageBar::findPrevious); connect(mp_findLineEdit, &QLineEdit::returnPressed, this, &FindInPageBar::findNext); } FindInPageBar::~FindInPageBar() { delete mp_ui; } void FindInPageBar::findNext() { auto searchText = mp_findLineEdit->text(); if (searchText.isEmpty()) return; auto current = KiwixApp::instance()->getTabWidget()->currentWebView(); if (!current) return; auto page = current->page(); page->findText(searchText); } void FindInPageBar::findPrevious() { auto searchText = mp_findLineEdit->text(); if (searchText.isEmpty()) return; auto current = KiwixApp::instance()->getTabWidget()->currentWebView(); if (!current) return; auto page = current->page(); page->findText(searchText, QWebEnginePage::FindBackward); } void FindInPageBar::findClose() { auto current = KiwixApp::instance()->getTabWidget()->currentWebView(); if (!current) return; auto page = current->page(); page->findText(""); current->setFocus(); close(); } void FindInPageBar::keyPressEvent(QKeyEvent *event) { switch(event->key()) { case Qt::Key_Escape: findClose(); break; default: QWidget::keyPressEvent(event); } }kiwix-desktop-2.4.1/src/findinpagebar.h000066400000000000000000000010711473106011000200410ustar00rootroot00000000000000#ifndef FINDINPAGEBAR_H #define FINDINPAGEBAR_H #include #include namespace Ui { class FindInPageBar; } class FindInPageBar : public QFrame { Q_OBJECT public: explicit FindInPageBar(QWidget *parent = nullptr); ~FindInPageBar(); QLineEdit* getFindLineEdit() { return mp_findLineEdit; }; public slots: void findNext(); void findPrevious(); void findClose(); protected: void keyPressEvent(QKeyEvent *event); private: Ui::FindInPageBar *mp_ui; QLineEdit *mp_findLineEdit; }; #endif // FINDINPAGEBAR_H kiwix-desktop-2.4.1/src/findinpagebar.ui000066400000000000000000000042141473106011000202310ustar00rootroot00000000000000 FindInPageBar 0 0 833 43 0 0 Frame Find in page :/icons/search_forward.svg:/icons/search_forward.svg true :/icons/search_backward.svg:/icons/search_backward.svg true Qt::Horizontal 350 20 :/icons/close.svg:/icons/close.svg true kiwix-desktop-2.4.1/src/flowlayout.cpp000066400000000000000000000147661473106011000200270ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "flowlayout.h" #include #include //! [1] FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) { setContentsMargins(margin, margin, margin, margin); } FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) : m_hSpace(hSpacing), m_vSpace(vSpacing) { setContentsMargins(margin, margin, margin, margin); } //! [1] //! [2] FlowLayout::~FlowLayout() { QLayoutItem *item; while ((item = takeAt(0))) delete item; } //! [2] //! [3] void FlowLayout::addItem(QLayoutItem *item) { itemList.append(item); } //! [3] //! [4] int FlowLayout::horizontalSpacing() const { if (m_hSpace >= 0) { return m_hSpace; } else { return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); } } int FlowLayout::verticalSpacing() const { if (m_vSpace >= 0) { return m_vSpace; } else { return smartSpacing(QStyle::PM_LayoutVerticalSpacing); } } //! [4] //! [5] int FlowLayout::count() const { return itemList.size(); } QLayoutItem *FlowLayout::itemAt(int index) const { return itemList.value(index); } QLayoutItem *FlowLayout::takeAt(int index) { if (index >= 0 && index < itemList.size()) return itemList.takeAt(index); return nullptr; } //! [5] //! [6] Qt::Orientations FlowLayout::expandingDirections() const { return { }; } //! [6] //! [7] bool FlowLayout::hasHeightForWidth() const { return true; } int FlowLayout::heightForWidth(int width) const { int height = doLayout(QRect(0, 0, width, 0), true); return height; } //! [7] //! [8] void FlowLayout::setGeometry(const QRect &rect) { QLayout::setGeometry(rect); doLayout(rect, false); } QSize FlowLayout::sizeHint() const { return minimumSize(); } QSize FlowLayout::minimumSize() const { QSize size; for (const QLayoutItem *item : std::as_const(itemList)) size = size.expandedTo(item->minimumSize()); const QMargins margins = contentsMargins(); size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); return size; } //! [8] //! [9] int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); int x = effectiveRect.x(); int y = effectiveRect.y(); int lineHeight = 0; //! [9] //! [10] for (QLayoutItem *item : std::as_const(itemList)) { const QWidget *wid = item->widget(); int spaceX = horizontalSpacing(); if (spaceX == -1) spaceX = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); int spaceY = verticalSpacing(); if (spaceY == -1) spaceY = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); //! [10] //! [11] int nextX = x + item->sizeHint().width() + spaceX; if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { x = effectiveRect.x(); y = y + lineHeight + spaceY; nextX = x + item->sizeHint().width() + spaceX; lineHeight = 0; } if (!testOnly) item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); } return y + lineHeight - rect.y() + bottom; } //! [11] //! [12] int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const { QObject *parent = this->parent(); if (!parent) { return -1; } else if (parent->isWidgetType()) { QWidget *pw = static_cast(parent); return pw->style()->pixelMetric(pm, nullptr, pw); } else { return static_cast(parent)->spacing(); } } //! [12] void FlowLayout::insertWidget(int index, QWidget *w) { addWidget(w); if (index < 0) index = 0; if (index >= itemList.size()) index = itemList.size() - 1; itemList.move(indexOf(w), index); } kiwix-desktop-2.4.1/src/flowlayout.h000066400000000000000000000070211473106011000174560ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FLOWLAYOUT_H #define FLOWLAYOUT_H #include #include #include //! [0] class FlowLayout : public QLayout { Q_OBJECT public: explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); ~FlowLayout(); void addItem(QLayoutItem *item) override; int horizontalSpacing() const; int verticalSpacing() const; Qt::Orientations expandingDirections() const override; bool hasHeightForWidth() const override; int heightForWidth(int) const override; int count() const override; QLayoutItem *itemAt(int index) const override; QSize minimumSize() const override; void setGeometry(const QRect &rect) override; QSize sizeHint() const override; QLayoutItem *takeAt(int index) override; void insertWidget(int index, QWidget *w); private: int doLayout(const QRect &rect, bool testOnly) const; int smartSpacing(QStyle::PixelMetric pm) const; QList itemList; int m_hSpace; int m_vSpace; }; //! [0] #endif // FLOWLAYOUT_H kiwix-desktop-2.4.1/src/fullscreennotification.cpp000066400000000000000000000027471473106011000223670ustar00rootroot00000000000000#include "fullscreennotification.h" #include "kiwixapp.h" #include #include #include FullScreenNotification::FullScreenNotification(QWidget *parent) : QLabel(parent) , m_previouslyVisible(false) { setText(gt("fullscreen-notification")); setStyleSheet( "font-size: 24px;" "color: white;" "background-color: black;" "border-color: white;" "border-width: 2px;" "border-style: solid;" "padding: 100px"); setAttribute(Qt::WA_TransparentForMouseEvents); auto effect = new QGraphicsOpacityEffect; effect->setOpacity(1); setGraphicsEffect(effect); auto animations = new QSequentialAnimationGroup(this); animations->addPause(3000); auto opacityAnimation = new QPropertyAnimation(effect, "opacity", animations); opacityAnimation->setDuration(2000); opacityAnimation->setStartValue(1.0); opacityAnimation->setEndValue(0.0); opacityAnimation->setEasingCurve(QEasingCurve::OutQuad); animations->addAnimation(opacityAnimation); connect(this, &FullScreenNotification::shown, [animations](){ animations->start(); }); connect(animations, &QAbstractAnimation::finished, [this](){ this->hide(); }); } void FullScreenNotification::showEvent(QShowEvent *event) { QLabel::showEvent(event); if (!m_previouslyVisible && isVisible()) emit shown(); m_previouslyVisible = isVisible(); }kiwix-desktop-2.4.1/src/fullscreennotification.h000066400000000000000000000005671473106011000220320ustar00rootroot00000000000000#ifndef FULLSCREENNOTIFICATION_H #define FULLSCREENNOTIFICATION_H #include class FullScreenNotification : public QLabel { Q_OBJECT public: FullScreenNotification(QWidget *parent = nullptr); protected: void showEvent(QShowEvent *event) override; signals: void shown(); private: bool m_previouslyVisible; }; #endif // FULLSCREENNOTIFICATION_Hkiwix-desktop-2.4.1/src/fullscreenwindow.cpp000066400000000000000000000024251473106011000212010ustar00rootroot00000000000000class QMenu; #include "fullscreenwindow.h" #include FullScreenWindow::FullScreenWindow(QWebEngineView *oldView, QWidget *parent) : QWidget(parent) , m_view(new QWebEngineView(this)) , m_notification(new FullScreenNotification(this)) , m_oldView(oldView) , m_oldGeometry(oldView->window()->geometry()) { m_view->stackUnder(m_notification); auto exitAction = new QAction(this); exitAction->setShortcut(Qt::Key_Escape); connect(exitAction, &QAction::triggered, [this]() { m_view->triggerPageAction(QWebEnginePage::ExitFullScreen); }); addAction(exitAction); m_view->setPage(m_oldView->page()); setGeometry(m_oldGeometry); showFullScreen(); m_oldView->window()->hide(); } FullScreenWindow::~FullScreenWindow() { m_oldView->setPage(m_view->page()); m_oldView->window()->setGeometry(m_oldGeometry); m_oldView->window()->show(); hide(); } void FullScreenWindow::resizeEvent(QResizeEvent *event) { QRect viewGeometry(QPoint(0, 0), size()); m_view->setGeometry(viewGeometry); QRect notificationGeometry(QPoint(0, 0), m_notification->sizeHint()); notificationGeometry.moveCenter(viewGeometry.center()); m_notification->setGeometry(notificationGeometry); QWidget::resizeEvent(event); } kiwix-desktop-2.4.1/src/fullscreenwindow.h000066400000000000000000000012061473106011000206420ustar00rootroot00000000000000#ifndef FULLSCREENWINDOW_H #define FULLSCREENWINDOW_H class QMenu; #include #include #include "fullscreennotification.h" QT_BEGIN_NAMESPACE class QWebEngineView; QT_END_NAMESPACE class FullScreenNotification; class FullScreenWindow : public QWidget { Q_OBJECT public: explicit FullScreenWindow(QWebEngineView *oldView, QWidget *parent = nullptr); ~FullScreenWindow(); protected: void resizeEvent(QResizeEvent *event) override; private: QWebEngineView *m_view; FullScreenNotification *m_notification; QWebEngineView *m_oldView; QRect m_oldGeometry; }; #endif // FULLSCREENWINDOW_H kiwix-desktop-2.4.1/src/kconstants.h000066400000000000000000000001341473106011000174360ustar00rootroot00000000000000#ifndef KCONSTANTS_H #define KCONSTANTS_H #define SYSTEMTITLEBAR 1 #endif // KCONSTANTS_H kiwix-desktop-2.4.1/src/kiwixapp.cpp000066400000000000000000000540101473106011000174400ustar00rootroot00000000000000#include "kiwixapp.h" #include "zim/error.h" #include "zim/version.h" #include "kiwix/tools.h" #include "kiwix/version.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include #endif const QString DEFAULT_SAVE_DIR = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); //////////////////////////////////////////////////////////////////////////////// // KiwixApp //////////////////////////////////////////////////////////////////////////////// KiwixApp::KiwixApp(int& argc, char *argv[]) : QtSingleApplication("kiwix-desktop", argc, argv), m_profile(), m_libraryDirectory(findLibraryDirectory()), m_library(m_libraryDirectory), mp_manager(nullptr), mp_mainWindow(nullptr), mp_nameMapper(std::make_shared(m_library.getKiwixLibrary(), false)), m_server(m_library.getKiwixLibrary(), mp_nameMapper), mp_session(nullptr) { /* Place session file in our global library path */ QDir dir(m_libraryDirectory); mp_session = new QSettings(dir.filePath("kiwix-desktop.session"), QSettings::IniFormat, this); try { m_translation.setTranslation(QLocale()); } catch (std::exception& e) { QMessageBox::critical(nullptr, "Translation error", e.what()); return; } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QString path = QLibraryInfo::location(QLibraryInfo::TranslationsPath); #else QString path = QLibraryInfo::path(QLibraryInfo::TranslationsPath); #endif loadAndInstallTranslations(m_qtTranslator, "qt", path); loadAndInstallTranslations(m_appTranslator, "kiwix-desktop", ":/i18n/"); QFontDatabase::addApplicationFont(":/fonts/Selawik/selawkb.ttf"); QFontDatabase::addApplicationFont(":/fonts/Selawik/selawkl.ttf"); QFontDatabase::addApplicationFont(":/fonts/Selawik/selawksb.ttf"); QFontDatabase::addApplicationFont(":/fonts/Selawik/selawksl.ttf"); QFontDatabase::addApplicationFont(":/fonts/Selawik/selawk.ttf"); setFont(QFont("Selawik")); } void KiwixApp::loadAndInstallTranslations(QTranslator& translator, const QString& filename, const QString& directory) { if (translator.load(QLocale(), filename, "_", directory)) { installTranslator(&translator); } } void KiwixApp::init() { mp_manager = new ContentManager(&m_library); mp_manager->setLocal(!m_library.getBookIds().isEmpty()); auto icon = QIcon(); icon.addFile(":/icons/kiwix-app-icons-square.svg"); setWindowIcon(icon); setApplicationName("Kiwix"); setDesktopFileName("kiwix.desktop"); setStyleSheet(parseStyleFromFile(":/css/style.css")); createActions(); mp_mainWindow = new MainWindow; getTabWidget()->setContentManagerView(mp_manager->getView()); const auto newTabAction = getAction(KiwixApp::NewTabAction); getTabWidget()->setNewTabButton(newTabAction); connect(newTabAction, &QAction::triggered, this, &KiwixApp::newTab); postInit(); mp_errorDialog = new QErrorMessage(mp_mainWindow); setActivationWindow(mp_mainWindow); mp_mainWindow->show(); #ifdef Q_OS_WIN QWindow *window = mp_mainWindow->windowHandle(); if (window) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QWindowsWindowFunctions::setHasBorderInFullScreen(window, true); #else HWND handle = reinterpret_cast(window->winId()); SetWindowLongPtr(handle, GWL_STYLE, GetWindowLongPtr(handle, GWL_STYLE) | WS_BORDER); #endif } #endif connect(this, &QtSingleApplication::messageReceived, this, [=](const QString &message) { if (!message.isEmpty()) { this->openZimFile(message); } }); restoreWindowState(); } void KiwixApp::setupDirectoryMonitoring() { QString monitorDir = m_settingsManager.getMonitorDir(); QString downloadDir = m_settingsManager.getDownloadDir(); auto dirList = QSet({monitorDir, downloadDir}); mp_manager->setMonitoredDirectories(dirList); } KiwixApp::~KiwixApp() { m_server.stop(); if (mp_manager) { delete mp_manager; } if (mp_mainWindow) { delete mp_mainWindow; } } void KiwixApp::newTab() { getTabWidget()->createNewTab(true, false); auto& searchBarLineEdit = getSearchBar().getLineEdit(); searchBarLineEdit.setFocus(Qt::MouseFocusReason); searchBarLineEdit.clear(); searchBarLineEdit.clearSuggestions(); searchBarLineEdit.hideSuggestions(); } QString KiwixApp::findLibraryDirectory() { auto dataDir = getDataDirectory(); if (isPortableMode()) return dataDir; auto libraryFile = QFileInfo(dataDir, "library.xml"); if (libraryFile.exists()) return dataDir; // Check if this is a pre-release version with wrong directory. auto oldDataDir = QDir(dataDir); oldDataDir.cdUp(); libraryFile = QFileInfo(oldDataDir, "library.xml"); if (libraryFile.exists()) { // We have to move all zim files and xml file to the new dataDir for (auto& fileInfo: oldDataDir.entryInfoList({"*.zim", "library*.xml"})) { auto newFileInfo = QFileInfo(dataDir, fileInfo.fileName()); QFile::rename(fileInfo.absoluteFilePath(), newFileInfo.absoluteFilePath()); } // Aria2 stores information about the current download using absolute path. // Let's remove everything. User will lose its ongoing download but it should be pretty rare. for (auto& fileInfo: oldDataDir.entryInfoList({"*.aria2", "*.meta4", "kiwix.session"})) QFile::remove(fileInfo.absoluteFilePath()); } // This is a first launch return dataDir; } void KiwixApp::restoreTabs() { QStringList tabsToOpen = mp_session->value("reopenTabList").toStringList(); /* Restart a new session to prevent duplicate records in openURL */ saveListOfOpenTabs(); if (m_settingsManager.getReopenTab()) { for (const auto &zimUrl : tabsToOpen) { if (zimUrl == "SettingsTab") getTabWidget()->openOrSwitchToSettingsTab(); else if (zimUrl.isEmpty()) getTabWidget()->createNewTab(true, true); else openUrl(QUrl(zimUrl)); } } /* Restore current tab index. */ getTabWidget()->setCurrentIndex(mp_session->value("currentTabIndex", 0).toInt()); } KiwixApp *KiwixApp::instance() { return static_cast(QApplication::instance()); } QString gt(const QString &key) { return KiwixApp::instance()->getText(key); } void KiwixApp::openZimFile(const QString &zimfile) { QString _zimfile; if (zimfile.isEmpty()) { QString importDir = mp_session->value("zim-import-dir").toString(); if (importDir.isEmpty()) { importDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); if (importDir.isEmpty()) { importDir = QDir::currentPath(); } } _zimfile = QFileDialog::getOpenFileName(getMainWindow(), gt("open-zim"), importDir, "ZIM Files (*.zim);;Split ZIM Files (*.zimaa)"); if (_zimfile.isEmpty()) { return; } _zimfile = QDir::toNativeSeparators(_zimfile); QFileInfo fileInfo(_zimfile); mp_session->setValue("zim-import-dir", fileInfo.absolutePath()); } QString zimId; const auto &validZimFile = zimfile.isEmpty() ? _zimfile : zimfile; try { zimId = m_library.openBookFromPath(validZimFile); } catch (const std::exception& e) { auto text = gt("zim-open-fail-text"); text = text.replace("{{ZIM}}", validZimFile); showMessage(text, gt("zim-open-fail-title"), QMessageBox::Warning); return; } openUrl(QUrl("zim://"+zimId+".zim/")); } void KiwixApp::printPage() { if(!getTabWidget()->currentZimView()) return; QPrinter* printer = new QPrinter(); QPrintDialog printDialog(printer, mp_mainWindow); printDialog.setStyle(nullptr); printDialog.setStyleSheet(""); if (printDialog.exec() == QDialog::Accepted) { auto webview = getTabWidget()->currentWebView(); if(!webview) return; const auto onPrintFinished = [=](bool success) { if (!success) { showMessage(gt("print-page-error"), gt("error-title"), QMessageBox::Critical); } delete printer; }; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) webview->page()->print(printer, onPrintFinished); #else webview->print(printer); connect(webview, &QWebEngineView::printFinished, this, onPrintFinished); #endif } } void KiwixApp::openUrl(const QString &url, bool newTab) { openUrl(QUrl(url), newTab); } void KiwixApp::openUrl(const QUrl &url, bool newTab) { getTabWidget()->openUrl(url, newTab); } void KiwixApp::openRandomUrl(bool newTab) { auto zimId = getTabWidget()->currentZimId(); if (zimId.isEmpty()) { return; } try { auto archive = m_library.getArchive(zimId); auto entry = archive->getRandomEntry(); QUrl url; url.setScheme("zim"); url.setHost(zimId + ".zim"); url.setPath("/" + QString::fromStdString(entry.getPath())); openUrl(url, newTab); } catch (const zim::EntryNotFound& e) { showMessage(gt("random-article-error"), gt("error-title"), QMessageBox::Information); } catch (std::out_of_range& e) { showMessage(gt("error-archive"), gt("error-title"), QMessageBox::Information); } } void KiwixApp::showMessage(const QString &message, const QString &title, const enum QMessageBox::Icon &icon) { QMessageBox msgBox( icon, //Icon title, //Title message, //Text QMessageBox::Ok //Buttons ); msgBox.exec(); } QAction *KiwixApp::getAction(KiwixApp::Actions action) { return mpa_actions[action]; } bool KiwixApp::isCurrentArticleBookmarked() { auto zimId = getTabWidget()->currentZimId().toStdString(); if (zimId.empty()) { return false; } auto url = getTabWidget()->currentArticleUrl().toStdString(); for (auto& bookmark: getLibrary()->getBookmarks()) { if (bookmark.getBookId() == zimId && bookmark.getUrl() == url) { return true; } } return false; } void KiwixApp::setMonitorDir(const QString &dir) { m_settingsManager.setMonitorDir(dir); setupDirectoryMonitoring(); } #define CREATE_ACTION(ID, TEXT) \ mpa_actions[ID] = new QAction(TEXT) #define CREATE_ACTION_ICON(ID, ICON, TEXT) \ mpa_actions[ID] = new QAction(QIcon(":/icons/" ICON ".svg"), TEXT); #define SET_SHORTCUT(ID, TEXT, SHORTCUT) \ mpa_actions[ID]->setShortcut(SHORTCUT); \ mpa_actions[ID]->setToolTip(TEXT + " (" + QKeySequence(SHORTCUT).toString() + ")" ) #define CREATE_ACTION_SHORTCUT(ID, TEXT, SHORTCUT) \ CREATE_ACTION(ID, TEXT); \ SET_SHORTCUT(ID, TEXT, SHORTCUT) #define CREATE_ACTION_ICON_SHORTCUT(ID, ICON, TEXT, SHORTCUT) \ CREATE_ACTION_ICON(ID, ICON, TEXT) \ SET_SHORTCUT(ID, TEXT, SHORTCUT) #define CREATE_ACTION_ONOFF_ICON_SHORTCUT(ID, ON_ICON, OFF_ICON, TEXT, SHORTCUT) \ CREATE_ACTION(ID, TEXT); \ SET_SHORTCUT(ID, TEXT, SHORTCUT); \ mpa_actions[ID]->setCheckable(true); \ { QIcon icon; \ icon.addPixmap(QPixmap(":/icons/" ON_ICON ".svg"), QIcon::Normal, QIcon::On); \ icon.addPixmap(QPixmap(":/icons/" OFF_ICON, ".svg"), QIcon::Normal, QIcon::Off); \ mpa_actions[ID]->setIcon(icon); } #define SET_SHORTCUTS(ID, TEXT, SHORTCUTS) \ mpa_actions[ID]->setShortcuts(SHORTCUTS); \ mpa_actions[ID]->setToolTip(TEXT + " (" + SHORTCUTS.first().toString() + ")" ) #define CREATE_ACTION_SHORTCUTS(ID, TEXT, SHORTCUTS) \ CREATE_ACTION(ID, TEXT); \ SET_SHORTCUTS(ID, TEXT, SHORTCUTS) #define CREATE_ACTION_ICON_SHORTCUTS(ID, ICON, TEXT, SHORTCUTS) \ CREATE_ACTION_ICON(ID, ICON, TEXT) \ SET_SHORTCUTS(ID, TEXT, SHORTCUTS) #define HIDE_ACTION(ID) mpa_actions[ID]->setVisible(false) #define DISABLE_ACTION(ID) mpa_actions[ID]->setDisabled(true) void KiwixApp::createActions() { CREATE_ACTION_ICON_SHORTCUT(KiwixServeAction, "share", gt("local-kiwix-server"), QKeySequence(Qt::CTRL | Qt::Key_I)); CREATE_ACTION_ICON_SHORTCUT(RandomArticleAction, "random", gt("random-article"), QKeySequence(Qt::CTRL | Qt::Key_R)); connect(mpa_actions[RandomArticleAction], &QAction::triggered, this, [=]() { this->openRandomUrl(false); }); CREATE_ACTION_ICON_SHORTCUT(OpenHomePageAction, "home-button", gt("home-page"), QKeySequence(Qt::ALT | Qt::Key_Home)); if (QGuiApplication::isLeftToRight()) { CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-left", gt("back"), QKeySequence(Qt::ALT | Qt::Key_Left)); CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-right", gt("forward"), QKeySequence(Qt::ALT | Qt::Key_Right)); CREATE_ACTION_ICON(ScrollNextTabAction, "caret-right-solid", gt("scroll-next-tab")); CREATE_ACTION_ICON(ScrollPreviousTabAction, "caret-left-solid", gt("scroll-previous-tab")); } else { CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-right", gt("back"), QKeySequence(Qt::ALT | Qt::Key_Right)); CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-left", gt("forward"), QKeySequence(Qt::ALT | Qt::Key_Left)); CREATE_ACTION_ICON(ScrollNextTabAction, "caret-left-solid", gt("scroll-next-tab")); CREATE_ACTION_ICON(ScrollPreviousTabAction, "caret-right-solid", gt("scroll-previous-tab")); } DISABLE_ACTION(HistoryBackAction); DISABLE_ACTION(HistoryForwardAction); CREATE_ACTION_SHORTCUT(ReadArticleAction, gt("read-article"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_A)); CREATE_ACTION_SHORTCUT(ReadTextAction, gt("read-text"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_S)); CREATE_ACTION_SHORTCUT(ReadStopAction, gt("read-stop"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_X)); CREATE_ACTION_SHORTCUT(ToggleTTSLanguageAction, gt("select-read-language"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_L)); CREATE_ACTION_SHORTCUT(ToggleTTSVoiceAction, gt("select-read-voice"), QKeySequence(Qt::ALT | Qt::SHIFT | Qt::Key_V)); mpa_actions[ToggleTTSLanguageAction]->setCheckable(true); mpa_actions[ToggleTTSVoiceAction]->setCheckable(true); CREATE_ACTION_ICON_SHORTCUT(PrintAction, "print", gt("print"), QKeySequence::Print); connect(mpa_actions[PrintAction], &QAction::triggered, this, &KiwixApp::printPage); CREATE_ACTION_ICON_SHORTCUT(NewTabAction,"new-tab-icon", gt("new-tab"), QKeySequence::AddTab); CREATE_ACTION_SHORTCUTS(CloseCurrentTabAction, gt("close-tab"), QList({QKeySequence(Qt::CTRL | Qt::Key_F4), QKeySequence(Qt::CTRL | Qt::Key_W)})); CREATE_ACTION_SHORTCUT(ReopenClosedTabAction, gt("reopen-closed-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_T)); HIDE_ACTION(ReopenClosedTabAction); CREATE_ACTION_SHORTCUT(BrowseLibraryAction, gt("browse-library"), QKeySequence(Qt::CTRL | Qt::Key_E)); HIDE_ACTION(BrowseLibraryAction); CREATE_ACTION_ICON_SHORTCUT(OpenFileAction, "open-file", gt("open-file"), QKeySequence::Open); connect(mpa_actions[OpenFileAction], &QAction::triggered, this, [=]() { openZimFile(); }); CREATE_ACTION(OpenRecentAction, gt("open-recent")); HIDE_ACTION(OpenRecentAction); CREATE_ACTION_SHORTCUT(SavePageAsAction, gt("save-page-as"), QKeySequence::Save); CREATE_ACTION_SHORTCUTS(SearchArticleAction, gt("search-article"), QList({QKeySequence(Qt::Key_F6), QKeySequence(Qt::CTRL | Qt::Key_L), QKeySequence(Qt::ALT | Qt::Key_D)})); CREATE_ACTION_SHORTCUT(SearchLibraryAction, gt("search-in-library"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_R)); HIDE_ACTION(SearchLibraryAction); CREATE_ACTION(FindInPageAction, gt("find-in-page")); mpa_actions[FindInPageAction]->setShortcuts({QKeySequence::Find, Qt::Key_F3}); connect(mpa_actions[FindInPageAction], &QAction::triggered, this, [=]() { getTabWidget()->openFindInPageBar(); }); const auto fullScreenKeySeq = QKeySequence(QKeySequence::FullScreen).isEmpty() ? QKeySequence(Qt::Key_F11) : QKeySequence(QKeySequence::FullScreen); CREATE_ACTION_ICON_SHORTCUT(ToggleFullscreenAction, "full-screen-enter", gt("set-fullscreen"), fullScreenKeySeq); connect(mpa_actions[ToggleFullscreenAction], &QAction::toggled, this, [=](bool checked) { auto action = mpa_actions[ToggleFullscreenAction]; action->setIcon( QIcon(checked ? ":/icons/full-screen-exit.svg" : ":/icons/full-screen-enter.svg")); action->setText(checked ? gt("quit-fullscreen") : gt("set-fullscreen")); }); mpa_actions[ToggleFullscreenAction]->setCheckable(true); CREATE_ACTION_ICON_SHORTCUT(ToggleTOCAction, "toc", gt("table-of-content"), QKeySequence(Qt::CTRL | Qt::Key_M)); mpa_actions[ToggleTOCAction]->setCheckable(true); CREATE_ACTION_ICON_SHORTCUT(OpenMultiZimAction, "filter", gt("search-options"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_L)); CREATE_ACTION_ONOFF_ICON_SHORTCUT(ToggleReadingListAction, "reading-list-active", "reading-list", gt("reading-list"), QKeySequence(Qt::CTRL | Qt::Key_B)); CREATE_ACTION(ExportReadingListAction, gt("export-reading-list")); CREATE_ACTION(ImportReadingListAction, gt("import-reading-list")); CREATE_ACTION_ONOFF_ICON_SHORTCUT(ToggleAddBookmarkAction, "star-active", "star", gt("add-bookmark"), QKeySequence(Qt::CTRL | Qt::Key_D)); CREATE_ACTION_SHORTCUTS(ZoomInAction, gt("zoom-in"), QList({QKeySequence::ZoomIn, QKeySequence(Qt::CTRL | Qt::Key_Equal)})); CREATE_ACTION_SHORTCUT(ZoomOutAction, gt("zoom-out"), QKeySequence::ZoomOut); CREATE_ACTION_SHORTCUT(ZoomResetAction, gt("zoom-reset"), QKeySequence(Qt::CTRL | Qt::Key_0)); CREATE_ACTION_SHORTCUT(NextTabAction, gt("next-tab"), QKeySequence(Qt::CTRL | Qt::Key_Tab)); CREATE_ACTION_SHORTCUT(PreviousTabAction, gt("previous-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab)); CREATE_ACTION_SHORTCUT(HelpAction, gt("help"), QKeySequence::HelpContents); HIDE_ACTION(HelpAction); CREATE_ACTION(FeedbackAction, gt("feedback")); HIDE_ACTION(FeedbackAction); CREATE_ACTION(ReportBugAction, gt("report-a-bug")); HIDE_ACTION(ReportBugAction); CREATE_ACTION(RequestFeatureAction, gt("request-a-feature")); HIDE_ACTION(RequestFeatureAction); CREATE_ACTION(AboutAction, gt("about-kiwix")); CREATE_ACTION_ICON_SHORTCUT(SettingAction, "settings", gt("settings"), QKeySequence(Qt::Key_F12)); CREATE_ACTION_ICON_SHORTCUT(DonateAction, "donate", gt("donate-to-support-kiwix"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D)); CREATE_ACTION_ICON_SHORTCUT(ExitAction, "exit", gt("exit"), QKeySequence::Quit); } void KiwixApp::postInit() { connect(getTabWidget(), &TabBar::tabDisplayed, this, &KiwixApp::handleItemsState); emit(m_library.booksChanged()); connect(&m_library, &Library::booksChanged, this, &KiwixApp::updateNameMapper); handleItemsState(TabType::LibraryTab); } void KiwixApp::handleItemsState(TabType tabType) { auto libraryOrSettingsTab = (tabType == TabType::LibraryTab || tabType == TabType::SettingsTab); auto notBookmarkableTab = libraryOrSettingsTab || getTabWidget()->currentArticleUrl().isEmpty(); auto app = KiwixApp::instance(); app->getAction(KiwixApp::ToggleTOCAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::ToggleReadingListAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::ToggleAddBookmarkAction)->setDisabled(notBookmarkableTab); app->getAction(KiwixApp::FindInPageAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::ZoomInAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::ZoomOutAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::ZoomResetAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::RandomArticleAction)->setDisabled(libraryOrSettingsTab); app->getAction(KiwixApp::OpenHomePageAction)->setDisabled(libraryOrSettingsTab); /* Non-Zim tabs are not bookmarkable therefore never in reading list. */ if (notBookmarkableTab) app->getAction(KiwixApp::ToggleAddBookmarkAction)->setChecked(false); } void KiwixApp::updateNameMapper() { mp_nameMapper->update(); } void KiwixApp::printVersions(std::ostream& out) { out << version.toStdString() << std::endl; out << "+ libqt (compile time) " << QT_VERSION_STR << std::endl; out << "+ libqt (run time) " << qVersion() << std::endl << std::endl; kiwix::printVersions(out); out << std::endl; zim::printVersions(out); } QString KiwixApp::parseStyleFromFile(QString filePath) { QFile file(filePath); file.open(QFile::ReadOnly); QString styleSheet = QString(file.readAll()); file.close(); return styleSheet; } void KiwixApp::saveListOfOpenTabs() { return mp_session->setValue("reopenTabList", getTabWidget()->getTabUrls()); } void KiwixApp::saveWindowState() { mp_session->setValue("geometry", getMainWindow()->saveGeometry()); mp_session->setValue("windowState", getMainWindow()->saveState()); } void KiwixApp::saveVoiceName(const QString& langName, const QString& voiceName) { mp_session->setValue("voice/" + langName, voiceName); } void KiwixApp::restoreWindowState() { getMainWindow()->restoreGeometry(mp_session->value("geometry").toByteArray()); getMainWindow()->restoreState(mp_session->value("windowState").toByteArray()); } void KiwixApp::saveCurrentTabIndex() { return mp_session->setValue("currentTabIndex", getTabWidget()->currentIndex()); } void KiwixApp::savePrevSaveDir(const QString &prevSaveDir) { mp_session->setValue("prevSaveDir", prevSaveDir); } QString KiwixApp::getSavedVoiceName(const QString& langName) const { return mp_session->value("voice/" + langName, "").toString(); } QString KiwixApp::getPrevSaveDir() const { QString prevSaveDir = mp_session->value("prevSaveDir", DEFAULT_SAVE_DIR).toString(); QDir dir(prevSaveDir); return dir.exists() ? prevSaveDir : DEFAULT_SAVE_DIR; } kiwix-desktop-2.4.1/src/kiwixapp.h000066400000000000000000000105201473106011000171030ustar00rootroot00000000000000#ifndef KIWIXAPP_H #define KIWIXAPP_H #include "library.h" #include "contentmanager.h" #include "tabbar.h" #include "mainwindow.h" #include "kiwix/downloader.h" #include #include "kprofile.h" #include "settingsmanager.h" #include "translation.h" #include #include #include #include #include #include #include #include typedef TabBar::TabType TabType; class KiwixApp : public QtSingleApplication { Q_OBJECT public: enum Actions { KiwixServeAction, RandomArticleAction, OpenHomePageAction, PrintAction, NewTabAction, CloseCurrentTabAction, ReopenClosedTabAction, BrowseLibraryAction, OpenFileAction, OpenRecentAction, OpenMultiZimAction, SavePageAsAction, SearchArticleAction, SearchLibraryAction, FindInPageAction, ToggleFullscreenAction, ToggleTOCAction, ToggleReadingListAction, ToggleAddBookmarkAction, ToggleTTSLanguageAction, ToggleTTSVoiceAction, ZoomInAction, ZoomOutAction, ZoomResetAction, NextTabAction, PreviousTabAction, HistoryBackAction, HistoryForwardAction, ReadTextAction, ReadArticleAction, ReadStopAction, HelpAction, FeedbackAction, ReportBugAction, RequestFeatureAction, AboutAction, SettingAction, DonateAction, ExitAction, ExportReadingListAction, ImportReadingListAction, ScrollPreviousTabAction, ScrollNextTabAction, MAX_ACTION }; KiwixApp(int& argc, char *argv[]); virtual ~KiwixApp(); static KiwixApp* instance(); void init(); void openRandomUrl(bool newTab=true); void showMessage(const QString& message, const QString& title, const enum QMessageBox::Icon& icon); KProfile* getProfile() { return &m_profile; } Library* getLibrary() { return &m_library; } MainWindow* getMainWindow() { return mp_mainWindow; } ContentManager* getContentManager() { return mp_manager; } TabBar* getTabWidget() { return getMainWindow()->getTabBar(); } SearchBar& getSearchBar() { return getMainWindow()->getTopWidget()->getSearchBar(); } QAction* getAction(Actions action); QString getLibraryDirectory() { return m_libraryDirectory; }; kiwix::Server* getLocalServer() { return &m_server; } SettingsManager* getSettingsManager() { return &m_settingsManager; }; QString getText(const QString &key) { return m_translation.getText(key); }; void setMonitorDir(const QString &dir); bool isCurrentArticleBookmarked(); QString parseStyleFromFile(QString filePath); void saveListOfOpenTabs(); void saveWindowState(); void saveVoiceName(const QString& langName, const QString& voiceName); void restoreWindowState(); void saveCurrentTabIndex(); void savePrevSaveDir(const QString& prevSaveDir); QString getSavedVoiceName(const QString& langName) const; QString getPrevSaveDir() const; void restoreTabs(); void setupDirectoryMonitoring(); public slots: void newTab(); void openZimFile(const QString& zimfile=""); void openUrl(const QString& url, bool newTab=true); void openUrl(const QUrl& url, bool newTab=true); void printPage(); void handleItemsState(TabType); void updateNameMapper(); void printVersions(std::ostream& out = std::cout); protected: void createActions(); void postInit(); private: QTranslator m_qtTranslator, m_appTranslator; SettingsManager m_settingsManager; KProfile m_profile; QString m_libraryDirectory; Library m_library; ContentManager* mp_manager; MainWindow* mp_mainWindow; QErrorMessage* mp_errorDialog; std::shared_ptr mp_nameMapper; kiwix::Server m_server; Translation m_translation; QSettings* mp_session; QAction* mpa_actions[MAX_ACTION]; QString findLibraryDirectory(); void loadAndInstallTranslations(QTranslator& translator, const QString& filename, const QString& directory); }; QString gt(const QString &key); #define _STR(...) # __VA_ARGS__ #define STR(X) _STR(X) static QString version = STR(VERSION); #endif // KIWIXAPP_H kiwix-desktop-2.4.1/src/kiwixchoicebox.cpp000066400000000000000000000225721473106011000206330ustar00rootroot00000000000000#include "kiwixchoicebox.h" #include "ui_kiwixchoicebox.h" #include "klistwidgetitem.h" #include "kiwixapp.h" #include "choiceitem.h" #include #include "choiceitem.h" #include "kiwixapp.h" #include #include #include #include #include "kiwixlineedit.h" #include "kiwixlistwidget.h" KiwixChoiceBox::KiwixChoiceBox(QWidget *parent) : QWidget(parent), ui(new Ui::kiwixchoicebox) { ui->setupUi(this); auto styleSheet = KiwixApp::instance()->parseStyleFromFile(":/css/choiceBox.css"); this->setStyleSheet(styleSheet); ui->clearButton->setText(gt("clear")); ui->clearButton->setToolTip(gt("clear-filter")); choiceLabel = ui->choiceLabel; choiceLabel->setText(gt("undefined")); choiceSelector = new KiwixListWidget(parent); choiceSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); choiceSelector->setMaximumWidth(250); // allow maximum 6 elements choiceSelector->setMaximumHeight(KListWidgetItem::getItemHeight() * 6); choiceSelector->setCursor(Qt::PointingHandCursor); choiceSelector->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); choiceSelector->setFocusPolicy(Qt::FocusPolicy::NoFocus); choiceSelector->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); choiceSelector->setStyleSheet(styleSheet); choiceSelector->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); currentChoicesLayout = new FlowLayout(ui->currentChoices, 4, 2, 2); searcher = new KiwixLineEdit(); searcher->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); searcher->setFixedWidth(20); currentChoicesLayout->addWidget(searcher); connect(choiceSelector, &QListWidget::itemPressed, this, [=](QListWidgetItem *item) { searcher->clear(); if (item->isSelected()) { addSelection(item); } else { removeSelection(item); } }); connect(searcher, &QLineEdit::textChanged, [=](QString search) { searcher->setStyleSheet("QLineEdit{color: #666;}"); QFontMetrics fm = searcher->fontMetrics(); auto w = fm.horizontalAdvance(search) + 20; if (w + 4 < ui->currentChoices->width()) { searcher->setFixedWidth(w); ui->currentChoices->resize(ui->currentChoices->width(), currentChoicesLayout->minimumHeightForWidth(ui->currentChoices->width())); } int visibleItems = 0; for (auto i = 0; i < choiceSelector->count(); i++) { auto itemAtRow = choiceSelector->item(i); itemAtRow->setHidden(!itemAtRow->text().contains(search, Qt::CaseSensitivity::CaseInsensitive)); visibleItems += !(itemAtRow->isHidden()); } choiceSelector->setVisibleItems(visibleItems); adjustSize(); choiceSelector->setVisible(true); }); connect(searcher, &KiwixLineEdit::clicked, [=]() { showOptions(); }); choiceSelector->setVisible(false); searcher->setStyleSheet("QLineEdit{color: #999;}"); connect(searcher, &KiwixLineEdit::focusedOut, [=]() { hideOptions(); }); connect(searcher, &KiwixLineEdit::focusedIn, [=]() { showOptions(); }); ui->clearButton->setCursor(Qt::PointingHandCursor); connect(ui->clearButton, &QPushButton::clicked, [=]() { clearSelections(); emit(choiceUpdated(getCurrentSelected())); hideOptions(); }); connect(this, &KiwixChoiceBox::choiceUpdated, [=]() { if (choiceSelector->selectedItems().isEmpty()) showPlaceholder(); choiceSelector->setVisible(false); }); connect(this, &KiwixChoiceBox::clicked, [=]() { showOptions(); }); } KiwixChoiceBox::~KiwixChoiceBox() { delete ui; } /* When the lineEdit is currently focused, if the outer widget is pressed, lineEdit loses focus and hides the options. When mouseRelease event is called, it will create a flicker effect: - Clicking and holding causes the lineEdit to lose focus and hide the options - Release causes the options to show up again. Showing the options on a mousePress doesn't allow this */ void KiwixChoiceBox::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { emit(clicked()); } } void KiwixChoiceBox::hideOptions() { if (choiceSelector->selectedItems().isEmpty()) { showPlaceholder(); } searcher->setStyleSheet("QLineEdit{color: #999;}"); choiceSelector->setVisible(false); ui->currentChoices->setStyleSheet("#currentChoices{border: 1px solid #ccc;}"); searcher->clearFocus(); } void KiwixChoiceBox::showOptions() { ui->currentChoices->setStyleSheet("#currentChoices{border: 2px solid #4e63ad;}"); adjustSize(); choiceSelector->setVisible(true); choiceSelector->raise(); searcher->setPlaceholderText(""); searcher->setFocus(); } void KiwixChoiceBox::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { hideOptions(); } else if (event->key() == Qt::Key_Down) { if (!choiceSelector->isVisible()) showOptions(); choiceSelector->moveDown(); } else if (event->key() == Qt::Key_Up) { choiceSelector->moveUp(); } else if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { choiceSelector->selectCurrent(); } } bool KiwixChoiceBox::addSelection(QListWidgetItem *item, bool updateRequired) { auto key = item->text(); auto value = item->data(Qt::UserRole).toString(); auto chItem = new ChoiceItem(key, value); connect(chItem, &ChoiceItem::closeButtonClicked, [=](QString text) { auto selectionItems = choiceSelector->findItems(text, Qt::MatchExactly); if (selectionItems.size() != 1) return; removeSelection(selectionItems[0]); }); chItem->setObjectName(key); currentChoicesLayout->insertWidget(ui->currentChoices->children().count() - 2, chItem); searcher->setFixedWidth(20); // put on top of list item = choiceSelector->takeItem(choiceSelector->row(item)); choiceSelector->insertItem(0, item); item->setSelected(true); searcher->setFixedWidth(20); if (updateRequired) { searcher->setFocus(); emit(choiceUpdated(getCurrentSelected())); } return true; } bool KiwixChoiceBox::removeSelection(QListWidgetItem *item) { auto chItem = ui->currentChoices->findChild(item->text()); chItem->deleteLater(); // selected items are always shown at top, put it after the last selected item item->setSelected(false); auto selItems = choiceSelector->selectedItems(); item = choiceSelector->takeItem(choiceSelector->row(item)); choiceSelector->insertItem(selItems.size(), item); emit(choiceUpdated(getCurrentSelected())); return true; } void KiwixChoiceBox::clearSelections() { for (auto &item : choiceSelector->selectedItems()) { item->setSelected(false); auto chItem = ui->currentChoices->findChild(item->text()); ui->currentChoices->layout()->removeWidget(chItem); delete chItem; } } void KiwixChoiceBox::showPlaceholder() { searcher->clear(); searcher->setPlaceholderText(gt(m_type + "-searcher-placeholder")); // Putting width based on placeholder contents QFontMetrics fm = searcher->fontMetrics(); auto w = fm.boundingRect(gt(m_type + "-searcher-placeholder")).width(); searcher->setFixedWidth(w + 20); } QString beautifyString(QString word) { word = word.replace("_", " "); word[0] = word[0].toUpper(); return word; } void KiwixChoiceBox::setSelections(SelectionList selections, SelectionList defaultSelection) { clearSelections(); choiceSelector->clear(); for (const auto &selection: selections) { auto item = new KListWidgetItem(beautifyString(selection.first)); item->setData(Qt::UserRole, selection.second); choiceSelector->addItem(item); } for (const auto &defSel : defaultSelection) { QString displayStr = beautifyString(defSel.first); auto itemList = choiceSelector->findItems(displayStr, Qt::MatchExactly); if (itemList.isEmpty()) { auto item = new KListWidgetItem(displayStr); item->setData(Qt::UserRole, defSel.second); choiceSelector->addItem(item); addSelection(item, false); } else { addSelection(itemList[0], false); } } if (choiceSelector->selectedItems().isEmpty()) showPlaceholder(); choiceSelector->setVisibleItems(choiceSelector->count()); adjustSize(); } void KiwixChoiceBox::adjustSize() { QWidget::adjustSize(); choiceSelector->adjustSize(); choiceSelector->setGeometry(this->x() + ui->currentChoices->x(), this->y() + ui->currentChoices->y() + ui->currentChoices->height(), choiceSelector->width(), choiceSelector->getVisibleItems() * KListWidgetItem::getItemHeight() + 2); // 2 is for the border so that all elements are visible } void KiwixChoiceBox::setType(QString type) { ui->choiceLabel->setText(gt(type)); m_type = type; } KiwixChoiceBox::SelectionList KiwixChoiceBox::getCurrentSelected() { SelectionList selections; for (auto &item : choiceSelector->selectedItems()) { selections.append({item->text(), item->data(Qt::UserRole).toString()}); } return selections; } kiwix-desktop-2.4.1/src/kiwixchoicebox.h000066400000000000000000000026261473106011000202760ustar00rootroot00000000000000#ifndef KIWIXCHOICEBOX_H #define KIWIXCHOICEBOX_H #include #include #include #include #include #include #include #include "flowlayout.h" #include #include class ChoiceItem; class KiwixLineEdit; class KiwixListWidget; namespace Ui { class kiwixchoicebox; } class KiwixChoiceBox : public QWidget { Q_OBJECT public: typedef QList> SelectionList; explicit KiwixChoiceBox(QWidget *parent = nullptr); void setType(QString type); void setSelections(SelectionList selections, SelectionList defaultSelection); ~KiwixChoiceBox(); void adjustSize(); protected: void keyPressEvent(QKeyEvent* event) override; void mousePressEvent(QMouseEvent *event) override; signals: void choiceUpdated(SelectionList); void clicked(); private: Ui::kiwixchoicebox *ui; QLabel *choiceLabel; QLineEdit *choiceSearch; KiwixListWidget *choiceSelector; FlowLayout *currentChoicesLayout; KiwixLineEdit *searcher; SelectionList getCurrentSelected(); bool removeSelection(QListWidgetItem *item); void clearSelections(); bool addSelection(QListWidgetItem *item, bool updateRequired = true); void showOptions(); void hideOptions(); void showPlaceholder(); QString m_type; bool m_sliderMoved = false; }; #endif // KIWIXCHOICEBOX_H kiwix-desktop-2.4.1/src/kiwixlineedit.cpp000066400000000000000000000011631473106011000204560ustar00rootroot00000000000000#include "kiwixlineedit.h" KiwixLineEdit::KiwixLineEdit(QWidget *parent) : QLineEdit(parent) { installEventFilter(this); } KiwixLineEdit::~KiwixLineEdit() { } void KiwixLineEdit::resizeEvent(QResizeEvent *event) { QLineEdit::resizeEvent(event); adjustSize(); } bool KiwixLineEdit::eventFilter(QObject* object, QEvent* event) { Q_UNUSED(object); if (event->type() == QEvent::MouseButtonPress) { emit(clicked()); } else if (event->type() == QEvent::FocusIn) { emit(focusedIn()); } else if (event->type() == QEvent::FocusOut) { emit(focusedOut()); } return false; } kiwix-desktop-2.4.1/src/kiwixlineedit.h000066400000000000000000000006771473106011000201340ustar00rootroot00000000000000#ifndef KIWIXLINEEDIT_H #define KIWIXLINEEDIT_H #include #include class KiwixLineEdit : public QLineEdit { Q_OBJECT; public: KiwixLineEdit(QWidget *parent = nullptr); ~KiwixLineEdit(); protected: void resizeEvent(QResizeEvent *event) override; bool eventFilter(QObject* object, QEvent* event) override; signals: void clicked(); void focusedIn(); void focusedOut(); }; #endif // KIWIXLINEEDIT_H kiwix-desktop-2.4.1/src/kiwixlistwidget.cpp000066400000000000000000000060171473106011000210430ustar00rootroot00000000000000#include "kiwixlistwidget.h" #include #include #include #include #include "kiwixapp.h" #include "klistwidgetitem.h" KiwixListWidget::KiwixListWidget(QWidget *parent) : QListWidget(parent), currRow(0), m_visibleItems(count()) { connect(this, &KiwixListWidget::currRowChanged, this, &KiwixListWidget::handleCurrRowChange); setMouseTracking(true); } void KiwixListWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { selectCurrent(item(m_mouseIndex)); } } void KiwixListWidget::mouseMoveEvent(QMouseEvent *event) { int oldRow = currRow; m_mouseIndex = row(itemAt(event->pos())); currRow = m_mouseIndex; emit(currRowChanged(oldRow, currRow)); } void KiwixListWidget::hideEvent(QHideEvent *event) { auto currItem = dynamic_cast(item(currRow)); if (currItem) currItem->disableHighlight(); QListWidget::hideEvent(event); } void KiwixListWidget::resizeEvent(QResizeEvent *e) { int oldRow = currRow; for (auto i = 0; i < count(); i++) { auto itemAtRow = item(i); if (!itemAtRow->isHidden() && !itemAtRow->isSelected()) { currRow = i; break; } } emit(currRowChanged(oldRow, currRow)); QListWidget::resizeEvent(e); } void KiwixListWidget::handleCurrRowChange(int oldRow, int newRow) { auto prevItem = dynamic_cast(item(oldRow)); if (prevItem) { prevItem->disableHighlight(); } auto currItem = dynamic_cast(item(newRow)); if (currItem) { currItem->enableHighlight(); scrollToItem(currItem, QAbstractItemView::EnsureVisible); } emit(dataChanged(QModelIndex(), QModelIndex())); } void KiwixListWidget::moveUp() { if (selectedItems().size() == count()) return; KListWidgetItem *currItem = dynamic_cast(item(currRow)); int oldRow = currRow; do { currRow--; if (currRow < 0) currRow = count() - 1; currItem = dynamic_cast(item(currRow)); } while (currItem->isSelected() || currItem->isHidden()); emit(currRowChanged(oldRow, currRow)); } void KiwixListWidget::moveDown() { if (selectedItems().size() == count()) return; KListWidgetItem *currItem = dynamic_cast(item(currRow)); int oldRow = currRow; do { currRow++; if (currRow == count()) currRow = 0; currItem = dynamic_cast(item(currRow)); } while (currItem->isSelected() || currItem->isHidden()); emit(currRowChanged(oldRow, currRow)); } void KiwixListWidget::selectCurrent() { selectCurrent(item(currRow)); } void KiwixListWidget::selectCurrent(QListWidgetItem *item) { auto currItem = dynamic_cast(item); if (currItem && !currItem->isSelected() && !currItem->isHidden()) { currItem->disableHighlight(); currItem->setSelected(!currItem->isSelected()); emit(itemPressed(currItem)); } } kiwix-desktop-2.4.1/src/kiwixlistwidget.h000066400000000000000000000015731473106011000205120ustar00rootroot00000000000000#ifndef KIWIXLISTWIDGET_H #define KIWIXLISTWIDGET_H #include class KiwixListWidget : public QListWidget { Q_OBJECT public: KiwixListWidget(QWidget *parent = nullptr); void moveUp(); void moveDown(); void selectCurrent(); void selectCurrent(QListWidgetItem *item); void setVisibleItems(int visibleItems) { m_visibleItems = visibleItems; } int getVisibleItems() { return m_visibleItems; } protected: void hideEvent(QHideEvent *event) override; void resizeEvent(QResizeEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; signals: void currRowChanged(int oldRow, int newRow); private slots: void handleCurrRowChange(int oldRow, int newRow); private: int currRow; int m_visibleItems; int m_mouseIndex; }; #endif // KIWIXLISTWIDGET_H kiwix-desktop-2.4.1/src/kiwixloader.cpp000066400000000000000000000035051473106011000201310ustar00rootroot00000000000000#include "kiwixloader.h" #include #include #include #include KiwixLoader::KiwixLoader(QWidget *parent) : QWidget(parent), m_timer(nullptr) { setFixedSize(parent->width(), parent->height()); m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this, &KiwixLoader::updateAnimation); } KiwixLoader::~KiwixLoader() { } void KiwixLoader::stopAnimation() { m_timer->stop(); } void KiwixLoader::startAnimation() { m_timer->start(20); } void createArc(QPainter &painter, int startAngle, int spanAngle, QRect rectangle, QPen pen) { painter.setRenderHint(QPainter::Antialiasing); int arcX = rectangle.x(); int arcY = rectangle.y(); int arcW = rectangle.width(); int arcH = rectangle.height(); QPainterPath path; path.moveTo(arcX + arcW, arcY + arcH/2); path.arcTo(rectangle, startAngle, spanAngle); painter.strokePath(path, pen); } void KiwixLoader::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); int width = 100; int height = 100; setFixedSize(this->parentWidget()->width(), this->parentWidget()->height()); int centerX = this->parentWidget()->width()/2 - width; int centerY = this->parentWidget()->height()/2 - height; QPen pen; pen.setWidth(5); painter.setPen(pen); painter.setRenderHint(QPainter::Antialiasing); QRect rectangle(centerX, centerY, width, height); pen.setColor("#eaecf0"); createArc(painter, 0, 360, rectangle, pen); int startAngle = 0; int spanAngle = -progress; pen.setColor("#3366cc"); createArc(painter, startAngle, spanAngle, rectangle, pen); } void KiwixLoader::updateAnimation() { progress += 10; if (progress == 360) progress = 0; update(); } kiwix-desktop-2.4.1/src/kiwixloader.h000066400000000000000000000007071473106011000175770ustar00rootroot00000000000000#ifndef KIWIXLOADER_H #define KIWIXLOADER_H #include #include class KiwixLoader : public QWidget { Q_OBJECT public: explicit KiwixLoader(QWidget *parent = nullptr); ~KiwixLoader(); void startAnimation(); void stopAnimation(); protected: void paintEvent(QPaintEvent *event) override; private slots: void updateAnimation(); private: QTimer *m_timer; int progress = 0; }; #endif // KIWIXLOADER_H kiwix-desktop-2.4.1/src/kiwixmessagebox.cpp000066400000000000000000000041241473106011000210160ustar00rootroot00000000000000#include "kiwixmessagebox.h" #include "ui_kiwixmessagebox.h" #include #include "kiwixapp.h" KiwixMessageBox::KiwixMessageBox(QString confirmTitle, QString confirmText, bool okDialog, QWidget *parent, QString leftAction, QString rightAction) : QDialog(parent), m_confirmTitle(confirmTitle), m_confirmText(confirmText), ui(new Ui::kiwixmessagebox) { ui->setupUi(this); setWindowFlag(Qt::FramelessWindowHint, true); setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/messageBox.css")); connect(ui->yesButton, &QPushButton::clicked, [=]() { emit yesClicked(); m_result = YesClicked; accept(); }); connect(ui->noButton, &QPushButton::clicked, [=]() { emit noClicked(); m_result = NoClicked; reject(); }); connect(ui->okButton, &QPushButton::clicked, [=]() { emit okClicked(); m_result = OkClicked; }); connect(ui->closeButton, &QPushButton::clicked, [=]() { this->close(); m_result = CloseClicked; }); ui->confirmText->setText(confirmText); ui->confirmTitle->setText(confirmTitle); ui->yesButton->setText(leftAction); ui->noButton->setText(rightAction); ui->okButton->setText(gt("ok")); ui->okButton->hide(); if (okDialog) { ui->yesButton->hide(); ui->noButton->hide(); ui->okButton->show(); } } KiwixMessageBox::~KiwixMessageBox() { delete ui; } void showInfoBox(QString title, QString text, QWidget *parent) { KiwixMessageBox *dialog = new KiwixMessageBox(title, text, true, parent); dialog->show(); QObject::connect(dialog, &KiwixMessageBox::okClicked, [=]() { dialog->deleteLater(); }); } KiwixMessageBox::Result showKiwixMessageBox(QString title, QString text, QWidget *parent, QString leftTitle, QString rightTitle) { KiwixMessageBox *dialog = new KiwixMessageBox(title, text, false, parent, leftTitle, rightTitle); QObject::connect(dialog, &KiwixMessageBox::finished, [=]() { dialog->deleteLater(); }); return dialog->execDialog(); } kiwix-desktop-2.4.1/src/kiwixmessagebox.h000066400000000000000000000037311473106011000204660ustar00rootroot00000000000000#ifndef KIWIXMESSAGEBOX_H #define KIWIXMESSAGEBOX_H #include #include "kiwixapp.h" #include namespace Ui { class kiwixmessagebox; } class KiwixMessageBox : public QDialog { Q_OBJECT public: KiwixMessageBox(QString confirmTitle, QString confirmText, bool okDialog, QWidget *parent = nullptr, QString leftAction = gt("yes"), QString rightAction = gt("no")); ~KiwixMessageBox(); enum Result { YesClicked, NoClicked, OkClicked, CloseClicked }; Result execDialog() { QDialog::exec(); return m_result; } signals: void yesClicked(); void noClicked(); void okClicked(); private: QString m_confirmTitle; QString m_confirmText; Ui::kiwixmessagebox *ui; Result m_result; }; void showInfoBox(QString title, QString text, QWidget *parent = nullptr); KiwixMessageBox::Result showKiwixMessageBox(QString title, QString text, QWidget *parent, QString leftTitle, QString rightTitle); template void showConfirmBox(QString title, QString text, QWidget *parent, YesAction yesAction) { KiwixMessageBox *dialog = new KiwixMessageBox(title, text, false, parent); dialog->show(); QObject::connect(dialog, &KiwixMessageBox::yesClicked, [=]() { yesAction(); dialog->deleteLater(); }); QObject::connect(dialog, &KiwixMessageBox::noClicked, [=]() { dialog->deleteLater(); }); } class KiwixAppError : public std::runtime_error { public: KiwixAppError(const QString& summary, const QString& details) : std::runtime_error(summary.toStdString()) , m_details(details) {} QString summary() const { return QString::fromStdString(what()); } QString details() const { return m_details; } private: QString m_details; }; inline void showErrorBox(const KiwixAppError& err, QWidget *parent = nullptr) { showInfoBox(err.summary(), err.details(), parent); } #endif // KIWIXMESSAGEBOX_H kiwix-desktop-2.4.1/src/kiwixwebchannelobject.h000066400000000000000000000010211473106011000216140ustar00rootroot00000000000000#ifndef KIWIXWEBCHANNELOBJECT_H #define KIWIXWEBCHANNELOBJECT_H #include class KiwixWebChannelObject : public QObject { Q_OBJECT public: explicit KiwixWebChannelObject(QObject *parent = nullptr) : QObject(parent) {}; Q_INVOKABLE void sendHeadersJSONStr(const QString& headersJSONStr) { emit headersChanged(headersJSONStr); }; signals: void headersChanged(const QString& headersJSONStr); void navigationRequested(const QString& url, const QString& anchor); }; #endif // KIWIXWEBCHANNELOBJECT_H kiwix-desktop-2.4.1/src/klistwidgetitem.cpp000066400000000000000000000017131473106011000210170ustar00rootroot00000000000000#include "klistwidgetitem.h" int KListWidgetItem::m_itemHeight = 35; KListWidgetItem::KListWidgetItem(QString text) : QListWidgetItem (text) { setSizeHint(QSize(200, m_itemHeight)); setBackground(QColor("white")); setForeground(QColor("#666666")); } void KListWidgetItem::disableHighlight() { isHighlighted = false; } void KListWidgetItem::enableHighlight() { isHighlighted = true; } QVariant KListWidgetItem::data(int role) const { QVariant v = QListWidgetItem::data(role); if( isSelected()) { if (role == Qt::FontRole) { QFont font = v.value(); font.setBold( true ); v = QVariant::fromValue( font ); } } if (isHighlighted) { if (role == Qt::BackgroundRole) { v = QVariant::fromValue(QColor("#4e63ad")); } else if (role == Qt::ForegroundRole) { v = QVariant::fromValue(QColor("white")); } } return v; } kiwix-desktop-2.4.1/src/klistwidgetitem.h000066400000000000000000000006501473106011000204630ustar00rootroot00000000000000#ifndef KLISTWIDGETITEM_H #define KLISTWIDGETITEM_H #include class KListWidgetItem : public QListWidgetItem { public: KListWidgetItem(QString text); QVariant data(int role) const; static int getItemHeight() { return m_itemHeight; }; void disableHighlight(); void enableHighlight(); private: static int m_itemHeight; bool isHighlighted = false; }; #endif // KLISTWIDGETITEM_H kiwix-desktop-2.4.1/src/kprofile.cpp000066400000000000000000000124311473106011000174200ustar00rootroot00000000000000#include "kprofile.h" #include "kiwixapp.h" #include "kiwixmessagebox.h" #include #include #include #include #include #include namespace { QWebEngineScript getScript(QString filename, QWebEngineScript::InjectionPoint point = QWebEngineScript::DocumentReady) { QWebEngineScript script; script.setInjectionPoint(point); script.setWorldId(QWebEngineScript::UserWorld); QFile scriptFile(filename); scriptFile.open(QIODevice::ReadOnly); script.setSourceCode(scriptFile.readAll()); return script; } } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #define DownloadFinishedSignal WebEngineDownloadType::finished #else #define DownloadFinishedSignal WebEngineDownloadType::isFinishedChanged #endif QString askForSaveFilePath(const QString& suggestedName) { const auto app = KiwixApp::instance(); const QString suggestedPath = app->getPrevSaveDir() + "/" + suggestedName; const QString extension = suggestedName.section(".", -1); const QString filter = extension.isEmpty() ? "" : "(*." + extension + ")"; QString fileName = QFileDialog::getSaveFileName( app->getMainWindow(), gt("save-file-as-window-title"), suggestedPath, filter); if (fileName.isEmpty()) return QString(); if (!fileName.endsWith(extension)) { fileName.append(extension); } app->savePrevSaveDir(QFileInfo(fileName).absolutePath()); return fileName; } KProfile::KProfile(QObject *parent) : QWebEngineProfile(parent) { connect(this, &QWebEngineProfile::downloadRequested, this, &KProfile::startDownload); installUrlSchemeHandler("zim", &m_schemeHandler); settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) // Earlier than Qt 5.13 setRequestInterceptor(new ExternalReqInterceptor(this)); #else // Qt 5.13 and later setUrlRequestInterceptor(new ExternalReqInterceptor(this)); #endif scripts()->insert(getScript(":/js/headerAnchor.js")); scripts()->insert(getScript(":/qtwebchannel/qwebchannel.js", QWebEngineScript::DocumentCreation)); } namespace { void setDownloadFilePath(WebEngineDownloadType* download, QString filePath) { #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) // WebEngineDownloadType is QWebEngineDownloadItem // and no QWebEngineDownloadItem::setDownloadFileName() yet download->setPath(filePath); #else // Same API for QWebEngineDownloadItem and QWebEngineDownloadRequest download->setDownloadFileName(filePath); #endif } QString getDownloadFilePath(WebEngineDownloadType* download) { #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) // WebEngineDownloadType is QWebEngineDownloadItem // and no QWebEngineDownloadItem::downloadFileName() yet return QUrl(download->path()).fileName(); #else // Same API for QWebEngineDownloadItem and QWebEngineDownloadRequest return download->downloadFileName(); #endif } } // unnamed namespace void KProfile::openFile(WebEngineDownloadType* download) { const QString defaultFileName = getDownloadFilePath(download); QTemporaryFile tempFile(QDir::tempPath() + "/XXXXXX." + QFileInfo(defaultFileName).suffix()); tempFile.setAutoRemove(false); if (tempFile.open()) { QString tempFilePath = tempFile.fileName(); tempFile.close(); setDownloadFilePath(download, tempFilePath); connect(download, &DownloadFinishedSignal, [tempFilePath]() { if(!QDesktopServices::openUrl(QUrl::fromLocalFile(tempFilePath))) showInfoBox(gt("error-title"), gt("error-opening-file"), KiwixApp::instance()->getMainWindow()); }); download->accept(); } else { qDebug()<<"tmp file err"; download->cancel(); } } void KProfile::saveFile(WebEngineDownloadType* download) { const QString defaultFileName = getDownloadFilePath(download); const QString fileName = askForSaveFilePath(defaultFileName); if (fileName.isEmpty()) { download->cancel(); return; } setDownloadFilePath(download, fileName); connect(download, &DownloadFinishedSignal, this, &KProfile::downloadFinished); download->accept(); } void KProfile::downloadFinished() { showInfoBox(gt("download-finished"), gt("download-finished-message"), KiwixApp::instance()->getMainWindow() ); } void KProfile::startDownload(WebEngineDownloadType* download) { const auto res = showKiwixMessageBox( gt("save-or-open"), gt("save-or-open-text"), KiwixApp::instance()->getMainWindow(), gt("save-file"), gt("open-file") ); if (res == KiwixMessageBox::YesClicked) { saveFile(download); return; } if (res == KiwixMessageBox::NoClicked) { openFile(download); return; } download->cancel(); } void ExternalReqInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) { const QString reqUrl = info.requestUrl().toString(); if (!reqUrl.startsWith("zim://")) { qDebug() << "Blocked external request to URL: " << reqUrl; info.block(true); } } kiwix-desktop-2.4.1/src/kprofile.h000066400000000000000000000023061473106011000170650ustar00rootroot00000000000000#ifndef KPROFILE_H #define KPROFILE_H #include #include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include typedef QWebEngineDownloadItem WebEngineDownloadType; #else #include typedef QWebEngineDownloadRequest WebEngineDownloadType; #endif #include "urlschemehandler.h" class KProfile : public QWebEngineProfile { Q_OBJECT public: KProfile(QObject *parent = nullptr); private: UrlSchemeHandler m_schemeHandler; signals: private slots: void startDownload(WebEngineDownloadType*); void downloadFinished(); void saveFile(WebEngineDownloadType*); void openFile(WebEngineDownloadType*); }; /** * @brief Intercepts and blocks a request if it is not native to our zim file. * https://stackoverflow.com/questions/70721311/qwebview-disable-external-resources */ class ExternalReqInterceptor : public QWebEngineUrlRequestInterceptor { Q_OBJECT public: explicit ExternalReqInterceptor(QObject *parent = nullptr) : QWebEngineUrlRequestInterceptor(parent) { } protected: void interceptRequest(QWebEngineUrlRequestInfo &info) override; }; #endif // KPROFILE_H kiwix-desktop-2.4.1/src/library.cpp000066400000000000000000000157111473106011000172550ustar00rootroot00000000000000#include "library.h" #include "kiwixapp.h" #include #include #include #include #include class LibraryManipulator: public kiwix::LibraryManipulator { public: LibraryManipulator(Library* p_library) : kiwix::LibraryManipulator(p_library->getKiwixLibrary()) , mp_library(p_library) {} virtual ~LibraryManipulator() {} bool addBookToLibrary(kiwix::Book book) { auto ret = mp_library->mp_library->addBook(book); emit(mp_library->booksChanged()); return ret; } void addBookmarkToLibrary(kiwix::Bookmark bookmark) { mp_library->mp_library->addBookmark(bookmark); } Library* mp_library; }; Library::Library(const QString& libraryDirectory) : mp_library(kiwix::Library::create()), m_libraryDirectory(libraryDirectory) { auto manager = kiwix::Manager(LibraryManipulator(this)); manager.readFile(kiwix::appendToDirectory(m_libraryDirectory.toStdString(),"library.xml"), false); manager.readBookmarkFile(kiwix::appendToDirectory(m_libraryDirectory.toStdString(),"library.bookmarks.xml")); emit(booksChanged()); } Library::~Library() { save(); } QString Library::openBookFromPath(const QString &zimPath) { try { auto& book = mp_library->getBookByPath(zimPath.toStdString()); return QString::fromStdString(book.getId()); } catch(std::out_of_range& e) { } kiwix::Manager manager(mp_library); auto id = manager.addBookFromPathAndGetId(zimPath.toStdString()); if (id == "") { throw std::invalid_argument("invalid zim file"); } save(); emit(booksChanged()); return QString::fromStdString(id); } std::shared_ptr Library::getArchive(const QString &zimId) { const auto archive = mp_library->getArchiveById(zimId.toStdString()); if ( ! archive ) { throw std::out_of_range("ZIM file doesn't exist (or cannot be opened)"); } return archive; } std::shared_ptr Library::getSearcher(const QString &zimId) { return mp_library->getSearcherById(zimId.toStdString()); } QIcon Library::getBookIcon(const QString &zimId) { static QIcon defaultIcon = QIcon(":/icons/placeholder-icon.png"); try { const auto& book = getBookById(zimId); const auto illustration = book.getIllustration(48); const auto& content = illustration->getData(); QPixmap pixmap; pixmap.loadFromData((const uchar*)content.data(), content.size()); return QIcon(pixmap); } catch (...) { return defaultIcon; } } QStringList Library::getBookIds() const { QStringList list; for(auto& id: mp_library->getBooksIds()) { list.append(QString::fromStdString(id)); } return list; } QStringList Library::listBookIds(const kiwix::Filter& filter, kiwix::supportedListSortBy sortBy, bool ascending) const { QStringList list; auto bookIds = mp_library->filter(filter); mp_library->sort(bookIds, sortBy, ascending); for(auto& id: bookIds) { list.append(QString::fromStdString(id)); } return list; } void Library::addBookToLibrary(kiwix::Book &book) { mp_library->addBook(book); } void Library::removeBookFromLibraryById(const QString& id) { mp_library->removeBookById(id.toStdString()); } namespace { const char BEINGDOWNLOADEDSUFFIX[] = ".beingdownloadedbykiwix"; std::string pseudoPathOfAFileBeingDownloaded(const std::string& path) { return path + BEINGDOWNLOADEDSUFFIX; } std::string dropSuffix(const std::string& str, const std::string& suffix) { const size_t s = suffix.size(); const size_t n = str.size(); return n > s && str.substr(n - s, s) == suffix ? str.substr(0, n - s) : str; } } // unnamed namespace std::string Library::getBookFilePath(const QString& bookId) const { const auto& book = getBookById(bookId); const std::string bookPath = book.getPath(); return book.getDownloadId().empty() ? bookPath : dropSuffix(bookPath, BEINGDOWNLOADEDSUFFIX); } void Library::addBookBeingDownloaded(const kiwix::Book& book, QString downloadDir) { const QString downloadUrl = QString::fromStdString(book.getUrl()); // XXX: This works if the URL is a direct link to a ZIM file // XXX: rather than to a torrent or a metalink file. In those cases // XXX: the file name of the download will be discovered after the // XXX: the metalink or torrent file is downloaded. Then the real // XXX: file name of a book must be set via updateBookBeingDownloaded(); const QString fileName = downloadUrl.split('/').back(); const QString path = QDir(downloadDir).absoluteFilePath(fileName); const std::string stlPath = QDir::toNativeSeparators(path).toStdString(); kiwix::Book bookCopy(book); bookCopy.setPath(pseudoPathOfAFileBeingDownloaded(stlPath)); addBookToLibrary(bookCopy); } void Library::updateBookBeingDownloaded(const QString& bookId, const QString& bookPath) { if ( bookPath.isEmpty() ) return; const kiwix::Book& book = getBookById(bookId); const auto bookPseudoPath = pseudoPathOfAFileBeingDownloaded(bookPath.toStdString()); if ( bookPseudoPath != book.getPath() ) { kiwix::Book bookCopy(book); bookCopy.setPath(bookPseudoPath); mp_library->addOrUpdateBook(bookCopy); save(); } } bool Library::isBeingDownloadedByUs(QString path) const { const auto fakePath = pseudoPathOfAFileBeingDownloaded(path.toStdString()); try { mp_library->getBookByPath(fakePath); return true; } catch ( const std::out_of_range& ) { return false; } } void Library::addBookmark(kiwix::Bookmark &bookmark) { mp_library->addBookmark(bookmark); emit bookmarksChanged(); } void Library::removeBookmark(const QString &zimId, const QString &url) { mp_library->removeBookmark(zimId.toStdString(), url.toStdString()); emit bookmarksChanged(); } void Library::save() { mp_library->writeToFile(kiwix::appendToDirectory(m_libraryDirectory.toStdString(),"library.xml")); mp_library->writeBookmarksToFile(kiwix::appendToDirectory(m_libraryDirectory.toStdString(), "library.bookmarks.xml")); } Library::QStringSet Library::getLibraryZimsFromDir(QString dir) const { QStringSet zimsInDir; for (auto str : getBookIds()) { auto filePath = QString::fromStdString(getBookById(str).getPath()); if ( filePath.endsWith(BEINGDOWNLOADEDSUFFIX) ) continue; const QFileInfo fileInfo(filePath); if (fileInfo.absoluteDir() == dir) { zimsInDir.insert(fileInfo.fileName()); } } return zimsInDir; } bool Library::readBookMarksFile(const std::string &filename) { kiwix::Manager manager(mp_library); if (!manager.readBookmarkFile(filename)) return false; emit bookmarksChanged(); return true; } const kiwix::Book &Library::getBookById(QString id) const { return mp_library->getBookById(id.toStdString()); } kiwix-desktop-2.4.1/src/library.h000066400000000000000000000042121473106011000167140ustar00rootroot00000000000000#ifndef LIBRARY_H #define LIBRARY_H #include #include #include #include #include #include #include #include #include #include #include #define TQS(v) (QString::fromStdString(v)) #define FORWARD_GETTER(METH) QString METH() const { return TQS(mp_book->METH()); } #undef FORWARD_GETTER #undef TQS class LibraryManipulator; class Library : public QObject { Q_OBJECT Q_PROPERTY(QStringList bookIds READ getBookIds NOTIFY booksChanged) public: typedef QSet QStringSet; Library(const QString& libraryDirectory); virtual ~Library(); QString openBookFromPath(const QString& zimPath); std::shared_ptr getArchive(const QString& zimId); std::shared_ptr getSearcher(const QString& zimId); QIcon getBookIcon(const QString& zimId); QStringList getBookIds() const; QStringList listBookIds(const kiwix::Filter& filter, kiwix::supportedListSortBy sortBy, bool ascending) const; const std::vector getBookmarks(bool onlyValidBookmarks = false) const { return mp_library->getBookmarks(onlyValidBookmarks); } QStringSet getLibraryZimsFromDir(QString dir) const; void addBookToLibrary(kiwix::Book& book); void addBookBeingDownloaded(const kiwix::Book& book, QString downloadDir); bool isBeingDownloadedByUs(QString path) const; void updateBookBeingDownloaded(const QString& bookId, const QString& bookPath); std::string getBookFilePath(const QString& bookId) const; void removeBookFromLibraryById(const QString& id); void addBookmark(kiwix::Bookmark& bookmark); void removeBookmark(const QString& zimId, const QString& url); bool readBookMarksFile(const std::string& filename); void save(); kiwix::LibraryPtr getKiwixLibrary() { return mp_library; } public slots: const kiwix::Book& getBookById(QString id) const; signals: void booksChanged(); void bookmarksChanged(); private: kiwix::LibraryPtr mp_library; QString m_libraryDirectory; friend class LibraryManipulator; }; #endif // LIBRARY_H kiwix-desktop-2.4.1/src/localkiwixserver.cpp000066400000000000000000000131761473106011000212110ustar00rootroot00000000000000#include "localkiwixserver.h" #include "ui_localkiwixserver.h" #include "kiwixapp.h" #include #include #include #include LocalKiwixServer::LocalKiwixServer(QWidget *parent) : QDialog(parent), ui(new Ui::LocalKiwixServer) { setWindowFlag(Qt::FramelessWindowHint, true); ui->setupUi(this); QFile styleFile(":/css/localServer.css"); styleFile.open(QIODevice::ReadOnly); auto byteContent = styleFile.readAll(); styleFile.close(); QString style(byteContent); setStyleSheet(style); mp_server = KiwixApp::instance()->getLocalServer(); m_port = KiwixApp::instance()->getSettingsManager()->getKiwixServerPort(); connect(ui->KiwixServerButton, SIGNAL(clicked()), this, SLOT(runOrStopServer())); connect(ui->OpenInBrowserButton, SIGNAL(clicked()), this, SLOT(openInBrowser())); connect(ui->closeButton, &QPushButton::clicked, this, &LocalKiwixServer::close); connect(ui->PortChooser, &QLineEdit::textChanged, ui->PortChooser, [=](const QString &text) { if (text.toInt() > 65535) { QString validText = text; validText.chop(1); ui->PortChooser->setText(validText); } else if (text.toInt() < 1) { QString defaultPort = QString::number(KiwixApp::instance()->getSettingsManager()->getKiwixServerPort()); ui->PortChooser->setText(defaultPort); } }); const auto interfacesMap = kiwix::getNetworkInterfacesIPv4Or6(); QVector interfaces; interfaces.reserve(interfacesMap.size() + 1); for (const auto &interfacePair : interfacesMap) { QString ipv4 = QString::fromStdString(interfacePair.second.addr); if (!ipv4.isEmpty() && !ipv4.startsWith("169.254")) interfaces.push_back(ipv4); QString ipv6 = QString::fromStdString(interfacePair.second.addr6); if (!ipv6.isEmpty()) interfaces.push_back(ipv6); } std::sort(interfaces.begin(), interfaces.end()); interfaces.push_front(QString(gt("ipv6"))); interfaces.push_front(QString(gt("ipv4"))); interfaces.push_front(QString(gt("all_ips"))); for (const auto &interface : interfaces) { ui->IpChooser->addItem(interface); } QString ipAddress = KiwixApp::instance()->getSettingsManager()->getKiwixServerIpAddress(); if (ipAddress == "0.0.0.0") ipAddress = "ipv4"; ui->IpChooser->setCurrentText(ipAddress == "all_ips" || ipAddress == "ipv4" || ipAddress == "ipv6" ? gt(ipAddress) : ipAddress); ui->PortChooser->setText(QString::number(m_port)); ui->PortChooser->setValidator(new QIntValidator(1, 65535, this)); ui->KiwixServerButton->setStyleSheet("QPushButton {background-color: RoyalBlue;" "color: white;" "padding: 5px;" "border-radius: 3px;}" "QPushButton:hover {background-color: DodgerBlue;}"); ui->label->setText(gt("local-kiwix-server")); ui->KiwixServerText->setText(gt("kiwix-server-description")); ui->OpenInBrowserButton->setText(gt("open-in-browser")); ui->KiwixServerButton->setText(gt("start-kiwix-server")); ui->closeButton->setText(gt("close")); } LocalKiwixServer::~LocalKiwixServer() { delete ui; } void LocalKiwixServer::openInBrowser() { QUrl url; url.setScheme("http"); url.setHost(m_ipAddress); url.setPort(m_port); QDesktopServices::openUrl(url); } void LocalKiwixServer::runOrStopServer() { if (!m_active) { auto settingsManager = KiwixApp::instance()->getSettingsManager(); m_port = ui->PortChooser->text().toInt(); mp_server->setPort(m_port); settingsManager->setKiwixServerPort(m_port); mp_server->setIpMode(kiwix::IpMode::AUTO); mp_server->setAddress(""); if (ui->IpChooser->currentText() == gt("all_ips")) { mp_server->setIpMode(kiwix::IpMode::ALL); settingsManager->setKiwixServerIpAddress("all_ips"); } else if (ui->IpChooser->currentText() == gt("ipv4")) { mp_server->setIpMode(kiwix::IpMode::IPV4); settingsManager->setKiwixServerIpAddress("ipv4"); } else if (ui->IpChooser->currentText() == gt("ipv6")) { mp_server->setIpMode(kiwix::IpMode::IPV6); settingsManager->setKiwixServerIpAddress("ipv6"); } else { mp_server->setAddress(ui->IpChooser->currentText().toStdString()); settingsManager->setKiwixServerIpAddress(ui->IpChooser->currentText()); } if (!mp_server->start()) { QMessageBox messageBox; messageBox.critical(0,gt("error-title"),gt("error-launch-server-message")); return; } kiwix::IpAddress serverAddress = mp_server->getAddress(); m_ipAddress = QString::fromStdString(serverAddress.addr.empty() ? serverAddress.addr6 : serverAddress.addr); if (m_ipAddress.contains(':')) m_ipAddress = "[" + m_ipAddress + "]"; ui->IpAddress->setText("http://" + m_ipAddress + ":" + QString::number(m_port)); ui->IpAddress->setReadOnly(true); m_active = true; } else { mp_server->stop(); m_active = false; } if (m_active) { ui->KiwixServerButton->setText(gt("stop-kiwix-server")); ui->KiwixServerText->setText(gt("kiwix-server-running-message")); ui->stackedWidget->setCurrentIndex(1); } else { ui->KiwixServerButton->setText(gt("start-kiwix-server")); ui->KiwixServerText->setText(gt("kiwix-server-description")); ui->stackedWidget->setCurrentIndex(0); } } kiwix-desktop-2.4.1/src/localkiwixserver.h000066400000000000000000000010221473106011000206410ustar00rootroot00000000000000#ifndef LOCALKIWIXSERVER_H #define LOCALKIWIXSERVER_H #include #include namespace Ui { class LocalKiwixServer; } class LocalKiwixServer : public QDialog { Q_OBJECT public: explicit LocalKiwixServer(QWidget *parent = nullptr); ~LocalKiwixServer(); public slots: void runOrStopServer(); void openInBrowser(); private: Ui::LocalKiwixServer *ui; kiwix::Server* mp_server; bool m_active = false; QString m_ipAddress; int m_port; }; #endif // LOCALKIWIXSERVER_H kiwix-desktop-2.4.1/src/main.cpp000066400000000000000000000055731473106011000165420ustar00rootroot00000000000000#include #include "kiwixapp.h" #include #include #include #ifdef Q_OS_WIN #include #include #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) #include #endif #ifdef Q_OS_WIN bool wasAppStartedFromARemoteDrive() { const std::string exePath = kiwix::getExecutablePath(); if ( exePath.substr(0, 2) == "\\\\" ) return true; return GetDriveTypeA(exePath.substr(0, 3).c_str()) == DRIVE_REMOTE; } #endif int main(int argc, char *argv[]) { // Small hack to make QtWebEngine works with AppImage. // See https://github.com/probonopd/linuxdeployqt/issues/554 if (qEnvironmentVariableIsSet("APPIMAGE")) { qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-gpu --no-sandbox"); QApplication::setAttribute(Qt::AA_UseOpenGLES); } // End of hack ^^^ #ifdef Q_OS_WIN const bool appWasStartedFromARemoteDrive = wasAppStartedFromARemoteDrive(); if ( appWasStartedFromARemoteDrive ) { // This has to be done early before the qtwebengine dll is loaded. // We notify the user about the implications and ask for confirmation // a little later (see closer to the bottom of this function). qputenv("QTWEBENGINE_CHROMIUM_FLAGS", QByteArray("--no-sandbox")); } #endif #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // High DPI Scaling is enabled by default in Qt6. This attribute no longer exists in 6.0 and later QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) QWebEngineUrlScheme scheme("zim"); QWebEngineUrlScheme::registerScheme(scheme); #endif KiwixApp a(argc, argv); QCommandLineParser parser; parser.setApplicationDescription(QStringLiteral("The Kiwix Desktop is a viewer/manager of ZIM files for GNU/Linux and Microsoft Windows OSes.")); parser.addHelpOption(); parser.addPositionalArgument("zimfile", "The zim file"); // Set version string std::ostringstream versions; a.printVersions(versions); a.setApplicationVersion(QString::fromStdString(versions.str())); parser.addVersionOption(); parser.process(a); auto positionalArguments = parser.positionalArguments(); if (a.isRunning()) { for (QString zimfile : positionalArguments) { a.sendMessage(zimfile); } return 0; } a.init(); #ifdef Q_OS_WIN if ( appWasStartedFromARemoteDrive ) { int result = QMessageBox::question(nullptr, gt("about-kiwix-desktop-title"), gt("disable-sandbox"), QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::No) return 0; } #endif /* Restore Tabs before directory monitoring to ensure we know what tabs user had. */ a.restoreTabs(); a.setupDirectoryMonitoring(); for (QString zimfile : positionalArguments) { a.openZimFile(zimfile); } return a.exec(); } kiwix-desktop-2.4.1/src/mainmenu.cpp000066400000000000000000000044071473106011000174220ustar00rootroot00000000000000#include "mainmenu.h" #include "kiwixapp.h" #include "menuproxystyle.h" #include #define ADD_ACTION(ID) addAction(app->getAction(KiwixApp::ID)); MainMenu::MainMenu(QWidget *parent) : QMenu(parent) { auto app = KiwixApp::instance(); setStyle(new MenuProxyStyle()); ADD_ACTION(KiwixServeAction); ADD_ACTION(RandomArticleAction); ADD_ACTION(PrintAction); addSeparator(); m_fileMenu.setTitle(gt("file")); m_fileMenu.ADD_ACTION(NewTabAction); m_fileMenu.ADD_ACTION(CloseCurrentTabAction); m_fileMenu.ADD_ACTION(ReopenClosedTabAction); m_fileMenu.ADD_ACTION(BrowseLibraryAction); m_fileMenu.ADD_ACTION(OpenFileAction); m_fileMenu.ADD_ACTION(OpenRecentAction); m_fileMenu.ADD_ACTION(ExportReadingListAction); m_fileMenu.ADD_ACTION(ImportReadingListAction); m_fileMenu.ADD_ACTION(SavePageAsAction); addMenu(&m_fileMenu); m_editMenu.setTitle(gt("edit")); m_editMenu.ADD_ACTION(SearchArticleAction); m_editMenu.ADD_ACTION(SearchLibraryAction); m_editMenu.ADD_ACTION(FindInPageAction); m_editMenu.ADD_ACTION(ToggleAddBookmarkAction); m_editMenu.ADD_ACTION(OpenMultiZimAction); #if defined(QT_TEXTTOSPEECH_LIB) m_editMenu.ADD_ACTION(ReadArticleAction); m_editMenu.ADD_ACTION(ReadTextAction); m_editMenu.ADD_ACTION(ReadStopAction); #endif addMenu(&m_editMenu); m_viewMenu.setTitle(gt("view")); m_viewMenu.ADD_ACTION(ToggleFullscreenAction); m_viewMenu.ADD_ACTION(ToggleTOCAction); m_viewMenu.ADD_ACTION(ToggleReadingListAction); m_viewMenu.ADD_ACTION(ToggleTTSLanguageAction); m_viewMenu.ADD_ACTION(ToggleTTSVoiceAction); m_viewMenu.ADD_ACTION(ZoomInAction); m_viewMenu.ADD_ACTION(ZoomOutAction); m_viewMenu.ADD_ACTION(ZoomResetAction); addMenu(&m_viewMenu); m_toolsMenu.setTitle(gt("tools")); // m_toolsMenu.addAction(); // addMenu(&m_toolsMenu); m_helpMenu.setTitle(gt("help")); m_helpMenu.ADD_ACTION(HelpAction); m_helpMenu.ADD_ACTION(FeedbackAction); m_helpMenu.ADD_ACTION(ReportBugAction); m_helpMenu.ADD_ACTION(RequestFeatureAction); m_helpMenu.ADD_ACTION(AboutAction); addMenu(&m_helpMenu); addSeparator(); ADD_ACTION(SettingAction); ADD_ACTION(DonateAction); ADD_ACTION(ExitAction); } kiwix-desktop-2.4.1/src/mainmenu.h000066400000000000000000000004471473106011000170670ustar00rootroot00000000000000#ifndef MAINMENU_H #define MAINMENU_H #include class MainMenu : public QMenu { Q_OBJECT public: MainMenu(QWidget *parent=nullptr); private: QMenu m_fileMenu; QMenu m_editMenu; QMenu m_viewMenu; QMenu m_toolsMenu; QMenu m_helpMenu; }; #endif // MAINMENU_H kiwix-desktop-2.4.1/src/mainwindow.cpp000066400000000000000000000177111473106011000177670ustar00rootroot00000000000000 #include "mainwindow.h" #include "portutils.h" #include "ui_mainwindow.h" #include "ui_about.h" #include "kiwixapp.h" #include "kconstants.h" #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), mp_ui(new Ui::MainWindow), mp_about(new About(this)), mp_localKiwixServer(new LocalKiwixServer(this)) { QWidget::setAttribute(Qt::WA_AlwaysShowToolTips); mp_ui->setupUi(this); mp_ui->tabBar->setExpanding(false); mp_ui->tabBar->setStackedWidget(mp_ui->mainView); auto app = KiwixApp::instance(); addAction(app->getAction(KiwixApp::ToggleFullscreenAction)); addAction(app->getAction(KiwixApp::NextTabAction)); addAction(app->getAction(KiwixApp::PreviousTabAction)); mp_ui->newTabSideButton->setDefaultAction(app->getAction(KiwixApp::NewTabAction)); mp_ui->nextTabButton->setDefaultAction(app->getAction(KiwixApp::ScrollNextTabAction)); mp_ui->prevTabButton->setDefaultAction(app->getAction(KiwixApp::ScrollPreviousTabAction)); connect(mp_ui->tabBar, &TabBar::sizeChanged, this, &MainWindow::updateTabButtons); connect(mp_ui->tabBar, &QTabBar::currentChanged, this, &MainWindow::updateTabButtons); connect(mp_ui->tabBar, &TabBar::tabRemovedSignal, this, &MainWindow::updateTabButtons); connect(mp_ui->tabBar, &TabBar::tabInsertedSignal, this, &MainWindow::updateTabButtons); connect(mp_ui->nextTabButton, &QToolButton::triggered, mp_ui->tabBar, &TabBar::scrollNextTab); connect(mp_ui->prevTabButton, &QToolButton::triggered, mp_ui->tabBar, &TabBar::scrollPreviousTab); connect(app->getAction(KiwixApp::ExitAction), &QAction::triggered, this, &QMainWindow::close); connect(app->getAction(KiwixApp::ToggleFullscreenAction), &QAction::triggered, this, &MainWindow::toggleFullScreen); connect(app->getAction(KiwixApp::ToggleReadingListAction), &QAction::toggled, this, &MainWindow::readingListToggled); connect(app->getAction(KiwixApp::ToggleTOCAction), &QAction::toggled, this, &MainWindow::tableOfContentToggled); connect(app->getAction(KiwixApp::AboutAction), &QAction::triggered, mp_about, &QDialog::show); connect(app->getAction(KiwixApp::DonateAction), &QAction::triggered, this, [=]() { QDesktopServices::openUrl(QUrl("https://donate.kiwix.org")); }); connect(app->getAction(KiwixApp::KiwixServeAction), &QAction::triggered, mp_localKiwixServer, &QDialog::show); connect(mp_ui->tabBar, &TabBar::currentTitleChanged, this, [=](const QString& title) { if (!title.isEmpty() && !title.startsWith("zim://")) setWindowTitle(title + " - Kiwix"); else setWindowTitle(gt("window-title")); }); addAction(app->getAction(KiwixApp::OpenHomePageAction)); #if !SYSTEMTITLEBAR setWindowFlags(Qt::Window | Qt::CustomizeWindowHint); #endif connect(mp_ui->tabBar, &QTabBar::currentChanged, mp_ui->mainToolBar, &TopWidget::updateBackForwardButtons); connect(mp_ui->tabBar, &TabBar::tabDisplayed, this, [=](TabType tabType) { tabChanged(tabType); }); connect(mp_ui->tabBar, &TabBar::currentTitleChanged, &(mp_ui->mainToolBar->getSearchBar()), &SearchBar::currentTitleChanged); // This signal emited more often than the history really updated // but for now we have no better signal for it. connect(mp_ui->tabBar, &TabBar::currentTitleChanged, mp_ui->mainToolBar, &TopWidget::updateBackForwardButtons); connect(mp_ui->tabBar, &TabBar::webActionEnabledChanged, mp_ui->mainToolBar, &TopWidget::handleWebActionEnabledChanged); mp_ui->contentmanagerside->setContentManager(app->getContentManager()); mp_ui->sideBar->setCurrentWidget(mp_ui->contentmanagerside); } MainWindow::~MainWindow() { delete mp_ui; } void MainWindow::toggleFullScreen() { if (isFullScreen()) { QApplication::instance()->removeEventFilter(this); showTabAndTop(); showNormal(); } else { QApplication::instance()->installEventFilter(this); hideTabAndTop(); showFullScreen(); } } void MainWindow::hideTabAndTop() { getTabBar()->hide(); getTopWidget()->hide(); } void MainWindow::showTabAndTop() { getTabBar()->show(); getTopWidget()->show(); } void MainWindow::updateTabButtons() { auto tabBar = getTabBar(); QRect tabBarRect = getTabBar()->rect(); QRect newTabButtonRect = tabBar->tabRect(tabBar->count() - 1); /* Decision is made at half way of the new button tab for smoothness */ newTabButtonRect.setWidth(newTabButtonRect.width() / 2); bool newTabButtonVisible = tabBarRect.contains(newTabButtonRect); mp_ui->newTabSideButton->setHidden(newTabButtonVisible); int lastTabIndex = tabBar->realTabCount() - 1; QRect firstTabRect = tabBar->tabRect(0); QRect lastTabRect = tabBar->tabRect(lastTabIndex); bool firstVisible = tabBarRect.contains(firstTabRect); bool lastVisible = tabBarRect.contains(lastTabRect); bool noOverFlow = firstVisible && lastVisible; mp_ui->prevTabButton->setHidden(noOverFlow); mp_ui->nextTabButton->setHidden(noOverFlow); mp_ui->prevTabButton->setDisabled(tabBar->currentIndex() == 0); mp_ui->nextTabButton->setDisabled(tabBar->currentIndex() == lastTabIndex); } bool MainWindow::eventFilter(QObject* /*object*/, QEvent* event) { if (event->type() == QEvent::MouseMove && isFullScreen()) { const auto mouseEvent = static_cast(event); const int tabRegion = getTabBar()->height() + getTopWidget()->height() + 30; int clickY = portutils::getY(*mouseEvent); // We don't have to check for visibilty as calling hide() on a hidden widget, or show() on a non-hidden widget is a no-op if (clickY == 0) { showTabAndTop(); } else if(clickY >= tabRegion) { hideTabAndTop(); } } return false; } void MainWindow::closeEvent(QCloseEvent *event) { KiwixApp::instance()->saveWindowState(); QMainWindow::closeEvent(event); } void MainWindow::resizeEvent(QResizeEvent *event) { QMainWindow::resizeEvent(event); KiwixApp::instance()->getContentManager()->getView()->updateSizeHint(); updateTabButtons(); } void checkActionNoSignal(KiwixApp::Actions actionFlag, bool checked) { const auto action = KiwixApp::instance()->getAction(actionFlag); const bool oldState = action->blockSignals(true); action->setChecked(checked); action->blockSignals(oldState); } void MainWindow::readingListToggled(bool state) { if (state) { checkActionNoSignal(KiwixApp::ToggleTOCAction, false); mp_ui->sideBar->setCurrentWidget(mp_ui->readinglistbar); mp_ui->sideBar->show(); } else { mp_ui->sideBar->hide(); } } void MainWindow::tableOfContentToggled(bool state) { if (state) { checkActionNoSignal(KiwixApp::ToggleReadingListAction, false); mp_ui->sideBar->setCurrentWidget(mp_ui->tableofcontentbar); mp_ui->sideBar->show(); } else { mp_ui->sideBar->hide(); } } void MainWindow::tabChanged(TabType tabType) { QAction *readingList = KiwixApp::instance()->getAction(KiwixApp::ToggleReadingListAction); QAction *tableOfContent = KiwixApp::instance()->getAction(KiwixApp::ToggleTOCAction); if (tabType == TabType::SettingsTab) { mp_ui->sideBar->hide(); } else if(tabType == TabType::LibraryTab) { mp_ui->sideBar->setCurrentWidget(mp_ui->contentmanagerside); mp_ui->sideBar->show(); } else if (readingList->isChecked()) { readingListToggled(true); } else if (tableOfContent->isChecked()) { tableOfContentToggled(true); } else { mp_ui->sideBar->hide(); } } TabBar* MainWindow::getTabBar() { return mp_ui->tabBar; } TopWidget *MainWindow::getTopWidget() { return mp_ui->mainToolBar; } TableOfContentBar *MainWindow::getTableOfContentBar() { return mp_ui->tableofcontentbar; } kiwix-desktop-2.4.1/src/mainwindow.h000066400000000000000000000021331473106011000174240ustar00rootroot00000000000000#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "webview.h" #include "tabbar.h" #include "topwidget.h" #include "about.h" #include "contentmanagerside.h" #include "localkiwixserver.h" namespace Ui { class MainWindow; } class TableOfContentBar; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); TabBar* getTabBar(); TopWidget* getTopWidget(); QWidget getMainView(); TableOfContentBar *getTableOfContentBar(); protected: bool eventFilter(QObject* object, QEvent* event) override; void closeEvent(QCloseEvent *event) override; void resizeEvent(QResizeEvent *event) override; private slots: void toggleFullScreen(); void tabChanged(TabBar::TabType); void readingListToggled(bool state); void tableOfContentToggled(bool state); void hideTabAndTop(); void showTabAndTop(); void updateTabButtons(); private: Ui::MainWindow *mp_ui; About *mp_about; LocalKiwixServer *mp_localKiwixServer; }; #endif // MAINWINDOW_H kiwix-desktop-2.4.1/src/menuproxystyle.h000066400000000000000000000010561473106011000204020ustar00rootroot00000000000000#include class MenuProxyStyle: public QProxyStyle { Q_OBJECT public: MenuProxyStyle(QStyle * style = 0) : QProxyStyle(style) {} MenuProxyStyle(const QString & key) : QProxyStyle(key) {} virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption * option = 0, const QWidget * widget = 0 ) const { switch ( metric ) { case QStyle::PM_SmallIconSize: return 25; default: return QProxyStyle::pixelMetric( metric, option, widget ); } } }; kiwix-desktop-2.4.1/src/multizimbutton.cpp000066400000000000000000000142251473106011000207160ustar00rootroot00000000000000#include #include #include #include #include #include "kiwixapp.h" #include "multizimbutton.h" #include "css_constants.h" QString getElidedText(const QFont& font, int length, const QString& text); MultiZimButton::MultiZimButton(QWidget *parent) : QToolButton(parent), mp_buttonList(new QListWidget), mp_radioButtonGroup(new QButtonGroup(this)) { setMenu(new QMenu(this)); setPopupMode(QToolButton::InstantPopup); setDefaultAction(KiwixApp::instance()->getAction(KiwixApp::OpenMultiZimAction)); connect(this, &QToolButton::triggered, this, &MultiZimButton::showMenu); const auto popupAction = new QWidgetAction(menu()); popupAction->setDefaultWidget(mp_buttonList); menu()->addAction(popupAction); connect(mp_buttonList, &QListWidget::currentRowChanged, this, [=](int row){ if (const auto widget = getZimWidget(row)) widget->getRadioButton()->setChecked(true); }); } void MultiZimButton::updateDisplay() { mp_buttonList->clear(); for (const auto& button : mp_radioButtonGroup->buttons()) mp_radioButtonGroup->removeButton(button); const auto library = KiwixApp::instance()->getLibrary(); const auto view = KiwixApp::instance()->getTabWidget()->currentWebView(); QListWidgetItem* currentItem = nullptr; QIcon currentIcon; const int paddingTopBot = CSS::MultiZimButton::QListWidget::paddingVertical * 2; const int itemHeight = paddingTopBot + CSS::ZimItemWidget::QLabel::lineHeight; for (const auto& bookId : library->getBookIds()) { try { library->getArchive(bookId); } catch (...) { continue; } const QString bookTitle = QString::fromStdString(library->getBookById(bookId).getTitle()); const QIcon zimIcon = library->getBookIcon(bookId); const auto item = new QListWidgetItem(); item->setData(Qt::UserRole, bookId); item->setData(Qt::DisplayRole, bookTitle); item->setSizeHint(QSize(0, itemHeight)); if (view && view->zimId() == bookId) { currentItem = item; currentIcon = zimIcon; continue; } mp_buttonList->addItem(item); setItemZimWidget(item, bookTitle, zimIcon); } mp_buttonList->sortItems(); if (currentItem) { mp_buttonList->insertItem(0, currentItem); const auto title = currentItem->data(Qt::DisplayRole).toString(); setItemZimWidget(currentItem, "*" + title, currentIcon); } /* Display should not be used other than for sorting. */ for (int i = 0; i < mp_buttonList->count(); i++) mp_buttonList->item(i)->setData(Qt::DisplayRole, QVariant()); setDisabled(mp_buttonList->model()->rowCount() == 0); mp_buttonList->scrollToTop(); mp_buttonList->setCurrentRow(0); /* We set a maximum display height for list. Respect padding. */ const int listHeight = itemHeight * std::min(7, mp_buttonList->count()); mp_buttonList->setFixedHeight(listHeight + paddingTopBot); mp_buttonList->setFixedWidth(menu()->width()); } QStringList MultiZimButton::getZimIds() const { QStringList idList; for (int row = 0; row < mp_buttonList->count(); row++) { const auto widget = getZimWidget(row); if (widget && widget->getRadioButton()->isChecked()) idList.append(mp_buttonList->item(row)->data(Qt::UserRole).toString()); } return idList; } ZimItemWidget *MultiZimButton::getZimWidget(int row) const { const auto widget = mp_buttonList->itemWidget(mp_buttonList->item(row)); return qobject_cast(widget); } void MultiZimButton::setItemZimWidget(QListWidgetItem *item, const QString &title, const QIcon &icon) { const auto zimWidget = new ZimItemWidget(title, icon); mp_radioButtonGroup->addButton(zimWidget->getRadioButton()); mp_buttonList->setItemWidget(item, zimWidget); } ZimItemWidget::ZimItemWidget(QString text, QIcon icon, QWidget *parent) : QWidget(parent), textLabel(new QLabel(this)), iconLabel(new QLabel(this)), radioBt(new QRadioButton(this)) { setLayout(new QHBoxLayout); const int paddingHorizontal = CSS::MultiZimButton::QListWidget::item::paddingHorizontal; layout()->setSpacing(paddingHorizontal); layout()->setContentsMargins(0, 0, 0, 0); const int iconWidth = CSS::ZimItemWidget::QLabel::lineHeight; const QSize iconSize = QSize(iconWidth, iconWidth); iconLabel->setPixmap(icon.pixmap(iconSize)); /* Align text on same side irregardless of text direction. */ const bool needAlignReverse = KiwixApp::isRightToLeft() == text.isRightToLeft(); const auto align = needAlignReverse ? Qt::AlignLeft : Qt::AlignRight; textLabel->setAlignment({Qt::AlignVCenter | align}); /* Need to align checkmark with select all button. Avoid scroller from changing checkmark position by always leaving out space on scroller's side. Do this by align items to the other side and reducing the total length. textLabel is the only expandable element here. We set textLabel width to make sure the entire length always leave out a fixed amount of white space for scroller. */ layout()->setAlignment({Qt::AlignVCenter | Qt::AlignLeading}); const auto menu = KiwixApp::instance()->getSearchBar().getMultiZimButton().menu(); const int iconAndCheckerWidth = iconWidth * 2; const int totalSpacing = paddingHorizontal * 4; /* Add an extra border to counteract item border on one side */ const int border = CSS::MultiZimButton::QListWidget::item::border; const int scrollerWidth = CSS::MultiZimButton::QScrollBar::width; const int contentWidthExcludeText = iconAndCheckerWidth + totalSpacing + scrollerWidth + border; const int labelWidth = menu->width() - contentWidthExcludeText; textLabel->setFixedWidth(labelWidth); QString elidedText = getElidedText(textLabel->font(), labelWidth, text); textLabel->setText(elidedText == text ? text : elidedText.trimmed() + "(...)"); layout()->addWidget(iconLabel); layout()->addWidget(textLabel); layout()->addWidget(radioBt); } kiwix-desktop-2.4.1/src/multizimbutton.h000066400000000000000000000016101473106011000203550ustar00rootroot00000000000000#ifndef MULTIZIMBUTTON_H #define MULTIZIMBUTTON_H #include class QListWidget; class QButtonGroup; class QListWidgetItem; class QRadioButton; class QLabel; class ZimItemWidget : public QWidget { Q_OBJECT public: ZimItemWidget(QString text, QIcon icon, QWidget *parent = nullptr); QRadioButton* getRadioButton() const { return radioBt; } private: QLabel* textLabel; QLabel* iconLabel; QRadioButton* radioBt; }; class MultiZimButton : public QToolButton { Q_OBJECT public: explicit MultiZimButton(QWidget *parent = nullptr); public slots: void updateDisplay(); QStringList getZimIds() const; private: QListWidget* mp_buttonList; QButtonGroup* mp_radioButtonGroup; ZimItemWidget* getZimWidget(int row) const; void setItemZimWidget(QListWidgetItem* item, const QString& title, const QIcon& icon); }; #endif // MULTIZIMBUTTON_H kiwix-desktop-2.4.1/src/node.h000066400000000000000000000006701473106011000162010ustar00rootroot00000000000000#ifndef NODE_H #define NODE_H #include #include class Node : public std::enable_shared_from_this { public: virtual ~Node() = default; virtual std::shared_ptr parentItem() = 0; virtual int childCount() const = 0; virtual int columnCount() const = 0; virtual QVariant data(int column) = 0; virtual int row() const = 0; virtual QString getBookId() const = 0; }; #endif // NODE_H kiwix-desktop-2.4.1/src/opdsrequestmanager.cpp000066400000000000000000000053401473106011000215170ustar00rootroot00000000000000#include "opdsrequestmanager.h" #include "kiwixapp.h" OpdsRequestManager::OpdsRequestManager() { } QString OpdsRequestManager::getCatalogHost() { const char* const envVarVal = getenv("KIWIX_CATALOG_HOST"); return envVarVal ? envVarVal : "library.kiwix.org"; } int OpdsRequestManager::getCatalogPort() { const char* const envVarVal = getenv("KIWIX_CATALOG_PORT"); return envVarVal ? atoi(envVarVal) : 443; } void OpdsRequestManager::doUpdate(const QString& currentLanguage, const QString& categoryFilter) { QUrlQuery query; // Service worker ZIM files are not (yet) supported QStringList excludeTags("_sw:yes"); // Add filter by language (if necessary) if (currentLanguage != "") { query.addQueryItem("lang", currentLanguage); } // Request all results (no pagination) query.addQueryItem("count", QString::number(-1)); // Add filter by category (if necessary) if (categoryFilter != "") { query.addQueryItem("category", categoryFilter); } auto mp_reply = opdsResponseFromPath("/catalog/search", query); connect(mp_reply, &QNetworkReply::finished, this, [=]() { receiveContent(mp_reply); }); } QNetworkReply* OpdsRequestManager::opdsResponseFromPath(const QString &path, const QUrlQuery &query) { QUrl url; const int port = getCatalogPort(); url.setScheme(port == 443 ? "https" : "http"); url.setHost(getCatalogHost()); url.setPort(port); url.setPath(path); url.setQuery(query); qInfo() << "Downloading" << url.toString(QUrl::FullyEncoded); QNetworkRequest request(url); return m_networkManager.get(request); } void OpdsRequestManager::getLanguagesFromOpds() { auto mp_reply = opdsResponseFromPath("/catalog/v2/languages"); connect(mp_reply, &QNetworkReply::finished, this, [=]() { receiveLanguages(mp_reply); }); } void OpdsRequestManager::getCategoriesFromOpds() { auto mp_reply = opdsResponseFromPath("/catalog/v2/categories"); connect(mp_reply, &QNetworkReply::finished, this, [=]() { receiveCategories(mp_reply); }); } QString replyContent(QNetworkReply *mp_reply) { QString content; if (mp_reply->error() != QNetworkReply::OperationCanceledError) { content = mp_reply->readAll().data(); } mp_reply->deleteLater(); mp_reply = nullptr; return content; } void OpdsRequestManager::receiveLanguages(QNetworkReply *mp_reply) { emit(languagesReceived(replyContent(mp_reply))); } void OpdsRequestManager::receiveCategories(QNetworkReply *mp_reply) { emit(categoriesReceived(replyContent(mp_reply))); } void OpdsRequestManager::receiveContent(QNetworkReply *mp_reply) { emit(requestReceived(replyContent(mp_reply))); } kiwix-desktop-2.4.1/src/opdsrequestmanager.h000066400000000000000000000017351473106011000211700ustar00rootroot00000000000000#ifndef OPDSREQUESTMANAGER_H #define OPDSREQUESTMANAGER_H #include #include #include #include class OpdsRequestManager : public QObject { Q_OBJECT public: OpdsRequestManager(); ~OpdsRequestManager() {} public: void doUpdate(const QString& currentLanguage, const QString& categoryFilter); void getLanguagesFromOpds(); void getCategoriesFromOpds(); private: QNetworkAccessManager m_networkManager; QNetworkReply* opdsResponseFromPath(const QString &path, const QUrlQuery &query = QUrlQuery()); signals: void requestReceived(const QString&); void languagesReceived(const QString&); void categoriesReceived(const QString&); public slots: void receiveContent(QNetworkReply*); void receiveLanguages(QNetworkReply*); void receiveCategories(QNetworkReply*); public: static QString getCatalogHost(); static int getCatalogPort(); }; #endif // OPDSREQUESTMANAGER_H kiwix-desktop-2.4.1/src/portutils.h000066400000000000000000000013041473106011000173140ustar00rootroot00000000000000#ifndef PORTUTILS_H #define PORTUTILS_H #include namespace portutils { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // Earlier than Qt6 inline int getX(const QMouseEvent& e) { return e.x(); } inline int getY(const QMouseEvent& e) { return e.y(); } inline QPoint getGlobalPos(const QMouseEvent& e) { return e.globalPos(); } #else // Qt6 and later inline int getX(const QMouseEvent& e) { return e.position().x(); } inline int getY(const QMouseEvent& e) { return e.position().y(); } inline QPoint getGlobalPos(const QMouseEvent& e) { return e.globalPosition().toPoint(); } #endif } #endif // PORTUTILS_H kiwix-desktop-2.4.1/src/readinglistbar.cpp000066400000000000000000000114761473106011000206070ustar00rootroot00000000000000#include "readinglistbar.h" #include "ui_readinglistbar.h" #include "kiwixapp.h" #include "zim/error.h" #include "zim/item.h" #include #include #include const QString documentsDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); ReadingListBar::ReadingListBar(QWidget *parent) : QFrame(parent), ui(new Ui::readinglistbar) { ui->setupUi(this); ui->titleLabel->setText(gt("reading-list")); connect(KiwixApp::instance()->getLibrary(), &Library::bookmarksChanged, this, &ReadingListBar::setupList); connect(ui->listWidget, &QListWidget::itemClicked, this, &ReadingListBar::onItemClicked); connect(ui->listWidget, &QListWidget::itemDoubleClicked, this, &ReadingListBar::onItemDoubleClicked); connect(ui->listWidget, &QListWidget::itemPressed, this, [this](QListWidgetItem* item) { onItemPressed(item, QGuiApplication::mouseButtons()); }); connect(ui->listWidget, &QListWidget::itemActivated, this, [this](QListWidgetItem* item) { onItemActivated(item, QGuiApplication::mouseButtons()); }); setupList(); auto app = KiwixApp::instance(); auto exportAction = app->getAction(KiwixApp::ExportReadingListAction); auto importAction = app->getAction(KiwixApp::ImportReadingListAction); connect(exportAction, &QAction::triggered, this, &ReadingListBar::onExport); connect(importAction, &QAction::triggered, this, &ReadingListBar::onImport); QMenu *portMenu = new QMenu(this); portMenu->addAction(exportAction); portMenu->addAction(importAction); ui->readingListMenuButton->setMenu(portMenu); } ReadingListBar::~ReadingListBar() { delete ui; } void ReadingListBar::setupList() { auto library = KiwixApp::instance()->getLibrary(); auto bookmarks = library->getBookmarks(); auto listWidget = ui->listWidget; listWidget->clear(); for(auto& bookmark:bookmarks) { const auto zimId = QString::fromStdString(bookmark.getBookId()); try { library->getArchive(zimId); } catch (std::out_of_range& e) { continue; } new QListWidgetItem( library->getBookIcon(zimId), QString::fromStdString(bookmark.getTitle()), listWidget); } } // Receives single clicks void ReadingListBar::onItemClicked(QListWidgetItem* item) { clickKind = 1; QTimer::singleShot(QApplication::doubleClickInterval(), [=]() { // Give time for a double click be handled if (clickKind == 1) { openUrl(item, false); } }); } // Receives double clicks void ReadingListBar::onItemDoubleClicked(QListWidgetItem* item) { clickKind = 2; openUrl(item, true); } // Receives single and middle click void ReadingListBar::onItemPressed(QListWidgetItem* item, Qt::MouseButtons buttons) { if (buttons & Qt::MiddleButton) { openUrl(item, true); } } // Receives left clicks and activation key void ReadingListBar::onItemActivated(QListWidgetItem* item, Qt::MouseButtons buttons) { if (!buttons) { // clicks are handled elsewhere, handle only the activation key case openUrl(item, true); } } void ReadingListBar::onExport() { auto app = KiwixApp::instance(); auto kiwixLibrary = app->getLibrary()->getKiwixLibrary(); auto suggestedFilePath = documentsDir + "/kiwix_readinglist.xml"; QString fileName = QFileDialog::getSaveFileName(app->getMainWindow(), gt("save-file-as-window-title"), suggestedFilePath, "(*.xml)"); if (fileName.isEmpty()) return; if (!kiwixLibrary->writeBookmarksToFile(fileName.toStdString())) app->showMessage(gt("export-reading-list-error"), gt("error-title"), QMessageBox::Information); } void ReadingListBar::onImport() { auto app = KiwixApp::instance(); auto library = app->getLibrary(); QString fileName = QFileDialog::getOpenFileName(app->getMainWindow(), gt("open-file"), documentsDir, "(*.xml)"); if (fileName.isEmpty()) return; if (!library->readBookMarksFile(fileName.toStdString())) app->showMessage(gt("import-reading-list-error"), gt("error-title"), QMessageBox::Information); } void ReadingListBar::openUrl(QListWidgetItem* item, bool newTab) { int index = ui->listWidget->row(item); auto bookmark = KiwixApp::instance()->getLibrary()->getBookmarks(true).at(index); QUrl url; url.setScheme("zim"); url.setHost(QString::fromStdString(bookmark.getBookId())+".zim"); url.setPath(QString::fromStdString(bookmark.getUrl())); KiwixApp::instance()->openUrl(url, newTab); } kiwix-desktop-2.4.1/src/readinglistbar.h000066400000000000000000000013521473106011000202440ustar00rootroot00000000000000#ifndef READINGLISTBAR_H #define READINGLISTBAR_H #include #include namespace Ui { class readinglistbar; } class ReadingListBar : public QFrame { Q_OBJECT public: explicit ReadingListBar(QWidget *parent = nullptr); ~ReadingListBar(); public slots: void setupList(); void onItemClicked(QListWidgetItem* item); void onItemDoubleClicked(QListWidgetItem *item); void onItemPressed(QListWidgetItem* item, Qt::MouseButtons buttons); void onItemActivated(QListWidgetItem *item, Qt::MouseButtons buttons); void onExport(); void onImport(); private: Ui::readinglistbar *ui; int clickKind; void openUrl(QListWidgetItem* item, bool newTab); }; #endif // READINGLISTBAR_H kiwix-desktop-2.4.1/src/readinglistbar.ui000066400000000000000000000060621473106011000204350ustar00rootroot00000000000000 readinglistbar 0 0 400 300 Form 0 0 0 0 0 16 Reading List Qt::Horizontal 40 20 :/icons/more-vertical.svg:/icons/more-vertical.svg 25 25 true Qt::Horizontal QFrame::NoFrame 0 Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::ElideRight false true true kiwix-desktop-2.4.1/src/rownode.cpp000066400000000000000000000033371473106011000172670ustar00rootroot00000000000000#include "rownode.h" #include #include "kiwixapp.h" #include "descriptionnode.h" //////////////////////////////////////////////////////////////////////////////// // RowNode //////////////////////////////////////////////////////////////////////////////// RowNode::RowNode(QList itemData, QString bookId, std::weak_ptr parent) : m_itemData(itemData), m_parentItem(parent), m_bookId(bookId) { } RowNode::~RowNode() {} void RowNode::appendChild(std::shared_ptr item) { m_childItems.append(item); } std::shared_ptr RowNode::child(int row) { if (row < 0 || row >= m_childItems.size()) return nullptr; return m_childItems.at(row); } int RowNode::childCount() const { return m_childItems.count(); } int RowNode::columnCount() const { return 6; } std::shared_ptr RowNode::parentItem() { std::shared_ptr temp = m_parentItem.lock(); if (!temp) return nullptr; return temp; } QVariant RowNode::data(int column) { if (column < 0 || column >= m_itemData.size()) return QVariant(); return m_itemData.at(column); } int RowNode::row() const { try { std::shared_ptr temp = m_parentItem.lock(); if (temp) { auto nodePtr = std::const_pointer_cast(shared_from_this()); return temp->m_childItems.indexOf(nodePtr); } } catch(...) { return 0; } return 0; } bool RowNode::isChild(Node *candidate) { if (!candidate) return false; for (auto item : m_childItems) { if (candidate == item.get()) return true; } return false; } void RowNode::setDownloadState(std::shared_ptr ds) { m_downloadState = ds; } kiwix-desktop-2.4.1/src/rownode.h000066400000000000000000000021501473106011000167240ustar00rootroot00000000000000#ifndef ROWNODE_H #define ROWNODE_H #include "node.h" #include #include #include "kiwix/book.h" #include "downloadmanagement.h" class RowNode : public Node { public: explicit RowNode(QList itemData, QString bookId, std::weak_ptr parentItem); ~RowNode(); std::shared_ptr parentItem() override; std::shared_ptr child(int row); void appendChild(std::shared_ptr child); int childCount() const override; int columnCount() const override; QVariant data(int column) override; int row() const override; QString getBookId() const override { return m_bookId; } void setIconData(QByteArray iconData) { m_itemData[0] = iconData; } bool isChild(Node* candidate); void setDownloadState(std::shared_ptr ds); std::shared_ptr getDownloadState() { return m_downloadState; } private: QList m_itemData; QList> m_childItems; std::weak_ptr m_parentItem; QString m_bookId; std::shared_ptr m_downloadState; }; #endif // ROWNODE_H kiwix-desktop-2.4.1/src/searchbar.cpp000066400000000000000000000407411473106011000175440ustar00rootroot00000000000000#include "searchbar.h" #include #include #include #include #include "kiwixapp.h" #include "suggestionlistworker.h" #include "css_constants.h" #include "suggestionlistdelegate.h" namespace HeaderSectionCSS = CSS::PopupCSS::QHeaderView::section; BookmarkButton::BookmarkButton(QWidget *parent) : QToolButton(parent) { connect(this, &QToolButton::triggered, this, &BookmarkButton::on_buttonClicked); connect(this, &QToolButton::triggered, this, &BookmarkButton::update_display); setDefaultAction(KiwixApp::instance()->getAction(KiwixApp::Actions::ToggleAddBookmarkAction)); auto library = KiwixApp::instance()->getLibrary(); connect(library, &Library::bookmarksChanged, this, &BookmarkButton::update_display); } void BookmarkButton::update_display() { auto isBookMarked = KiwixApp::instance()->isCurrentArticleBookmarked(); auto buttonText = isBookMarked ? gt("remove-bookmark") : gt("add-bookmark"); defaultAction()->setChecked(isBookMarked); defaultAction()->setToolTip(buttonText); defaultAction()->setText(buttonText); } void BookmarkButton::on_buttonClicked() { auto kiwixApp = KiwixApp::instance(); auto library = kiwixApp->getLibrary(); auto tabWidget = kiwixApp->getTabWidget(); if (kiwixApp->isCurrentArticleBookmarked()) { auto zimid = tabWidget->currentZimId(); library->removeBookmark( zimid, tabWidget->currentArticleUrl() ); } else { kiwix::Bookmark bookmark; auto zimid = tabWidget->currentZimId().toStdString(); bookmark.setBookId(zimid); bookmark.setUrl(tabWidget->currentArticleUrl().toStdString()); bookmark.setTitle(tabWidget->currentArticleTitle().toStdString()); library->addBookmark(bookmark); } library->save(); } SearchBarLineEdit::SearchBarLineEdit(QWidget *parent) : QLineEdit(parent), m_suggestionView(new QTreeView), m_completer(&m_suggestionModel, this) { installEventFilter(this); setAlignment(KiwixApp::isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft); mp_typingTimer = new QTimer(this); mp_typingTimer->setSingleShot(true); /* Placeholder does not affect line edit alignment and is aligned to line edit purely by text direction (LTR leading RTL ending). Thus, we need directional mask to make it LTR at leading position. https://stackoverflow.com/questions/66430215/english-and-arabic-mixed-string-not-ordered-correctly-qt */ const QString ltrConversionChar(u8"\u200e"); setPlaceholderText(ltrConversionChar + gt("search")); setToolTip(gt("search")); m_completer.setCompletionMode(QCompleter::UnfilteredPopupCompletion); m_completer.setCaseSensitivity(Qt::CaseInsensitive); /* The items should be less than fetch size to enable scrolling. */ m_completer.setMaxVisibleItems(SuggestionListWorker::getFetchSize() / 2); m_completer.setWidget(this); /* QCompleter's uses default list views, which do not have headers. */ m_completer.setPopup(m_suggestionView); /* The Delegate was overwritten by setPopup(), which is not style-aware */ m_suggestionView->setItemDelegate(new SuggestionListDelegate(this)); m_suggestionView->header()->setStretchLastSection(true); m_suggestionView->setRootIsDecorated(false); m_suggestionView->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/popup.css")); const int contentHeight = HeaderSectionCSS::lineHeight; m_suggestionView->setIconSize(QSize(contentHeight, contentHeight)); /* The suggestionView sizing unfortunately is not aware of headers. We have to do this manually. We also sized header the same as items. */ connect(&m_suggestionModel, &QAbstractListModel::modelReset, [=](){ /* +1 for header. */ const int maxItem = m_completer.maxVisibleItems(); const int count = std::min(m_suggestionModel.rowCount(), maxItem) + 1; const int itemHeight = m_suggestionView->sizeHintForRow(0); /* Extra space styling above header and below last suggestion item. */ const int extraMargin = 2 * HeaderSectionCSS::marginTop; m_suggestionView->setFixedHeight(itemHeight * count + extraMargin); }); connect(m_suggestionView->verticalScrollBar(), &QScrollBar::valueChanged, this, &SearchBarLineEdit::onScroll); qRegisterMetaType>("QList"); connect(mp_typingTimer, &QTimer::timeout, this, &SearchBarLineEdit::updateCompletion); connect(this, &QLineEdit::textEdited, this, [=](const QString &text) { m_searchbarInput = text; m_returnPressed = false; mp_typingTimer->start(100); }); connect(this, &QLineEdit::textChanged, this, [=](const QString &text) { Q_UNUSED(text) if (m_returnPressed) { this->setText(m_searchbarInput); } /* Empty text is LTR which changes the line edit alignment. Need to explicitly align right. This is a generalized solution that aligns text to the direction of the app. */ bool isSameDirection = text.isRightToLeft() == KiwixApp::isRightToLeft(); setAlignment(isSameDirection ? Qt::AlignLeft : Qt::AlignRight); }); connect(this, &QLineEdit::returnPressed, this, [=]() { m_returnPressed = true; /* Open default index when nothing is selected. Key_Return can be pressed during typing, where suggestions no longer match the text typed. Hence the suggestionsValid check. */ const bool suggestionsValid = m_suggestionsAreValidFor == m_searchbarInput; if (!m_suggestionView->currentIndex().isValid() && suggestionsValid) openCompletion(getDefaulSuggestionIndex()); }); auto app = KiwixApp::instance(); connect(app->getAction(KiwixApp::SearchArticleAction), &QAction::triggered, this, [=]() { this->selectAll(); this->setFocus(Qt::ShortcutFocusReason); }); } void SearchBarLineEdit::hideSuggestions() { m_suggestionView->hide(); } bool SearchBarLineEdit::eventFilter(QObject *, QEvent *event) { if (!(m_aboutToScrollPastEnd && m_moreSuggestionsAreAvailable)) return false; if (const auto e = dynamic_cast(event)) { const auto key = e->key(); const bool isScrollDownKey = key == Qt::Key_Down || key == Qt::Key_PageDown; const bool noModifiers = e->modifiers().testFlag(Qt::NoModifier); if (isScrollDownKey && noModifiers) { m_aboutToScrollPastEnd = false; fetchMoreSuggestions(); return true; } } return false; } void SearchBarLineEdit::clearSuggestions() { m_suggestionModel.resetSuggestions(); m_moreSuggestionsAreAvailable = false; } void SearchBarLineEdit::on_currentTitleChanged(const QString& title) { if (this->hasFocus()) { return; } if (!title.startsWith("zim://")) { setText(title); } else { setText(""); } m_title = title; } void SearchBarLineEdit::focusInEvent( QFocusEvent* event) { setReadOnly(false); if (event->reason() == Qt::MouseFocusReason && text() == m_title) { clear(); } if (event->reason() == Qt::ActiveWindowFocusReason || event->reason() == Qt::MouseFocusReason || event->reason() == Qt::ShortcutFocusReason || event->reason() == Qt::PopupFocusReason) { connect(&m_completer, QOverload::of(&QCompleter::activated), this, &QLineEdit::setText,Qt::UniqueConnection); connect(&m_completer, QOverload::of(&QCompleter::activated), this, QOverload::of(&SearchBarLineEdit::openCompletion), Qt::UniqueConnection); connect(&m_completer, QOverload::of(&QCompleter::highlighted), this, [=](const QModelIndex &index){ setText(index.isValid() ? index.data().toString() : m_searchbarInput); }, Qt::UniqueConnection); } QLineEdit::focusInEvent(event); } void SearchBarLineEdit::focusOutEvent(QFocusEvent* event) { setReadOnly(true); if (event->reason() == Qt::MouseFocusReason && text().isEmpty()) { setText(m_title); } deselect(); disconnect(&m_completer, nullptr, this, nullptr); return QLineEdit::focusOutEvent(event); } void SearchBarLineEdit::updateCompletion() { mp_typingTimer->stop(); clearSuggestions(); const auto& multiZim = KiwixApp::instance()->getSearchBar().getMultiZimButton(); if (multiZim.getZimIds().isEmpty() || m_searchbarInput.isEmpty()) { hideSuggestions(); return; } m_token++; fetchSuggestions(&SearchBarLineEdit::onInitialSuggestions); } void SearchBarLineEdit::fetchMoreSuggestions() { /* TODO: Refactor suggestion worker to re-use zim::SuggestionSearcher for fetching more suggestion in a single archive. Currently we create a searcher for every fetch, and discarded after one use. */ fetchSuggestions(&SearchBarLineEdit::onAdditionalSuggestions); } void SearchBarLineEdit::onScroll(int value) { if (!m_moreSuggestionsAreAvailable) { m_aboutToScrollPastEnd = false; return; } /* Scrolling using key_down past end will teleport scroller to the top. We undo this here. Block signal to avoid recursion. We cannot find a way to intercept the scrolling in eventFilter so, until we find out how, this code is here to stay. */ if (!m_suggestionView->currentIndex().isValid()) { const auto old = m_suggestionView->verticalScrollBar()->blockSignals(true); m_suggestionView->scrollToBottom(); m_suggestionView->verticalScrollBar()->blockSignals(old); return; } const auto suggestionScroller = m_suggestionView->verticalScrollBar(); const auto scrollMin = suggestionScroller->minimum(); const auto scrollMax = suggestionScroller->maximum(); const bool scrolledToEnd = value == suggestionScroller->maximum(); if (m_aboutToScrollPastEnd) { if (scrolledToEnd) { /* The user's intention to scroll past end has been confirmed */ fetchMoreSuggestions(); m_aboutToScrollPastEnd = false; /* Relax until next time */ } else { /* Scrolling past end did not happen - remove the extra scroll room created for detecting the intention of scrolling past end */ suggestionScroller->setRange(scrollMin, scrollMax - 1); m_aboutToScrollPastEnd = false; /* ... and relax */ } } else if (scrolledToEnd) { /* The user has scrolled to end - monitor for furthur scrolling */ m_aboutToScrollPastEnd = true; /* Create some fictitious room for an extra scroll */ suggestionScroller->setRange(scrollMin, scrollMax + 1); } } void SearchBarLineEdit::openCompletion(const QModelIndex &index) { if (index.isValid()) { const QUrl url = index.data(Qt::UserRole).toUrl(); const auto app = KiwixApp::instance(); const bool newTab = app->getTabWidget()->currentWebView() == nullptr; QTimer::singleShot(0, [=](){KiwixApp::instance()->openUrl(url, newTab);}); } } void SearchBarLineEdit::onInitialSuggestions(int) { if (m_returnPressed) { openCompletion(getDefaulSuggestionIndex()); } else { m_completer.complete(getCompleterRect()); /* Select nothing by default */ const auto completerSelModel = m_suggestionView->selectionModel(); completerSelModel->setCurrentIndex(QModelIndex(), QItemSelectionModel::Current); } } void SearchBarLineEdit::onAdditionalSuggestions(int start) { /* Set selection to be at the last row of the previous list */ const auto completerStartIdx = m_suggestionView->model()->index(start, 0); m_suggestionView->setCurrentIndex(completerStartIdx); m_suggestionView->show(); } void SearchBarLineEdit::fetchSuggestions(NewSuggestionHandlerFuncPtr callback) { const int start = m_suggestionModel.countOfRegularSuggestions(); const auto searchText = m_searchbarInput; const auto suggestionWorker = new SuggestionListWorker(searchText, m_token, start, this); connect(suggestionWorker, &SuggestionListWorker::searchFinished, this, [=] (const QList& suggestionList, int token) { if (token != m_token) { return; } m_suggestionModel.append(suggestionList); m_suggestionsAreValidFor = searchText; const int listSize = suggestionList.size(); const bool hasFullText = listSize > 0 && suggestionList.back().isFullTextSearchSuggestion(); const int maxFetchSize = SuggestionListWorker::getFetchSize() + hasFullText; m_moreSuggestionsAreAvailable = listSize >= maxFetchSize; (this->*callback)(start); }); connect(suggestionWorker, &SuggestionListWorker::finished, suggestionWorker, &QObject::deleteLater); suggestionWorker->start(); } QModelIndex SearchBarLineEdit::getDefaulSuggestionIndex() const { const auto firstSuggestionIndex = m_suggestionModel.index(0); if (!firstSuggestionIndex.isValid()) return firstSuggestionIndex; /* If the first entry matches the typed text, use it as default, otherwise use the last entry if fulltext search exist. */ const auto firstSuggestionText = firstSuggestionIndex.data().toString(); if (this->text().compare(firstSuggestionText, Qt::CaseInsensitive) == 0) return firstSuggestionIndex; else if (m_suggestionModel.hasFullTextSearchSuggestion()) return m_suggestionModel.index(m_suggestionModel.rowCount() - 1); return QModelIndex(); } /* Line edit does not span the entire searchBar. Completer is displayed based on line edit, and thus shifting and resizing is needed. */ QRect SearchBarLineEdit::getCompleterRect() const { auto& searchBar = KiwixApp::instance()->getSearchBar(); const auto& searchGeo = searchBar.geometry(); const auto& searchLineEditGeo = searchBar.getLineEdit().geometry(); const int margin = CSS::SearchBar::margin; const int border = CSS::SearchBar::border; const int spaceAround = margin + border; /* Border and margin are not accounted in height and width. */ const int top = searchGeo.height() - 2 * spaceAround; const int width = searchGeo.width() - 2 * spaceAround; /* Shift completer to one of the two laterals of search bar, where which one it shifted to dependes on whether the line edit is flipped. */ int left = -searchLineEditGeo.left(); /* When not flipped, left() is relative to within the search bar border, thus, we shift by spaceAround to match the side of search bar. When flipped, the completer starts at the right end of the search bar We shift it by width to make the completer start at left lateral of search bar. Since in a flipped state, left() also considered the opposite side's border, which means we need to shift by a border width in addition to spaceAround. */ left += isRightToLeft() ? -width + spaceAround + border : spaceAround; /* Can't set height to 0. Will cause rectangle to be ignored. */ return QRect(QPoint(left, top), QSize(width, 1)); } SearchBar::SearchBar(QWidget *parent) : QToolBar(parent), m_searchBarLineEdit(this), m_bookmarkButton(this), m_multiZimButton(this) { QLabel* searchIconLabel = new QLabel; searchIconLabel->setObjectName("searchIcon"); searchIconLabel->setPixmap(QIcon(":/icons/search.svg").pixmap(QSize(27, 27))); setIconSize(QSize(32, 32)); addWidget(searchIconLabel); addWidget(&m_searchBarLineEdit); addWidget(&m_bookmarkButton); addWidget(&m_multiZimButton); connect(this, &SearchBar::currentTitleChanged, &m_searchBarLineEdit, &SearchBarLineEdit::on_currentTitleChanged); connect(this, &SearchBar::currentTitleChanged, &m_bookmarkButton, &BookmarkButton::update_display); connect(KiwixApp::instance()->getContentManager(), &ContentManager::booksChanged, &m_multiZimButton, &MultiZimButton::updateDisplay); connect(this, &SearchBar::currentTitleChanged, &m_multiZimButton, &MultiZimButton::updateDisplay); } kiwix-desktop-2.4.1/src/searchbar.h000066400000000000000000000046071473106011000172120ustar00rootroot00000000000000#ifndef SEARCHBAR_H #define SEARCHBAR_H #include #include #include #include #include #include #include #include #include #include "suggestionlistmodel.h" #include "multizimbutton.h" class QTreeView; class BookmarkButton : public QToolButton { Q_OBJECT public: BookmarkButton(QWidget *parent = nullptr); public slots: void update_display(); void on_buttonClicked(); }; class SearchBarLineEdit : public QLineEdit { Q_OBJECT typedef void (SearchBarLineEdit::*NewSuggestionHandlerFuncPtr)(int start); public: SearchBarLineEdit(QWidget *parent = nullptr); void hideSuggestions(); bool eventFilter(QObject *watched, QEvent *event) override; public slots: void on_currentTitleChanged(const QString &title); void clearSuggestions(); protected: virtual void focusInEvent(QFocusEvent *); virtual void focusOutEvent(QFocusEvent *); private: SuggestionListModel m_suggestionModel; QTreeView *m_suggestionView; QCompleter m_completer; QString m_title; QString m_searchbarInput; QString m_suggestionsAreValidFor; bool m_returnPressed = false; QTimer* mp_typingTimer; int m_token; bool m_moreSuggestionsAreAvailable = false; /* We only fetch more suggestions when the user is at the end and tries to scroll again. This variable is set whenever the user scrolled to the end, indicating the next scroll should trigger a fetch more action. */ bool m_aboutToScrollPastEnd = false; private slots: void updateCompletion(); void fetchMoreSuggestions(); void onScroll(int value); void openCompletion(const QModelIndex& index); void onInitialSuggestions(int); void onAdditionalSuggestions(int start); void fetchSuggestions(NewSuggestionHandlerFuncPtr callback); QModelIndex getDefaulSuggestionIndex() const; QRect getCompleterRect() const; }; class SearchBar : public QToolBar { Q_OBJECT public: SearchBar(QWidget *parent = nullptr); SearchBarLineEdit& getLineEdit() { return m_searchBarLineEdit; }; MultiZimButton& getMultiZimButton() { return m_multiZimButton; }; signals: void currentTitleChanged(const QString &title); private: SearchBarLineEdit m_searchBarLineEdit; BookmarkButton m_bookmarkButton; MultiZimButton m_multiZimButton; }; #endif // SEARCHBAR_H kiwix-desktop-2.4.1/src/settingsmanager.cpp000066400000000000000000000154121473106011000210020ustar00rootroot00000000000000#include "settingsmanager.h" #include "kiwixapp.h" #include #include #include #include #include #include QString getDataDirectory() { if (isPortableMode()) { auto currentDataDir = QString::fromStdString(kiwix::removeLastPathElement(kiwix::getExecutablePath())); return currentDataDir + QDir::separator() + "data"; } QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (!dataDir.isEmpty() && QDir().mkpath(dataDir)) return dataDir; return QString::fromStdString(kiwix::getCurrentDirectory()); } bool isPortableMode() { auto currentDataDir = QString::fromStdString(kiwix::removeLastPathElement(kiwix::getExecutablePath())); auto portableFile = QFileInfo(currentDataDir, ".portable"); return portableFile.exists(); } namespace { QString getSettingsConfPath() { QString confDirectory = isPortableMode() ? getDataDirectory() : QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); return confDirectory + QDir::separator() + "Kiwix-desktop.conf"; } } SettingsManager::SettingsManager(QObject *parent) : QObject(parent), m_settings(getSettingsConfPath(), QSettings::IniFormat), m_view(nullptr) { initSettings(); } SettingsView* SettingsManager::getView() { if (m_view == nullptr) { auto view = new SettingsView(); view->init(m_zoomFactor * 100, m_downloadDir, m_monitorDir, m_moveToTrash, m_reopenTab); connect(view, &QObject::destroyed, this, [=]() { m_view = nullptr; }); m_view = view; } return m_view; } void SettingsManager::setSettings(const QString &key, const QVariant &value) { m_settings.setValue(key, value); } void SettingsManager::deleteSettings(const QString &key) { m_settings.remove(key); } bool SettingsManager::settingsExists(const QString &key) { return m_settings.contains(key); } QVariant SettingsManager::getSettings(const QString &key) { return m_settings.value(key); } qreal SettingsManager::getZoomFactorByZimId(const QString &id) { auto zoomFactor = m_zoomFactor; QString key = id + "/zoomFactor"; if (settingsExists(key)) { zoomFactor = getSettings(key).toDouble(); } return zoomFactor; } void SettingsManager::setKiwixServerPort(int port) { m_kiwixServerPort = port; m_settings.setValue("localKiwixServer/port", port); emit(portChanged(port)); } void SettingsManager::setKiwixServerIpAddress(QString ipAddress) { m_kiwixServerIpAddress = ipAddress; m_settings.setValue("localKiwixServer/ipAddress", ipAddress); } void SettingsManager::setZoomFactor(qreal zoomFactor) { m_zoomFactor = zoomFactor; m_settings.setValue("view/zoomFactor", zoomFactor); emit(zoomChanged(zoomFactor)); } void SettingsManager::setDownloadDir(QString downloadDir) { downloadDir = QDir::toNativeSeparators(downloadDir); m_downloadDir = downloadDir; m_settings.setValue("download/dir", downloadDir); emit(downloadDirChanged(downloadDir)); } void SettingsManager::setMonitorDir(QString monitorDir) { monitorDir = QDir::toNativeSeparators(monitorDir); m_monitorDir = monitorDir; m_settings.setValue("monitor/dir", monitorDir); emit(monitorDirChanged(monitorDir)); } void SettingsManager::setMoveToTrash(bool moveToTrash) { m_moveToTrash = moveToTrash; setSettings("moveToTrash", m_moveToTrash); emit(moveToTrashChanged(m_moveToTrash)); } void SettingsManager::setReopenTab(bool reopenTab) { m_reopenTab = reopenTab; setSettings("reopenTab", m_reopenTab); emit(reopenTabChanged(reopenTab)); } QList SettingsManager::flattenPair(FilterList pairList) { QList res; for (auto &pair : pairList) { res.push_back(pair.first+"|"+pair.second); } return res; } SettingsManager::FilterList SettingsManager::deducePair(QList variantList) { FilterList pairList; for (auto &variant : variantList) { QString str = variant.toString(); auto pairs = str.split('|'); pairList.push_back({pairs[0], pairs[1]}); } return pairList; } void SettingsManager::setLanguage(FilterList langList) { m_langList = flattenPair(langList); setSettings("language", m_langList); emit(languageChanged(m_langList)); } void SettingsManager::setCategory(QStringList categoryList) { m_categoryList = categoryList; setSettings("category", m_categoryList); emit(categoryChanged(m_categoryList)); } void SettingsManager::setContentType(FilterList contentTypeList) { m_contentTypeList = flattenPair(contentTypeList); setSettings("contentType", m_contentTypeList); emit(contentTypeChanged(m_contentTypeList)); } void SettingsManager::initSettings() { if(isPortableMode()) { m_downloadDir = m_monitorDir = getDataDirectory(); } else { m_downloadDir = m_settings.value("download/dir", getDataDirectory()).toString(); m_monitorDir = m_settings.value("monitor/dir", QString("")).toString(); } m_kiwixServerPort = m_settings.value("localKiwixServer/port", 8080).toInt(); m_zoomFactor = m_settings.value("view/zoomFactor", 1).toDouble(); m_kiwixServerIpAddress = m_settings.value("localKiwixServer/ipAddress", QString("0.0.0.0")).toString(); m_moveToTrash = m_settings.value("moveToTrash", true).toBool(); m_reopenTab = m_settings.value("reopenTab", false).toBool(); QString defaultLang = QLocale::languageToString(QLocale().language()) + '|' + QLocale().name().split("_").at(0); /* * Qt5 & Qt6 have slightly different behaviors with regards to initializing QVariant. * The below approach is specifically chosen to work with both versions. * m_langList initialized with defaultLang should be of the form: * * (QVariant(QString, "English|en")) * * and not * * QList(QVariant(QChar, 'E'), QVariant(QChar, 'n'), QVariant(QChar, 'g'), ... */ QList defaultLangList; // Qt5 QList doesn't support supplying a constructor list defaultLangList.append(defaultLang); QVariant defaultLangVariant(defaultLangList); m_langList = m_settings.value("language", defaultLangVariant).toList(); m_categoryList = m_settings.value("category", {}).toStringList(); /* Older versions used to save both the category identifier/code and its * name as shown to the user (separated by the | symbol). Now we store only * the category identifier from which the name is generated after loading. * In order to avoid user confusion we drop entries stored in the old format */ setCategory(m_categoryList.filter(QRegularExpression(R"(^[^|]*$)"))); m_contentTypeList = m_settings.value("contentType", {}).toList(); } kiwix-desktop-2.4.1/src/settingsmanager.h000066400000000000000000000056601473106011000204530ustar00rootroot00000000000000#ifndef SETTINGSMANAGER_H #define SETTINGSMANAGER_H #include #include #include "settingsview.h" class SettingsManager : public QObject { Q_OBJECT Q_PROPERTY(int kiwixServerPort READ getKiwixServerPort NOTIFY portChanged) Q_PROPERTY(qreal zoomFactor MEMBER m_zoomFactor WRITE setZoomFactor NOTIFY zoomChanged) Q_PROPERTY(QString downloadDir MEMBER m_downloadDir WRITE setDownloadDir NOTIFY downloadDirChanged) public: typedef QList> FilterList; explicit SettingsManager(QObject *parent = nullptr); virtual ~SettingsManager() {}; SettingsView* getView(); void setSettings(const QString &key, const QVariant &value); void deleteSettings(const QString &key); bool settingsExists(const QString &key); QVariant getSettings(const QString &key); qreal getZoomFactorByZimId(const QString &id); int getKiwixServerPort() const { return m_kiwixServerPort; } QString getKiwixServerIpAddress() const { return m_kiwixServerIpAddress; } qreal getZoomFactor() const { return m_zoomFactor; } QString getDownloadDir() const { return m_downloadDir; } QString getMonitorDir() const { return m_monitorDir; } bool getMoveToTrash() const { return m_moveToTrash; } bool getReopenTab() const { return m_reopenTab; } FilterList getLanguageList() { return deducePair(m_langList); } QStringList getCategoryList() { return m_categoryList; } FilterList getContentType() { return deducePair(m_contentTypeList); } public slots: void setKiwixServerPort(int port); void setKiwixServerIpAddress(QString ipAddress); void setZoomFactor(qreal zoomFactor); void setDownloadDir(QString downloadDir); void setMonitorDir(QString monitorDir); void setMoveToTrash(bool moveToTrash); void setReopenTab(bool reopenTab); void setLanguage(FilterList langList); void setCategory(QStringList categoryList); void setContentType(FilterList contentTypeList); private: void initSettings(); QList flattenPair(FilterList pairList); FilterList deducePair(QList); signals: void portChanged(int port); void zoomChanged(qreal zoomFactor); void downloadDirChanged(QString downloadDir); void monitorDirChanged(QString monitorDir); void moveToTrashChanged(bool moveToTrash); void reopenTabChanged(bool reopenTab); void languageChanged(QList langList); void categoryChanged(QStringList categoryList); void contentTypeChanged(QList contentTypeList); private: QSettings m_settings; SettingsView *m_view; int m_kiwixServerPort; QString m_kiwixServerIpAddress; qreal m_zoomFactor; QString m_downloadDir; QString m_monitorDir; bool m_moveToTrash; bool m_reopenTab; QList m_langList; QStringList m_categoryList; QList m_contentTypeList; }; QString getDataDirectory(); bool isPortableMode(); #endif // SETTINGSMANAGER_H kiwix-desktop-2.4.1/src/settingsview.cpp000066400000000000000000000211501473106011000203360ustar00rootroot00000000000000#include "settingsview.h" #include "ui_settings.h" #include "kiwixapp.h" #include #include #include #include #include #include namespace { QString formatSettingsDir(const QString& input) { const int maxLength = 40; if (input.length() > maxLength) { QString suffix = input.right(maxLength); int directoryIndex = suffix.indexOf('/'); return "..." + suffix.mid(directoryIndex != -1 ? directoryIndex : 0); } return input; } void disableInPortableMode(QWidget* w) { w->setEnabled(false); QString disabledStyle = "color: gray;"; w->setStyleSheet(disabledStyle); w->setToolTip(gt("portable-disabled-tooltip")); } } SettingsView::SettingsView(QWidget *parent) : QScrollArea(parent) , ui(new Ui::Settings) { SettingsManager *settingsMgr = KiwixApp::instance()->getSettingsManager(); ui->setupUi(this); ui->widget->setStyleSheet(KiwixApp::instance()->parseStyleFromFile(":/css/_settingsManager.css")); connect(ui->zoomPercentSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &SettingsView::setZoom); connect(ui->moveToTrashToggle, &QCheckBox::clicked, this, &SettingsView::setMoveToTrash); connect(ui->reopenTabToggle, &QCheckBox::clicked, this, &SettingsView::setReopenTab); connect(ui->browseButton, &QPushButton::clicked, this, &SettingsView::browseDownloadDir); connect(ui->downloadDirPathCopy, &QPushButton::clicked, [this, settingsMgr]() { copySettingsPathToClipboard(settingsMgr->getDownloadDir(), ui->downloadDirPathCopy); }); connect(ui->monitorDirPathCopy, &QPushButton::clicked, [this, settingsMgr]() { copySettingsPathToClipboard(settingsMgr->getMonitorDir(), ui->monitorDirPathCopy); }); connect(ui->resetButton, &QPushButton::clicked, this, &SettingsView::resetDownloadDir); connect(ui->monitorBrowse, &QPushButton::clicked, this, &SettingsView::browseMonitorDir); connect(ui->monitorClear, &QPushButton::clicked, this, &SettingsView::clearMonitorDir); connect(settingsMgr, &SettingsManager::downloadDirChanged, this, &SettingsView::onDownloadDirChanged); connect(settingsMgr, &SettingsManager::monitorDirChanged, this, &SettingsView::onMonitorDirChanged); connect(settingsMgr, &SettingsManager::zoomChanged, this, &SettingsView::onZoomChanged); connect(settingsMgr, &SettingsManager::moveToTrashChanged, this, &SettingsView::onMoveToTrashChanged); connect(settingsMgr, &SettingsManager::reopenTabChanged, this, &SettingsView::onReopenTabChanged); ui->settingsLabel->setText(gt("settings")); ui->zoomPercentLabel->setText(gt("zoom-level-setting")); ui->downloadDirLabel->setText(gt("download-directory-setting")); ui->monitorDirLabel->setText(gt("monitor-directory-setting")); ui->resetButton->setText(gt("reset")); ui->browseButton->setText(gt("browse")); ui->monitorClear->setText(gt("clear")); ui->monitorBrowse->setText(gt("browse")); QIcon copyIcon(":/icons/copy.svg"); ui->downloadDirPathCopy->setIcon(copyIcon); ui->downloadDirPathCopy->setIconSize(QSize(24, 24)); ui->monitorDirPathCopy->setIcon(copyIcon); ui->monitorDirPathCopy->setIconSize(QSize(24, 24)); ui->monitorHelp->setText("?"); ui->monitorHelp->setToolTip(gt("monitor-directory-tooltip")); ui->moveToTrashLabel->setText(gt("move-files-to-trash")); ui->reopenTabLabel->setText(gt("open-previous-tabs-at-startup")); if(isPortableMode()) { disableInPortableMode(ui->browseButton); disableInPortableMode(ui->resetButton); disableInPortableMode(ui->monitorBrowse); disableInPortableMode(ui->monitorClear); } #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) ui->line_5->hide(); ui->moveToTrashLabel->hide(); ui->moveToTrashToggle->hide(); #endif } void SettingsView::init(int zoomPercent, const QString &downloadDir, const QString &monitorDir, const bool moveToTrash, bool reopentab) { ui->zoomPercentSpinBox->setValue(zoomPercent); SettingsView::onDownloadDirChanged(downloadDir); SettingsView::onMonitorDirChanged(monitorDir); ui->moveToTrashToggle->setChecked(moveToTrash); ui->reopenTabToggle->setChecked(reopentab); } bool SettingsView::confirmDialog( QString messageText, QString messageTitle) { QMessageBox msgBox( QMessageBox::Question, //Icon messageTitle, //Title messageText, //Text QMessageBox::Ok | QMessageBox::Cancel //Buttons ); msgBox.setDefaultButton(QMessageBox::Ok); int ret = msgBox.exec(); return (ret == QMessageBox::Ok); } bool SettingsView::confirmDialogDownloadDir(const QString &dir) { auto messageText = gt("download-dir-dialog-msg"); messageText = messageText.replace("{{DIRECTORY}}", dir); return confirmDialog(messageText, gt("download-dir-dialog-title")); } bool SettingsView::confirmDialogMonitorDir(const QString &dir) { auto messageText = gt("monitor-dir-dialog-msg"); messageText = messageText.replace("{{DIRECTORY}}", dir); auto messageTitle = gt("monitor-dir-dialog-title"); return confirmDialog(messageText, messageTitle); } void SettingsView::resetDownloadDir() { auto dir = getDataDirectory(); const auto &downloadDir = KiwixApp::instance()->getSettingsManager()->getDownloadDir(); if (dir == downloadDir) { return; } if (confirmDialogDownloadDir(dir)) { KiwixApp::instance()->getSettingsManager()->setDownloadDir(dir); } } void SettingsView::browseDownloadDir() { const auto &downloadDir = KiwixApp::instance()->getSettingsManager()->getDownloadDir(); QString dir = QFileDialog::getExistingDirectory(KiwixApp::instance()->getMainWindow(), gt("browse-directory"), downloadDir, QFileDialog::ShowDirsOnly); if (dir == downloadDir || dir.isEmpty()) { return; } if (confirmDialogDownloadDir(dir)) { KiwixApp::instance()->getSettingsManager()->setDownloadDir(dir); } } void SettingsView::browseMonitorDir() { const auto &monitorDir = KiwixApp::instance()->getSettingsManager()->getMonitorDir(); QString previousDir; if (monitorDir == "") { previousDir = KiwixApp::instance()->getSettingsManager()->getDownloadDir(); } else { previousDir = monitorDir; } QString dir = QFileDialog::getExistingDirectory(KiwixApp::instance()->getMainWindow(), gt("browse-directory"), previousDir, QFileDialog::ShowDirsOnly); if (dir == monitorDir || dir.isEmpty()) { return; } if (confirmDialogMonitorDir(dir)) { KiwixApp::instance()->setMonitorDir(dir); } } void SettingsView::clearMonitorDir() { if (confirmDialog(gt("monitor-clear-dir-dialog-msg"), gt("monitor-clear-dir-dialog-title"))) { KiwixApp::instance()->setMonitorDir(""); } } void SettingsView::setZoom(int zoomPercent) { qreal zoomFactor = (qreal) zoomPercent/100; KiwixApp::instance()->getSettingsManager()->setZoomFactor(zoomFactor); } void SettingsView::setMoveToTrash(bool moveToTrash) { KiwixApp::instance()->getSettingsManager()->setMoveToTrash(moveToTrash); } void SettingsView::setReopenTab(bool reopen) { KiwixApp::instance()->getSettingsManager()->setReopenTab(reopen); } void SettingsView::onDownloadDirChanged(const QString &dir) { ui->downloadDirPath->setText(formatSettingsDir(dir)); ui->downloadDirPath->setToolTip(dir); } void SettingsView::copySettingsPathToClipboard(QString pathToCopy, QPushButton* button) { QApplication::clipboard()->setText(pathToCopy); QPoint globalPos = button->mapToGlobal(QPoint(0, -button->height())); QToolTip::showText(globalPos, gt("path-was-copied"), button); } void SettingsView::onMonitorDirChanged(const QString &dir) { ui->monitorClear->setVisible(!dir.isEmpty()); ui->monitorDirPathCopy->setVisible(!dir.isEmpty()); ui->monitorDirPath->setText(formatSettingsDir(dir)); ui->monitorDirPath->setToolTip(dir); } void SettingsView::onZoomChanged(qreal zoomFactor) { qreal zoomPercent = zoomFactor * 100; ui->zoomPercentSpinBox->setValue(zoomPercent); } void SettingsView::onMoveToTrashChanged(bool moveToTrash) { ui->moveToTrashToggle->setChecked(moveToTrash); } void SettingsView::onReopenTabChanged(bool reopen) { ui->reopenTabToggle->setChecked(reopen); } kiwix-desktop-2.4.1/src/settingsview.h000066400000000000000000000023141473106011000200040ustar00rootroot00000000000000#ifndef SETTINGSVIEW_H #define SETTINGSVIEW_H #include #include #include namespace Ui { class Settings; } class SettingsView : public QScrollArea { Q_OBJECT public: SettingsView(QWidget *parent = nullptr); ~SettingsView(){}; void init(int zoomPercent, const QString &downloadDir, const QString &monitorDir, const bool moveToTrash, bool reopentab); public Q_SLOTS: void resetDownloadDir(); void browseDownloadDir(); void browseMonitorDir(); void clearMonitorDir(); void setZoom(int zoomPercent); void setMoveToTrash(bool moveToTrash); void setReopenTab(bool reopen); void onDownloadDirChanged(const QString &dir); void copySettingsPathToClipboard(QString pathToCopy, QPushButton* button); void onMonitorDirChanged(const QString &dir); void onZoomChanged(qreal zoomFactor); void onMoveToTrashChanged(bool moveToTrash); void onReopenTabChanged(bool reopen); private: bool confirmDialogDownloadDir(const QString& dir); bool confirmDialog(QString messageText, QString messageTitle); bool confirmDialogMonitorDir(const QString& dir); Ui::Settings *ui; }; #endif // SETTINGSVIEW_H kiwix-desktop-2.4.1/src/suggestionlistdelegate.cpp000066400000000000000000000073131473106011000223660ustar00rootroot00000000000000#include "suggestionlistdelegate.h" #include "kiwixapp.h" #include "css_constants.h" #include namespace HeaderSectionCSS = CSS::PopupCSS::QHeaderView::section; void SuggestionListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { /* Paint without text and icon */ QStyleOptionViewItem opt(option); QStyledItemDelegate::paint(painter, opt, QModelIndex()); paintIcon(painter, opt, index); paintText(painter, opt, index); } void SuggestionListDelegate::paintIcon(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const { QRect pixmapRect = opt.rect; const int lineHeight = HeaderSectionCSS::lineHeight; const int paddingLeft = HeaderSectionCSS::paddingLeft; const QSize mapSize = QSize(lineHeight, lineHeight); auto pixmap = index.data(Qt::DecorationRole).value().pixmap(mapSize); /* Align icon to Header text */ if (KiwixApp::isRightToLeft()) { const int rightEnd = pixmapRect.width() - mapSize.width(); pixmapRect.setX(pixmapRect.x() + rightEnd - paddingLeft); } else pixmapRect.setX(pixmapRect.x() + paddingLeft); /* Align middle */ pixmapRect.setY(pixmapRect.y() + (pixmapRect.height() - mapSize.height()) / 2); pixmapRect.setSize(mapSize); p->drawPixmap(pixmapRect, pixmap); } /** * @brief Get the elided text using font that can fit inside the length when * appended with the custom elide text "(...)". * * @param font * @param textRect * @param text * @return QString the elided text without any marker. */ QString getElidedText(const QFont& font, int length, const QString& text) { const QFontMetrics metrics(font); const int elideMarkerLength = metrics.tightBoundingRect("(...)").width(); const int textLength = length - elideMarkerLength; QString elidedText = metrics.elidedText(text, Qt::ElideRight, textLength); if (elidedText != text) return elidedText.isEmpty() ? "" : elidedText.chopped(1); return text; } void SuggestionListDelegate::paintText(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const { auto& searchBar = KiwixApp::instance()->getSearchBar(); const auto& lineEditGeo = searchBar.getLineEdit().geometry(); /* Remove border from left() since left is is with respect to border. Detail reason on how this calculation comes about can be seen in SearchBarLineEdit::getCompleterRect(); */ const int left = lineEditGeo.left() - CSS::SearchBar::border; QRect textRect = opt.rect; if (KiwixApp::isRightToLeft()) { const auto& searchGeo = searchBar.geometry(); const int right = searchGeo.width() - left - lineEditGeo.width(); textRect.setWidth(textRect.width() - right); } else textRect.setX(textRect.x() + left); const int flag = {Qt::AlignVCenter | Qt::AlignLeading}; const QString text = index.data(Qt::DisplayRole).toString(); /* Custom text elide. */ QString elidedText = getElidedText(opt.font, textRect.width(), text); if (elidedText != text) { /* drawText's Align direction determines text direction */ const bool textDirFlipped = KiwixApp::isRightToLeft() != text.isRightToLeft(); elidedText = textDirFlipped ? "(...)" + elidedText.trimmed() : elidedText.trimmed() + "(...)"; p->drawText(textRect, flag, elidedText); } else p->drawText(textRect, flag, text); } kiwix-desktop-2.4.1/src/suggestionlistdelegate.h000066400000000000000000000011441473106011000220270ustar00rootroot00000000000000#ifndef SUGGESTIONLISTDELEGATE_H #define SUGGESTIONLISTDELEGATE_H #include class SuggestionListDelegate : public QStyledItemDelegate { public: SuggestionListDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: void paintIcon(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const; void paintText(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const; }; #endif // SUGGESTIONLISTDELEGATE_H kiwix-desktop-2.4.1/src/suggestionlistmodel.cpp000066400000000000000000000052511473106011000217130ustar00rootroot00000000000000#include "suggestionlistmodel.h" #include "kiwixapp.h" #include "css_constants.h" #include namespace HeaderSectionCSS = CSS::PopupCSS::QHeaderView::section; QString getZimIdFromUrl(QUrl url); SuggestionListModel::SuggestionListModel(QObject *parent) : QAbstractListModel(parent) { } SuggestionListModel::~SuggestionListModel() { } int SuggestionListModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_suggestions.size(); } QVariant SuggestionListModel::data(const QModelIndex &index, int role) const { const int row = index.row(); if (row < 0 || row >= rowCount()) return QVariant(); switch (role) { case Qt::DisplayRole: case Qt::EditRole: return m_suggestions.at(row).text; case Qt::UserRole: return m_suggestions.at(row).url; case Qt::DecorationRole: { const auto library = KiwixApp::instance()->getLibrary(); const auto zimId = getZimIdFromUrl(m_suggestions.at(row).url); return library->getBookIcon(zimId); } case Qt::SizeHintRole: { /* Padding in css can't change height, we have to achieve padding by increasing height. */ const int padding = HeaderSectionCSS::paddingVertical; const int lineHeight = HeaderSectionCSS::lineHeight; return QSize(0, lineHeight + 2 * padding); } } return QVariant(); } QVariant SuggestionListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section != 0 || orientation != Qt::Orientation::Horizontal) return QVariant(); switch (role) { case Qt::DisplayRole: return gt("kiwix-search"); } return QVariant(); } void SuggestionListModel::resetSuggestions() { beginResetModel(); m_suggestions.clear(); endResetModel(); } void SuggestionListModel::append(const QList &suggestionList) { beginResetModel(); if (hasFullTextSearchSuggestion()) m_suggestions.pop_back(); for (const auto& suggestion : suggestionList) m_suggestions.append(suggestion); endResetModel(); } int SuggestionListModel::countOfRegularSuggestions() const { return hasFullTextSearchSuggestion() ? rowCount() - 1 : rowCount(); } bool SuggestionListModel::hasFullTextSearchSuggestion() const { return rowCount() > 0 && m_suggestions.last().isFullTextSearchSuggestion(); } bool SuggestionData::isFullTextSearchSuggestion() const { return url.host().endsWith(".search"); } kiwix-desktop-2.4.1/src/suggestionlistmodel.h000066400000000000000000000016351473106011000213620ustar00rootroot00000000000000#ifndef SUGGESTIONLISTMODEL_H #define SUGGESTIONLISTMODEL_H #include #include struct SuggestionData { QString text; QUrl url; bool isFullTextSearchSuggestion() const; }; class SuggestionListModel : public QAbstractListModel { Q_OBJECT public: explicit SuggestionListModel(QObject *parent = nullptr); ~SuggestionListModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; void resetSuggestions(); void append(const QList& suggestionList); int countOfRegularSuggestions() const; bool hasFullTextSearchSuggestion() const; private: QList m_suggestions; }; #endif // SUGGESTIONLISTMODEL_H kiwix-desktop-2.4.1/src/suggestionlistworker.cpp000066400000000000000000000044561473106011000221320ustar00rootroot00000000000000#include "suggestionlistworker.h" #include "kiwixapp.h" #include SuggestionListWorker::SuggestionListWorker(const QString& text, int token, int start, QObject *parent) : QThread(parent), m_text(text), m_token(token), m_start(start) { } void SuggestionListWorker::run() { QList suggestionList; const auto app = KiwixApp::instance(); const auto selectedIdList = app->getSearchBar().getMultiZimButton().getZimIds(); /* TODO: re-implement this after introducing the actual Multi-Zim. */ const auto currentZimId = selectedIdList[0]; try { const auto archive = app->getLibrary()->getArchive(currentZimId); QUrl url; url.setScheme("zim"); url.setHost(currentZimId + ".zim"); auto prefix = m_text.toStdString(); auto suggestionSearcher = zim::SuggestionSearcher(*archive); auto suggestionSearch = suggestionSearcher.suggest(prefix); const auto suggestions = suggestionSearch.getResults(m_start, getFetchSize()); for (auto current : suggestions) { QString path = QString("/") + QString::fromStdString(current.getPath()); url.setPath(path); const auto text = QString::fromStdString(current.getTitle()); suggestionList.append({text, url}); } // Propose fulltext search url.setPath(""); if (archive->hasFulltextIndex()) { // The host is used to determine the currentZimId // The content query item is used to know in which zim search (as for kiwix-serve) url.setHost(currentZimId + ".search"); QUrlQuery query; query.addQueryItem("content", currentZimId); query.addQueryItem("pattern", m_text); url.setQuery(query); const auto text = m_text + " (" + gt("fulltext-search") + ")"; suggestionList.append({text, url}); } } catch (std::out_of_range& e) { // Impossible to find the requested archive (bug ?) // We could propose a suggestion to do multi-zim search with: // url.setHost("library.search"); // but we don't have a correct UI to select on which zim search, how to display results, ... // So do nothing for now } emit(searchFinished(suggestionList, m_token)); } kiwix-desktop-2.4.1/src/suggestionlistworker.h000066400000000000000000000010431473106011000215640ustar00rootroot00000000000000#ifndef SUGGESTIONLISTWORKER_H #define SUGGESTIONLISTWORKER_H #include #include "suggestionlistmodel.h" class SuggestionListWorker : public QThread { Q_OBJECT public: static int getFetchSize() { return 15; }; SuggestionListWorker(const QString& text, int token, int start, QObject *parent = nullptr); void run() override; signals: void searchFinished(const QList& suggestionList, int token); private: QString m_text; int m_token = 0; int m_start; }; #endif // SUGGESTIONLISTWORKER_H kiwix-desktop-2.4.1/src/tabbar.cpp000066400000000000000000000411101473106011000170340ustar00rootroot00000000000000class QMenu; #include "tabbar.h" #include "kiwixapp.h" #include "css_constants.h" #include #include #include #include #include #include #include #define QUITIFNULL(VIEW) if (nullptr==(VIEW)) { return; } #define CURRENTIFNULL(VIEW) if(nullptr==VIEW) { VIEW = currentZimView();} namespace { QAction* getAction(KiwixApp::Actions action) { return KiwixApp::instance()->getAction(action); } } // unnamed namespace TabBar::TabBar(QWidget *parent) : QTabBar(parent) { QTabBar::setDrawBase(false); setTabsClosable(true); setElideMode(Qt::ElideNone); setDocumentMode(true); setFocusPolicy(Qt::NoFocus); setMovable(true); setIconSize(QSize(30, 30)); connect(this, &QTabBar::currentChanged, this, &TabBar::onCurrentChanged, Qt::QueuedConnection); connect(getAction(KiwixApp::NextTabAction), &QAction::triggered, this, &TabBar::moveToNextTab); connect(getAction(KiwixApp::PreviousTabAction), &QAction::triggered, this, &TabBar::moveToPreviousTab); connect(getAction(KiwixApp::CloseCurrentTabAction), &QAction::triggered, this, [=]() { this->closeTab(currentIndex()); }); connect(getAction(KiwixApp::OpenHomePageAction), &QAction::triggered, this, &TabBar::openHomePage); connect(getAction(KiwixApp::SettingAction), &QAction::triggered, this, &TabBar::openOrSwitchToSettingsTab); for (int i = 0 ; i <= 9 ; i++) { QAction *a = new QAction(this); a->setShortcut(QKeySequence(Qt::ALT | (Qt::Key_0 + i))); addAction(a); connect(a, &QAction::triggered, this, [=](){ const int tabIndex = i == 0 ? 9 : i - 1; if (tabIndex < realTabCount()) { setCurrentIndex(tabIndex); } }); } // the slot relies the connection will be direct to reverting back the tab connect(this, SIGNAL(tabMoved(int,int)), this, SLOT(onTabMoved(int,int)), Qt::DirectConnection); } void TabBar::openHomePage() { auto current = this->currentWebView(); QUITIFNULL(current); current->setUrl("zim://" + current->zimId() + ".zim/"); } void TabBar::openOrSwitchToSettingsTab() { SettingsView* view = KiwixApp::instance()->getSettingsManager()->getView(); for (int i = 0 ; i < mp_stackedWidget->count(); i++) { if (mp_stackedWidget->widget(i) == view) { setCurrentIndex(i); return; } } int index = currentIndex() + 1; mp_stackedWidget->insertWidget(index, view); emit tabDisplayed(TabType::SettingsTab); insertTab(index,QIcon(":/icons/settings.svg"), gt("settings")); setCloseTabButton(index); setCurrentIndex(index); KiwixApp::instance()->saveListOfOpenTabs(); } void TabBar::setStackedWidget(QStackedWidget *widget) { mp_stackedWidget = widget; connect(this, &QTabBar::currentChanged, widget, &QStackedWidget::setCurrentIndex); } void TabBar::setContentManagerView(ContentManagerView* view) { qInfo() << "add widget"; mp_stackedWidget->addWidget(view); mp_stackedWidget->show(); int idx = addTab(QIcon(":/icons/kiwix-logo.svg"), ""); setTabButton(idx, RightSide, nullptr); } void TabBar::setNewTabButton(QAction* newTabAction) { QToolButton *tb = new QToolButton(); tb->setObjectName("newTabButton"); tb->setDefaultAction(newTabAction); tb->setIcon(QIcon(":/icons/new-tab-icon.svg")); int idx = addTab(""); setTabEnabled(idx, false); setTabButton(idx, QTabBar::LeftSide, tb); tabButton(idx, QTabBar::RightSide)->deleteLater(); setTabButton(idx, QTabBar::RightSide, Q_NULLPTR); } // Returns the count of real tabs with content (excluding the last pseudo-tab // that acts as a button for creating new empty tabs; BTW what is the use for // such empty tabs?) int TabBar::realTabCount() const { return count() < 1 ? 0 : count() - 1; } void TabBar::moveToNextTab() { const int index = currentIndex(); setCurrentIndex(index == realTabCount() - 1 ? 0 : index + 1); } void TabBar::moveToPreviousTab() { const int index = currentIndex(); setCurrentIndex(index <= 0 ? realTabCount() - 1 : index - 1); } void TabBar::scrollNextTab() { const int index = currentIndex(); setCurrentIndex(index == realTabCount() - 1 ? index : index + 1); } void TabBar::scrollPreviousTab() { const int index = currentIndex(); setCurrentIndex(index <= 0 ? index : index - 1); } void TabBar::setCloseTabButton(int index) { Q_ASSERT(index > 0 && index < realTabCount()); QToolButton *tb = new QToolButton(this); tb->setObjectName("closeTabButton"); QAction *a = new QAction(QIcon(":/icons/close.svg"), gt("close-tab"), tb); a->setToolTip(getAction(KiwixApp::CloseCurrentTabAction)->toolTip()); tb->setDefaultAction(a); setTabButton(index, QTabBar::RightSide, tb); connect(tb, &QToolButton::triggered, this, [=]() { for ( int i = 0; i < realTabCount(); ++i ) { if ( tb == tabButton(i, QTabBar::RightSide) ) { closeTab(i); return; } } }); } ZimView* TabBar::createNewTab(bool setCurrent, bool nextToCurrentTab) { auto tab = new ZimView(this, this); const int index = nextToCurrentTab ? currentIndex() + 1 : realTabCount(); mp_stackedWidget->insertWidget(index, tab); insertTab(index, ""); setCloseTabButton(index); if (setCurrent) { setCurrentIndex(index); } connect(tab, &ZimView::webActionEnabledChanged, this, &TabBar::onWebviewHistoryActionChanged); KiwixApp::instance()->saveListOfOpenTabs(); return tab; } void TabBar::openUrl(const QUrl& url, bool newTab) { WebView* webView = currentWebView(); if (newTab || !webView) { webView = createNewTab(true, true)->getWebView(); } QUITIFNULL(webView); webView->setUrl(url); } void TabBar::setTitleOf(const QString& title, ZimView* tab) { CURRENTIFNULL(tab); int idx = mp_stackedWidget->indexOf(tab); if (idx < 0) return; QString t = title; if (title.startsWith("zim://")) { auto url = QUrl(title); t = url.path(); } setTabToolTip(idx, t); /* we don't use setTabText() because Qt can't draw text with * fade-out gradient selectively (only for large texts). * So we just store tab's title, and will draw it later ourselves. */ setTabData(idx, QVariant::fromValue(t)); // need to initiate repaint // because setTabData() didn't do it as setTabText() before. repaint(); } void TabBar::setIconOf(const QIcon &icon, ZimView *tab) { CURRENTIFNULL(tab); setTabIcon(mp_stackedWidget->indexOf(tab), icon); } QString TabBar::currentZimId() { if (WebView *w = currentWebView()) return w->zimId(); return ""; } QString TabBar::currentArticleUrl() { if (WebView *w = currentWebView()) return w->url().path(); return ""; } QString TabBar::currentArticleTitle() { if (WebView *w = currentWebView()) return w->title(); return ""; } QSize TabBar::tabSizeHint(int index) const { QWidget *w = mp_stackedWidget->widget(index); if ((w && qobject_cast(w)) || index >= count() - 1) return QSize(40, 40); // the "Library" tab is only icon return QSize(205, 40); // "Settings" and content tabs have text } void TabBar::openFindInPageBar() { if (ZimView *zv = currentZimView()) zv->openFindInPageBar(); } void TabBar::triggerWebPageAction(QWebEnginePage::WebAction action, ZimView *widget) { CURRENTIFNULL(widget); QUITIFNULL(widget); widget->getWebView()->triggerPageAction(action); widget->getWebView()->setFocus(); } void TabBar::closeTabsByZimId(const QString &id) { // 0th tab is always (unless this comment becomes outdated by the time you // read it) the library tab, so iteration could start from 1, however we // shouldn't try to save CPU cycles at the cost of the code breaking // should this comment indeed become outdated ;) for (int i = 0 ; i < realTabCount() ; ++i ) { auto *zv = qobject_cast(mp_stackedWidget->widget(i)); if (zv && zv->getWebView()->zimId() == id) { closeTab(i); } } } QStringList TabBar::getTabUrls() const { QStringList idList; for (int index = 0; index <= mp_stackedWidget->count(); index++) { if (ZimView* zv = qobject_cast(mp_stackedWidget->widget(index))) idList.push_back(zv->getWebView()->url().url()); else if (qobject_cast(mp_stackedWidget->widget(index))) idList.push_back("SettingsTab"); } return idList; } QStringList TabBar::getTabZimIds() const { QStringList idList; for (int index = 0; index <= mp_stackedWidget->count(); index++) if (ZimView* zv = qobject_cast(mp_stackedWidget->widget(index))) idList.push_back(zv->getWebView()->zimId()); return idList; } void TabBar::closeTab(int index) { // The first and last tabs (i.e. the library tab and the + (new tab) button) // cannot be closed if (index <= 0 || index >= this->realTabCount()) return; if ( index == currentIndex() ) { setCurrentIndex(index + 1 == realTabCount() ? index - 1 : index + 1); } QWidget *view = mp_stackedWidget->widget(index); mp_stackedWidget->removeWidget(view); view->setParent(nullptr); removeTab(index); view->close(); view->deleteLater(); KiwixApp::instance()->saveListOfOpenTabs(); } void TabBar::onCurrentChanged(int index) { if (index == -1) return; // if somehow the last tab (+ button) became active, switch to the previous if (index >= realTabCount()) { setCurrentIndex(realTabCount() - 1); return; } QWidget *w = mp_stackedWidget->widget(index); if (qobject_cast(w)) { emit webActionEnabledChanged(QWebEnginePage::Back, false); emit webActionEnabledChanged(QWebEnginePage::Forward, false); emit tabDisplayed(TabType::SettingsTab); QTimer::singleShot(0, [=](){emit currentTitleChanged("");}); } else if (auto zv = qobject_cast(w)) { auto view = zv->getWebView(); emit webActionEnabledChanged(QWebEnginePage::Back, view->isWebActionEnabled(QWebEnginePage::Back)); emit webActionEnabledChanged(QWebEnginePage::Forward, view->isWebActionEnabled(QWebEnginePage::Forward)); emit tabDisplayed(TabType::ZimViewTab); QTimer::singleShot(0, [=](){emit currentTitleChanged(view->title());}); } else if (qobject_cast(w)) { emit webActionEnabledChanged(QWebEnginePage::Back, false); emit webActionEnabledChanged(QWebEnginePage::Forward, false); emit tabDisplayed(TabType::LibraryTab); QTimer::singleShot(0, [=](){emit currentTitleChanged("");}); } else { Q_ASSERT(false); // In the future, other types of tabs can be added. // For example, About dialog, or Kiwix Server control panel. } KiwixApp::instance()->saveCurrentTabIndex(); } void TabBar::fullScreenRequested(QWebEngineFullScreenRequest request) { if (request.toggleOn()) { if (m_fullScreenWindow) return; request.accept(); m_fullScreenWindow.reset(new FullScreenWindow(this->currentWebView())); } else { if (!m_fullScreenWindow) return; request.accept(); m_fullScreenWindow.reset(); } } void TabBar::on_webview_titleChanged(const QString& title) { ZimView* tab = qobject_cast(sender()->parent()); if (! tab) return; setTitleOf(title, tab); if (currentZimView() == tab) emit currentTitleChanged(title); } void TabBar::onWebviewHistoryActionChanged(QWebEnginePage::WebAction action, bool enabled) { ZimView *zv = qobject_cast(sender()); if (!zv || zv != this->currentZimView()) return; emit webActionEnabledChanged(action, enabled); } void TabBar::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::MiddleButton) { closeTab(this->tabAt(event->pos())); } else { QTabBar::mousePressEvent(event); } } void TabBar::paintEvent(QPaintEvent *e) { /* first, let Qt draw QTabBar normally. * QTabbar will leave tabs titles empty because we didn't set these values into QTabBar. */ QTabBar::paintEvent(e); // Then, for each tab, we draw titles, using fade-out effect when needed. QPainter p(this); for (int i = 0; i < count(); ++i) { QString tab_title = tabData(i).toString(); if (tab_title.isEmpty()) continue; /* See the implementation of QTabBar for better understanding this code: * /5.12.6/Src/qtbase/src/widgets/widgets/qtabbar.cpp * in particular, QTabBar::initStyleOption() */ QStyleOptionTab tabopt; initStyleOption(&tabopt, i); bool need_fade_out = false; bool textRightToLeft = tab_title.isRightToLeft(); bool appRightToLeft = QWidget::isRightToLeft(); const int padding = CSS::QTabBar::tab::padding; QRect tabTextRect = style()->subElementRect(QStyle::SE_TabBarTabText, &tabopt, this); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const int border = CSS::QTabBar::tab::border; // Add Padding to left, right. Padding is 4px. Add 5 to account for // Extra pixel from border. tabTextRect.setX(tabTextRect.x() + padding + border); tabTextRect.setWidth(tabTextRect.width() - padding - border); #else // Qt6 correctly adds left and right padding but now incorrectly adds // top or bottom padding. tabTextRect.setY(tabTextRect.y() - padding); #endif QRect fontTextRect = fontMetrics().boundingRect(tab_title); if (fontTextRect.width() > tabTextRect.width()) need_fade_out = true; if (need_fade_out) { // draw the most of tab text extent with the normal color, // and draw the rest with alpha channel gradient QColor c0 = tabopt.palette.brush(QPalette::ButtonText).color(); QColor c1(c0); c0.setAlpha(255); // color of font c1.setAlpha(0); // transparent const int mid_Y = tabTextRect.center().y(); QLinearGradient gr; if (textRightToLeft) { // arabic right-to-left text gr.setStart(tabTextRect.x(), mid_Y); gr.setFinalStop(tabTextRect.x() + 0.2 * tabTextRect.width(), mid_Y); gr.setColorAt(0.0, c1); gr.setColorAt(1.0, c0); } else { // normal left-to-right text direction gr.setStart(tabTextRect.x() + 0.8 * tabTextRect.width(), mid_Y); gr.setFinalStop(tabTextRect.right(), mid_Y); gr.setColorAt(0.0, c0); gr.setColorAt(1.0, c1); } tabopt.palette.setBrush(QPalette::ButtonText, QBrush(gr)); } int align = Qt::AlignVCenter; if (need_fade_out) { /* We align LTR text in LTR app to the left, while RTL text in RTL app to the right. Since Qt mirror alignment, we can simply do ALignLeft for both cases. When text and app direction doesn't match, we flip the text alignment. */ align |= (textRightToLeft == appRightToLeft) ? Qt::AlignLeft : Qt::AlignRight; } style()->drawItemText(&p, tabTextRect, align, tabopt.palette, true, tab_title, QPalette::ButtonText); } } void TabBar::tabRemoved(int index) { QTabBar::tabRemoved(index); emit tabRemovedSignal(index); } void TabBar::tabInserted(int index) { QTabBar::tabInserted(index); emit tabInsertedSignal(index); } void TabBar::resizeEvent(QResizeEvent *event) { QTabBar::resizeEvent(event); emit sizeChanged(); } void TabBar::onTabMoved(int from, int to) { // avoid infinitive recursion static bool reverting = false; if (reverting) return; // on attempt to move the last tab (+ button) just move it back // and the library should stick the first (zero) tab int last = mp_stackedWidget->count(); if ( (from == last || to == last) || (from == 0 || to == 0) ) { reverting = true; moveTab(to, from); reverting = false; return; } // swap widgets QWidget *w_from = mp_stackedWidget->widget(from); mp_stackedWidget->removeWidget(w_from); mp_stackedWidget->insertWidget(to, w_from); KiwixApp::instance()->saveListOfOpenTabs(); } kiwix-desktop-2.4.1/src/tabbar.h000066400000000000000000000055651473106011000165170ustar00rootroot00000000000000#ifndef TABWIDGET_H #define TABWIDGET_H #include #include #include #include "webview.h" #include "zimview.h" #include "contentmanagerview.h" #include "fullscreenwindow.h" #include #include class TabBar : public QTabBar { Q_OBJECT public: enum class TabType { LibraryTab, ZimViewTab, SettingsTab }; TabBar(QWidget* parent=nullptr); void setStackedWidget(QStackedWidget* widget); void setContentManagerView(ContentManagerView* view); void setNewTabButton(QAction* newTabAction); ZimView* createNewTab(bool setCurrent, bool adjacentToCurrentTab); ZimView* currentZimView() { return qobject_cast(mp_stackedWidget->currentWidget()); } WebView* currentWebView() { if (ZimView *zv = currentZimView()) return zv->getWebView(); return nullptr; } void openUrl(const QUrl &url, bool newTab); // Redirect call to sub-webView void setTitleOf(const QString& title, ZimView* tab=nullptr); void setIconOf(const QIcon& icon, ZimView* tab=nullptr); QString currentZimId(); void triggerWebPageAction(QWebEnginePage::WebAction action, ZimView* widget=nullptr); QString currentArticleUrl(); QString currentArticleTitle(); virtual QSize tabSizeHint(int index) const; void openFindInPageBar(); void closeTabsByZimId(const QString &id); QStringList getTabUrls() const; QStringList getTabZimIds() const; // The "+" (new tab) button is implemented as a tab (that is always placed at the end). // This function returns the count of real tabs. int realTabCount() const; protected: void mousePressEvent(QMouseEvent *event); void paintEvent(QPaintEvent *); void tabRemoved(int index) override; void tabInserted(int index) override; void resizeEvent(QResizeEvent *) override; signals: void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled); void tabDisplayed(TabType tabType); void currentTitleChanged(const QString& title); void tabRemovedSignal(int index); void tabInsertedSignal(int index); void sizeChanged(); public slots: void closeTab(int index); void openHomePage(); void openOrSwitchToSettingsTab(); void fullScreenRequested(QWebEngineFullScreenRequest request); void on_webview_titleChanged(const QString& title); void moveToNextTab(); void moveToPreviousTab(); void scrollNextTab(); void scrollPreviousTab(); private: void setCloseTabButton(int index); private: QStackedWidget* mp_stackedWidget; QScopedPointer m_fullScreenWindow; private slots: void onTabMoved(int from, int to); void onCurrentChanged(int index); void onWebviewHistoryActionChanged(QWebEnginePage::WebAction action, bool enabled); }; #endif // TABWIDGET_H kiwix-desktop-2.4.1/src/tableofcontentbar.cpp000066400000000000000000000063261473106011000213070ustar00rootroot00000000000000#include "tableofcontentbar.h" #include "ui_tableofcontentbar.h" #include "kiwixapp.h" #include #include TableOfContentBar::TableOfContentBar(QWidget *parent) : QFrame(parent), ui(new Ui::tableofcontentbar) { ui->setupUi(this); ui->titleLabel->setFont(QFont("Selawik", 18, QFont::Weight::Medium)); ui->titleLabel->setText(gt("table-of-content")); ui->hideLabel->setFont(QFont("Selawik", 12)); ui->hideLabel->setTextFormat(Qt::RichText); /* href is needed to make hide clickable, but not used. So Kiwix it is :) */ ui->hideLabel->setText("" + gt("hide") + ""); connect(ui->hideLabel, &QLabel::linkActivated, this, [=](){ KiwixApp::instance()->getAction(KiwixApp::ToggleTOCAction)->setChecked(false); }); ui->tree->setRootIsDecorated(false); ui->tree->setItemsExpandable(false); connect(ui->tree, &QTreeWidget::itemClicked, this, &TableOfContentBar::onTreeItemActivated); connect(ui->tree, &QTreeWidget::itemActivated, this, &TableOfContentBar::onTreeItemActivated); } TableOfContentBar::~TableOfContentBar() { delete ui; } void TableOfContentBar::onTreeItemActivated(QTreeWidgetItem *item) { emit navigationRequested(m_url, item->data(0, Qt::UserRole).toString()); } namespace { QTreeWidgetItem* createChildItem(QTreeWidgetItem* parent, const QString& childNo, const QJsonObject& headerObj) { const auto item = new QTreeWidgetItem(parent); item->setExpanded(true); const auto display = childNo + " " + headerObj["text"].toString(); item->setToolTip(0, display); item->setData(0, Qt::DisplayRole, display); item->setData(0, Qt::FontRole, QFont("Selawik", 12)); item->setData(0, Qt::UserRole, headerObj["anchor"].toString()); return item; } QJsonArray takeDeeperEntries(QJsonArray& headerArr, int level) { QJsonArray result; while (!headerArr.isEmpty()) { const auto& nextHeader = headerArr.first().toObject(); if (nextHeader["level"].toInt() <= level) break; result.push_back(nextHeader); headerArr.pop_front(); } return result; } void createSubTree(QTreeWidgetItem* parent, QString parentNo, QJsonArray& headerArr) { while (!headerArr.isEmpty()) { const auto childHeader = headerArr.takeAt(0).toObject(); const int childLevel = childHeader["level"].toInt(); const QString childNo = parentNo + QString::number(parent->childCount() + 1); QTreeWidgetItem* childItem = createChildItem(parent, childNo, childHeader); QJsonArray deeperEntries = takeDeeperEntries(headerArr, childLevel); createSubTree(childItem, childNo + ".", deeperEntries); } } } void TableOfContentBar::setupTree(const QJsonObject& headers) { const auto webView = KiwixApp::instance()->getTabWidget()->currentWebView(); if (!webView) return; const auto headerUrl = headers["url"].toString(); const auto currentUrl = webView->url().url(QUrl::RemoveFragment); if (headerUrl != currentUrl) return; m_url = headerUrl; ui->tree->clear(); QJsonArray headerArr = headers["headers"].toArray(); createSubTree(ui->tree->invisibleRootItem(), "", headerArr); } kiwix-desktop-2.4.1/src/tableofcontentbar.h000066400000000000000000000011111473106011000207370ustar00rootroot00000000000000#ifndef TABLEOFCONTENTBAR_H #define TABLEOFCONTENTBAR_H #include namespace Ui { class tableofcontentbar; } class QTreeWidgetItem; class TableOfContentBar : public QFrame { Q_OBJECT public: explicit TableOfContentBar(QWidget *parent = nullptr); ~TableOfContentBar(); public slots: void setupTree(const QJsonObject& headers); void onTreeItemActivated(QTreeWidgetItem* item); signals: void navigationRequested(const QString& url, const QString& anchor); private: Ui::tableofcontentbar *ui; QString m_url; }; #endif // TABLEOFCONTENTBAR_H kiwix-desktop-2.4.1/src/tableofcontentbar.ui000066400000000000000000000062231473106011000211360ustar00rootroot00000000000000 tableofcontentbar 0 0 400 300 0 0 Form 0 0 0 0 0 16 0 Qt::Horizontal 40 20 0 Qt::Horizontal QFrame::NoFrame 0 Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::ElideRight 30 true true true false 1 kiwix-desktop-2.4.1/src/texttospeechbar.cpp000066400000000000000000000143731473106011000210200ustar00rootroot00000000000000#include "texttospeechbar.h" #include "kiwixapp.h" #include "ui_texttospeechbar.h" TextToSpeechBar::TextToSpeechBar(QWidget *parent) : QFrame(parent), ui(new Ui::TextToSpeechBar) { ui->setupUi(this); connect(&m_speech, &QTextToSpeech::stateChanged, this, &TextToSpeechBar::onStateChanged); ui->stopButton->setText(gt("stop")); ui->stopButton->setDisabled(true); const auto app = KiwixApp::instance(); connect(app->getAction(KiwixApp::ReadStopAction), &QAction::triggered, this, &TextToSpeechBar::stop); connect(ui->stopButton, &QPushButton::pressed, this, &TextToSpeechBar::stop); connect(ui->closeButton, &QPushButton::pressed, this, &TextToSpeechBar::speechClose); setupVoiceComboBox(); setupLanguageComboBox(); languageSelected(ui->langComboBox->currentIndex()); connect(app->getAction(KiwixApp::ToggleTTSLanguageAction), &QAction::triggered, this, &TextToSpeechBar::toggleLanguage); connect(app->getAction(KiwixApp::ToggleTTSVoiceAction), &QAction::triggered, this, &TextToSpeechBar::toggleVoice); } void TextToSpeechBar::speak(const QString &text) { m_text = text; m_speech.say(m_text); } void TextToSpeechBar::stop() { m_speech.stop(); } void TextToSpeechBar::setLocale(const QLocale& locale) { for (int i = 0; i < ui->langComboBox->count(); i++) { if (ui->langComboBox->itemData(i).toLocale().language() == locale.language()) { ui->langComboBox->setCurrentIndex(i); languageSelected(i); return; } } } void TextToSpeechBar::setupLanguageComboBox() { ui->langLabel->setText(gt("language")); ui->langComboBox->setMaxVisibleItems(10); ui->langComboBox->setLineEdit(new ComboBoxLineEdit(ui->langComboBox)); QLocale current = QLocale::system(); for (const auto& locale : m_speech.availableLocales()) { const QString name(QString("%1 (%2)") .arg(QLocale::languageToString(locale.language())) .arg(locale.nativeLanguageName())); ui->langComboBox->addItem(name, locale); if (locale.name() == current.name()) current = locale; } ui->langComboBox->setCurrentIndex(ui->langComboBox->findData(current)); connect(ui->langComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &TextToSpeechBar::languageSelected); } void TextToSpeechBar::setupVoiceComboBox() { ui->voiceLabel->setText(gt("voice")); ui->voiceComboBox->setMaxVisibleItems(10); ui->voiceComboBox->setLineEdit(new ComboBoxLineEdit(ui->voiceComboBox)); } void TextToSpeechBar::resetVoiceComboBox() { disconnect(ui->voiceComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &TextToSpeechBar::voiceSelected); ui->voiceComboBox->clear(); m_voices = m_speech.availableVoices(); if ( m_voices.isEmpty() ) return; for (const auto& voice : m_voices) { ui->voiceComboBox->addItem(QString("%1 - %2 - %3").arg(voice.name()) .arg(QVoice::genderName(voice.gender())) .arg(QVoice::ageName(voice.age()))); } const int voiceIndex = getVoiceIndex(); ui->voiceComboBox->setCurrentIndex(voiceIndex); voiceSelected(voiceIndex); connect(ui->voiceComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &TextToSpeechBar::voiceSelected); } int TextToSpeechBar::getVoiceIndex() { int voiceIndex = 0; const QVoice currentVoice = m_speech.voice(); const QString savedVoiceName = KiwixApp::instance()->getSavedVoiceName(m_speech.locale().name()); /* We either stay with default voices or matches with the saved voice. */ for (int i = 0; i < ui->voiceComboBox->count(); i++) { if (m_voices[i].name() == currentVoice.name()) voiceIndex = i; if (m_voices[i].name() == savedVoiceName) { voiceIndex = i; break; } } return voiceIndex; } void TextToSpeechBar::speechClose() { /* Prevent webview from scrolling to up to the top after losing focus. */ const auto current = KiwixApp::instance()->getTabWidget()->currentWebView(); if (!current) return; current->setFocus(); m_speech.stop(); close(); } void TextToSpeechBar::speechShow() { show(); setFocus(); } void TextToSpeechBar::toggleVoice() { const auto zimView = KiwixApp::instance()->getTabWidget()->currentZimView(); if (!zimView || zimView->getTextToSpeechBar() != this) return; if (isHidden()) speechShow(); ui->voiceComboBox->showPopup(); } void TextToSpeechBar::toggleLanguage() { const auto zimView = KiwixApp::instance()->getTabWidget()->currentZimView(); if (!zimView || zimView->getTextToSpeechBar() != this) return; if (isHidden()) speechShow(); ui->langComboBox->showPopup(); } void TextToSpeechBar::languageSelected(int index) { const QLocale locale = ui->langComboBox->itemData(index).toLocale(); m_speech.setLocale(locale); resetVoiceComboBox(); } void TextToSpeechBar::voiceSelected(int index) { const auto voice = m_voices.at(index); const auto currentLang = ui->langComboBox->currentData().toLocale().name(); KiwixApp::instance()->saveVoiceName(currentLang, voice.name()); m_speech.setVoice(voice); if (m_speech.state() == QTextToSpeech::Speaking) speak(m_text); } void TextToSpeechBar::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { speechClose(); return; } QFrame::keyPressEvent(event); } void TextToSpeechBar::onStateChanged(QTextToSpeech::State state) { ui->stopButton->setEnabled(state != QTextToSpeech::Ready); } ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) : QLineEdit(parent) { setFrame(false); /* Work around to both have max visible item and a read-only combobox.*/ setReadOnly(true); connect(this, &QLineEdit::selectionChanged, this, &ComboBoxLineEdit::preventSelection); } void ComboBoxLineEdit::preventSelection() { setSelection(0, 0); } void ComboBoxLineEdit::mouseReleaseEvent(QMouseEvent *) { const auto combo = qobject_cast(parent()); if(combo) combo->showPopup(); } kiwix-desktop-2.4.1/src/texttospeechbar.h000066400000000000000000000022241473106011000204550ustar00rootroot00000000000000#ifndef TEXTTOSPEECHMANAGER_H #define TEXTTOSPEECHMANAGER_H #include #include #include namespace Ui { class TextToSpeechBar; } class ComboBoxLineEdit : public QLineEdit { Q_OBJECT public: explicit ComboBoxLineEdit(QWidget *parent = 0); public slots: void preventSelection(); protected: void mouseReleaseEvent(QMouseEvent *); }; class TextToSpeechBar : public QFrame { Q_OBJECT public: explicit TextToSpeechBar(QWidget *parent = nullptr); void speak(const QString& text); void stop(); void setLocale(const QLocale& locale); void setupLanguageComboBox(); void setupVoiceComboBox(); void resetVoiceComboBox(); int getVoiceIndex(); public slots: void onStateChanged(QTextToSpeech::State state); void speechClose(); void speechShow(); void toggleVoice(); void toggleLanguage(); void languageSelected(int index); void voiceSelected(int index); protected: void keyPressEvent(QKeyEvent *event); private: QTextToSpeech m_speech; Ui::TextToSpeechBar *ui; QVector m_voices; QString m_text; }; #endif // TEXTTOSPEECHMANAGER_H kiwix-desktop-2.4.1/src/texttospeechbar.ui000066400000000000000000000061711473106011000206500ustar00rootroot00000000000000 TextToSpeechBar 0 0 833 43 0 0 Frame Qt::LeftToRight true true Qt::Horizontal QSizePolicy::Expanding 40 20 true 0 0 :/icons/stop-circle.svg:/icons/stop-circle.svg Qt::Horizontal 40 20 :/icons/close.svg:/icons/close.svg true kiwix-desktop-2.4.1/src/thumbnaildownloader.cpp000066400000000000000000000023711473106011000216510ustar00rootroot00000000000000#include "thumbnaildownloader.h" #include #include #include #include ThumbnailDownloader::ThumbnailDownloader() { connect(this, &ThumbnailDownloader::oneThumbnailDownloaded, this, &ThumbnailDownloader::startNextDownload); } ThumbnailDownloader::~ThumbnailDownloader() { } void ThumbnailDownloader::addDownload(QString url, ThumbnailId index) { m_downloadQueue.append({index, url}); if (!m_isDownloading) startNextDownload(); } void ThumbnailDownloader::startNextDownload() { if (m_downloadQueue.size() == 0) { m_isDownloading = false; return; } m_isDownloading = true; downloadThumbnail(m_downloadQueue.takeFirst()); } void ThumbnailDownloader::downloadThumbnail(ThumbnailInfo thumbnailInfo) { QNetworkRequest req(thumbnailInfo.second); auto reply = manager.get(req); connect(reply, &QNetworkReply::finished, this, [=](){ fileDownloaded(reply, thumbnailInfo); }); } void ThumbnailDownloader::fileDownloaded(QNetworkReply *pReply, ThumbnailInfo thumbnailInfo) { auto downloadedData = pReply->readAll(); emit oneThumbnailDownloaded(thumbnailInfo.first, thumbnailInfo.second, downloadedData); pReply->deleteLater(); } kiwix-desktop-2.4.1/src/thumbnaildownloader.h000066400000000000000000000016141473106011000213150ustar00rootroot00000000000000#ifndef THUMBNAILDOWNLOADER_H #define THUMBNAILDOWNLOADER_H #include #include #include #include class ThumbnailDownloader : public QObject { Q_OBJECT public: typedef QString ThumbnailId; typedef QPair ThumbnailInfo; public: ThumbnailDownloader(); ~ThumbnailDownloader(); void addDownload(QString url, ThumbnailId index); void startNextDownload(); void clearQueue() { m_downloadQueue.clear(); } private: void downloadThumbnail(ThumbnailInfo thumbnailInfo); signals: void oneThumbnailDownloaded(ThumbnailId, QString, QByteArray); private: QQueue m_downloadQueue; QNetworkAccessManager manager; bool m_isDownloading = false; private slots: void fileDownloaded(QNetworkReply *pReply, ThumbnailInfo thumbnailInfo); }; #endif // THUMBNAILDOWNLOADER_H kiwix-desktop-2.4.1/src/topwidget.cpp000066400000000000000000000103171473106011000176140ustar00rootroot00000000000000#include "topwidget.h" #include "kconstants.h" #include "kiwixapp.h" #include "mainmenu.h" #include "tabbar.h" #include "portutils.h" #include #include #include TopWidget::TopWidget(QWidget *parent) : QToolBar(parent) { auto app = KiwixApp::instance(); QAction *back = app->getAction(KiwixApp::HistoryBackAction); connect(back, &QAction::triggered, [app](){ app->getTabWidget()->triggerWebPageAction(QWebEnginePage::Back); }); addAction(back); QAction *forward = app->getAction(KiwixApp::HistoryForwardAction); connect(forward, &QAction::triggered, [app](){ app->getTabWidget()->triggerWebPageAction(QWebEnginePage::Forward); }); addAction(forward); QAction *random = app->getAction(KiwixApp::RandomArticleAction); addAction(random); QAction *toc = app->getAction(KiwixApp::ToggleTOCAction); addAction(toc); // For CSS if (QGuiApplication::isLeftToRight()) { widgetForAction(back)->setObjectName("leftHistoryButton"); widgetForAction(forward)->setObjectName("rightHistoryButton"); } else { widgetForAction(forward)->setObjectName("leftHistoryButton"); widgetForAction(back)->setObjectName("rightHistoryButton"); } addSeparator(); addAction(app->getAction(KiwixApp::OpenHomePageAction)); addWidget(&m_searchEntry); addAction(app->getAction(KiwixApp::ToggleReadingListAction)); addSeparator(); addAction(app->getAction(KiwixApp::OpenFileAction)); QMenu* menu = new MainMenu(); QToolButton *toolButton = new QToolButton(menu); toolButton->setIcon(QIcon(":/icons/more.svg")); toolButton->setPopupMode(QToolButton::InstantPopup); toolButton->setToolTip(gt("main-menu")); toolButton->setMenu(menu); addWidget(toolButton); setContextMenuPolicy( Qt::PreventContextMenu ); #if !SYSTEMTITLEBAR addAction(QIcon(":/icons/minimize.svg"), "minimize", parent, SLOT(showMinimized())); #endif addAction(app->getAction(KiwixApp::ToggleFullscreenAction)); widgetForAction(app->getAction(KiwixApp::ToggleFullscreenAction))->setObjectName("fullScreenButton"); #if !SYSTEMTITLEBAR addAction(QIcon(":/icons/close.svg"), "close", parent, SLOT(close())); #endif setMovable(false); } TopWidget::~TopWidget() { } void TopWidget::handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled) { auto app = KiwixApp::instance(); switch (action) { case QWebEnginePage::Back: app->getAction(KiwixApp::HistoryBackAction)->setEnabled(enabled); break; case QWebEnginePage::Forward: app->getAction(KiwixApp::HistoryForwardAction)->setEnabled(enabled); break; default: break; } } void TopWidget::mousePressEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) return; QPoint globalPos = portutils::getGlobalPos(*event); m_cursorPos = globalPos + frameGeometry().topLeft() - parentWidget()->frameGeometry().topLeft(); m_timestamp = event->timestamp(); event->accept(); } void TopWidget::mouseMoveEvent(QMouseEvent *event) { if (event->timestamp() <= m_timestamp) return; QPoint globalPos = portutils::getGlobalPos(*event); m_timestamp = event->timestamp(); auto delta = globalPos - m_cursorPos; parentWidget()->move(delta); event->accept(); } QToolButton* TopWidget::getBackButton() const { auto app = KiwixApp::instance(); QAction *back = app->getAction(KiwixApp::HistoryBackAction); return qobject_cast(widgetForAction(back)); } QToolButton* TopWidget::getForwardButton() const { auto app = KiwixApp::instance(); QAction *forward = app->getAction(KiwixApp::HistoryForwardAction); return qobject_cast(widgetForAction(forward)); } void TopWidget::updateBackForwardButtons() { WebView *webview = KiwixApp::instance()->getTabWidget()->currentWebView(); if (webview) { back_menu.reset(webview->getHistoryBackMenu()); forward_menu.reset(webview->getHistoryForwardMenu()); } else { back_menu.reset(); forward_menu.reset(); } getBackButton()->setMenu(back_menu.data()); getForwardButton()->setMenu(forward_menu.data()); } kiwix-desktop-2.4.1/src/topwidget.h000066400000000000000000000016311473106011000172600ustar00rootroot00000000000000#ifndef TOPWIDGET_H #define TOPWIDGET_H #include #include #include #include #include "searchbar.h" class TopWidget : public QToolBar { Q_OBJECT public: explicit TopWidget(QWidget *parent = nullptr); virtual ~TopWidget(); SearchBar &getSearchBar() { return m_searchEntry; }; public slots: void handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled); void updateBackForwardButtons(); protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); private: SearchBar m_searchEntry; QPoint m_cursorPos; ulong m_timestamp; QScopedPointer back_menu; QScopedPointer forward_menu; QToolButton* getBackButton() const; QToolButton* getForwardButton() const; }; #endif // TOPWIDGET_H kiwix-desktop-2.4.1/src/translation.cpp000066400000000000000000000026201473106011000201420ustar00rootroot00000000000000#include "translation.h" #include #include #include #include #include Translation::Translation() { } void Translation::setTranslation(QLocale locale) { auto defaultText = JsonFileToQMap(":/i18n/en.json"); if (defaultText.isEmpty()) { throw std::runtime_error("Invalid translation file"); } if (locale.bcp47Name() == "en") { m_translations = defaultText; return; } m_translations = JsonFileToQMap(":/i18n/" + locale.bcp47Name() + ".json"); for (auto &key : defaultText.keys()) { if (!m_translations.contains(key) || m_translations.value(key).isEmpty()) { m_translations.insert(key, defaultText.value(key)); } } } QMap Translation::JsonFileToQMap(const QString &filePath) { QMap translations; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { return translations; } QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); file.close(); if (doc.isNull()) { return translations; } auto jsonObj = doc.object(); for (auto &key : jsonObj.keys()) { translations.insert(key, jsonObj.value(key).toString()); } return translations; } QString Translation::getText(const QString &key) { return (m_translations.contains(key)) ? m_translations.value(key) : key; } kiwix-desktop-2.4.1/src/translation.h000066400000000000000000000006051473106011000176100ustar00rootroot00000000000000#ifndef TRANSLATION_H #define TRANSLATION_H #include #include #include class Translation { public: Translation(); void setTranslation(QLocale locale); QString getText(const QString &key); private: QMap JsonFileToQMap(const QString &filePath); private: QMap m_translations; }; #endif // TRANSLATION_H kiwix-desktop-2.4.1/src/urlschemehandler.cpp000066400000000000000000000215521473106011000211360ustar00rootroot00000000000000#include "urlschemehandler.h" #include "kiwixapp.h" #include "blobbuffer.h" #include #include #include #include #include #include #include #include #include #include UrlSchemeHandler::UrlSchemeHandler() { } zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url) { std::string path = url.path().toUtf8().constData(); if (path[0] == '/') path = path.substr(1); try { return archive.getEntryByPath(path); } catch (zim::EntryNotFound& e) { if (path.empty() || path == "/") { return archive.getMainEntry(); } } throw zim::EntryNotFound("Cannot find entry for non empty path"); } void UrlSchemeHandler::handleContentRequest(QWebEngineUrlRequestJob *request) { auto qurl = request->requestUrl(); auto library = KiwixApp::instance()->getLibrary(); auto zim_id = qurl.host(); zim_id.resize(zim_id.length()-4); std::shared_ptr archive; try { archive = library->getArchive(zim_id); } catch (std::out_of_range& e) { replyZimNotFoundPage(request, zim_id); return; } try { auto entry = getArchiveEntryFromUrl(*archive, qurl); auto item = entry.getItem(true); if (entry.isRedirect()) { auto path = QString("/") + QString::fromStdString(item.getPath()); qurl.setPath(path); request->redirect(qurl); return; } BlobBuffer* buffer = new BlobBuffer(item.getData(0)); auto mimeType = QByteArray::fromStdString(item.getMimetype()); mimeType = mimeType.split(';')[0]; connect(request, &QObject::destroyed, buffer, &QObject::deleteLater); request->reply(mimeType, buffer); } catch (zim::EntryNotFound&) { request->fail(QWebEngineUrlRequestJob::UrlNotFound); } catch (const zim::ZimFileFormatError&) { replyBadZimFilePage(request, zim_id); } } void UrlSchemeHandler::handleMetaRequest(QWebEngineUrlRequestJob* request) { auto qurl = request->requestUrl(); auto host = qurl.host(); auto parts = host.split('.'); auto zimId = parts[0]; auto metaName = parts[1]; if (metaName == "favicon") { try { auto library = KiwixApp::instance()->getLibrary(); auto book = library->getBookById(zimId); auto illustration = book.getIllustration(48); std::string content = illustration->getData(); std::string mimeType = illustration->mimeType; QBuffer* buffer = new QBuffer; buffer->setData(content.data(), content.size()); connect(request, &QObject::destroyed, buffer, &QObject::deleteLater); request->reply(QByteArray::fromStdString(mimeType), buffer); return; } catch (...) {} } request->fail(QWebEngineUrlRequestJob::UrlNotFound); } class IdNameMapper : public kiwix::NameMapper { std::string getNameForId(const std::string& id) const { return id + ".zim"; } std::string getIdForName(const std::string& id) const { return id.substr(0, id.size()-4); } }; namespace { struct SearchResultsWithEstimatedMatchCount { std::shared_ptr results; int estimatedMatchCount = 0; }; SearchResultsWithEstimatedMatchCount getSearchResults(zim::Search& s, int start, int pageLength) { SearchResultsWithEstimatedMatchCount r; r.estimatedMatchCount = s.getEstimatedMatches(); r.results = std::make_shared(s.getResults(start, pageLength)); return r; } } // unnamed namespace void UrlSchemeHandler::handleSearchRequest(QWebEngineUrlRequestJob* request) { auto qurl = request->requestUrl(); auto app = KiwixApp::instance(); auto host = qurl.host(); auto bookId = host.split('.')[0]; qInfo() << "Handling request" << qurl; QUrlQuery query(qurl.query()); if (bookId == "library") { bookId = query.queryItemValue("content"); } auto searchQuery = query.queryItemValue("pattern").toStdString(); int start = 0; bool ok; int temp = query.queryItemValue("start").toInt(&ok); if (ok) start = temp; int pageLength = 25; temp = query.queryItemValue("pageLength").toInt(&ok); if (ok) pageLength = temp; std::shared_ptr search; try { auto searcher = app->getLibrary()->getSearcher(bookId); search = std::make_shared(searcher->search(searchQuery)); } catch(...) { request->fail(QWebEngineUrlRequestJob::UrlInvalid); return; } SearchResultsWithEstimatedMatchCount searchResult; try { searchResult = getSearchResults(*search, start, pageLength); } catch (...) { request->fail(QWebEngineUrlRequestJob::RequestFailed); return; } kiwix::SearchRenderer renderer( *searchResult.results, start, searchResult.estimatedMatchCount); renderer.setSearchPattern(searchQuery); renderer.setSearchBookQuery("content="+bookId.toStdString()); renderer.setProtocolPrefix("zim://"); renderer.setSearchProtocolPrefix("zim://" + host.toStdString() + "/"); renderer.setPageLength(pageLength); IdNameMapper mapper; auto content = renderer.getHtml(mapper, nullptr); QBuffer *buffer = new QBuffer; buffer->setData(content.data(), content.size()); connect(request, &QObject::destroyed, buffer, &QObject::deleteLater); request->reply("text/html", buffer); } namespace { QString completeHtml(const QString& htmlBodyContent) { const QString htmlHead = R"()"; const QString fullHtml = "" + htmlHead + "" + htmlBodyContent + "" + ""; return fullHtml; } void sendHtmlResponse(QWebEngineUrlRequestJob *request, const QString& htmlBodyContent) { QBuffer *buffer = new QBuffer; buffer->open(QIODevice::WriteOnly); buffer->write(completeHtml(htmlBodyContent).toStdString().c_str()); buffer->close(); QObject::connect(request, SIGNAL(destroyed()), buffer, SLOT(deleteLater())); request->reply("text/html", buffer); } } // unnamed namespace void UrlSchemeHandler::replyZimNotFoundPage(QWebEngineUrlRequestJob *request, const QString &zimId) { QString path = "N/A", name = "N/A"; try { auto& book = KiwixApp::instance()->getLibrary()->getBookById(zimId); path = QString::fromStdString(book.getPath()); name = QString::fromStdString(book.getName()); } catch (...) { /* Blank */ } QString contentHtml = "
" "

" + gt("file-not-found-title") + "

" "

" + gt("file-not-found-text") + "

" "

" + gt("zim-id") + ": " + zimId + "

" "

" + gt("zim-name") + ": " + name + "

" "

" + gt("zim-path") + ": " + path + "

" "
"; sendHtmlResponse(request, contentHtml); } void UrlSchemeHandler::replyBadZimFilePage(QWebEngineUrlRequestJob *request, const QString &zimId) { const auto& book = KiwixApp::instance()->getLibrary()->getBookById(zimId); const QString path = QString::fromStdString(book.getPath()); const QString name = QString::fromStdString(book.getName()); const QString zimEntryPath = request->requestUrl().path(); QString contentHtml = "
" "

" + gt("bad-zim-file-error-page-title") + "

" "

" + gt("bad-zim-file-error-page-text") + "

" "

" + gt("zim-id") + ": " + zimId + "

" "

" + gt("zim-name") + ": " + name + "

" "

" + gt("zim-path") + ": " + path + "

" "

" + gt("zim-entry-path") + ": " + zimEntryPath + "

" "
"; sendHtmlResponse(request, contentHtml); } void UrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request) { auto qurl = request->requestUrl(); auto host = qurl.host(); if (host.endsWith(".zim")) { handleContentRequest(request); } else if (host.endsWith(".meta")) { handleMetaRequest(request); } else if (host.endsWith(".search")) { handleSearchRequest(request); } else { request->fail(QWebEngineUrlRequestJob::UrlNotFound); } } kiwix-desktop-2.4.1/src/urlschemehandler.h000066400000000000000000000012271473106011000206000ustar00rootroot00000000000000#ifndef URLSCHEMEHANDLER_H #define URLSCHEMEHANDLER_H #include class UrlSchemeHandler : public QWebEngineUrlSchemeHandler { Q_OBJECT public: UrlSchemeHandler(); void requestStarted(QWebEngineUrlRequestJob *request); private: void handleMetaRequest(QWebEngineUrlRequestJob *request); void handleContentRequest(QWebEngineUrlRequestJob *request); void handleSearchRequest(QWebEngineUrlRequestJob *request); void replyZimNotFoundPage(QWebEngineUrlRequestJob *request, const QString& zimId); void replyBadZimFilePage(QWebEngineUrlRequestJob *request, const QString& zimId); }; #endif // URLSCHEMEHANDLER_H kiwix-desktop-2.4.1/src/webpage.cpp000066400000000000000000000012271473106011000172200ustar00rootroot00000000000000#include "webpage.h" #include #include #include #include "kiwixapp.h" #include WebPage::WebPage(QObject *parent) : QWebEnginePage(KiwixApp::instance()->getProfile(), parent) { action(QWebEnginePage::SavePage)->setVisible(false); action(QWebEnginePage::ViewSource)->setVisible(false); action(QWebEnginePage::Reload)->setVisible(false); } bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType /*type*/, bool /*isMainFrame*/) { if (url.scheme() != "zim") { QDesktopServices::openUrl(url); return false; } return true; } kiwix-desktop-2.4.1/src/webpage.h000066400000000000000000000004511473106011000166630ustar00rootroot00000000000000#ifndef WEBPAGE_H #define WEBPAGE_H #include class WebPage : public QWebEnginePage { Q_OBJECT public: explicit WebPage(QObject *parent = nullptr); protected: bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); }; #endif // WEBPAGE_H kiwix-desktop-2.4.1/src/webview.cpp000066400000000000000000000322651473106011000172640ustar00rootroot00000000000000class QMenu; #include "webview.h" #include #include #include #include "kiwixapp.h" #include "webpage.h" #include "css_constants.h" #include #include #include #include #include #include #include #include #include #include #include "kiwixwebchannelobject.h" #include "tableofcontentbar.h" zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url); QString askForSaveFilePath(const QString& suggestedName); void WebViewBackMenu::showEvent(QShowEvent *) { /* In Qt 5.12 CSS options for shifting this menu didn't work. * In particular: * - toolbar->setContentsMargins(0,0,0,0); * - toolbar->layout()->setContentsMargins(0,0,0,0); * - QToolBar { padding-left: } * - QToolBar { margin-left; } * - QToolBar { padding: 5px 12px 5px 12px; } * - QToolBar::separator:first { width: 10px; } * (that was attempts to set some spacing on left and right in toolbar * so back button will be shifted right. * If in Qt 6.x QToolButton shows its menu in the right position * this code can be removed. */ QRect geo = geometry(); const int marginLeft = CSS::TopWidget::QToolButton::backButton::marginLeft; geo.moveLeft(geo.left() + marginLeft); geo.moveTop(geo.top() + 2); setGeometry(geo); } void WebViewForwardMenu::showEvent(QShowEvent *) { QRect geo = geometry(); geo.moveTop(geo.top() + 2); setGeometry(geo); } QString getZimIdFromUrl(QUrl url) { return url.host().split('.')[0]; } QString getResultTypeFromUrl(QUrl url) { return url.host().split('.')[1]; } void WebView::applyCorrectZoomFactor() { auto url = this->url(); auto settingsManager = KiwixApp::instance()->getSettingsManager(); qreal zoomFactor; const bool isSearchResultsView = QUrlQuery(url).hasQueryItem("pattern") && (getResultTypeFromUrl(url) == "search"); if (isSearchResultsView) { zoomFactor = settingsManager->getZoomFactor(); } else { auto zimId = getZimIdFromUrl(url); zoomFactor = settingsManager->getZoomFactorByZimId(zimId); } this->setZoomFactor(zoomFactor); } WebView::WebView(QWidget *parent) : QWebEngineView(parent) { setPage(new WebPage(this)); QObject::connect(this, &QWebEngineView::urlChanged, this, &WebView::onUrlChanged); connect(this->page(), &QWebEnginePage::linkHovered, this, [=] (const QString& url) { m_linkHovered = url; }); /* In Qt 5.12, the zoom factor is not correctly passed after a fulltext search * Bug Report: https://bugreports.qt.io/browse/QTBUG-51851 * This rezooms the page to its correct zoom (default/by ZIM ID) after loading is finished. * If the page is search results, we put the default zoom factor * If in Qt 6.x, the bug is fixed this code can be removed. */ #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) connect(this, &QWebEngineView::loadFinished, this, [=] (bool ok) { if (ok) { applyCorrectZoomFactor(); } }); #endif const auto channel = new QWebChannel(this); const auto kiwixChannelObj = new KiwixWebChannelObject; page()->setWebChannel(channel, QWebEngineScript::UserWorld); channel->registerObject("kiwixChannelObj", kiwixChannelObj); const auto tabbar = KiwixApp::instance()->getTabWidget(); connect(tabbar, &TabBar::currentTitleChanged, this, &WebView::onCurrentTitleChanged); connect(kiwixChannelObj, &KiwixWebChannelObject::headersChanged, this, &WebView::onHeadersReceived); const auto tocbar = KiwixApp::instance()->getMainWindow()->getTableOfContentBar(); connect(this, &WebView::headersChanged, tocbar, &TableOfContentBar::setupTree); connect(tocbar, &TableOfContentBar::navigationRequested, this, &WebView::onNavigationRequested); connect(this, &WebView::navigationRequested, kiwixChannelObj, &KiwixWebChannelObject::navigationRequested); } WebView::~WebView() {} bool WebView::isWebActionEnabled(QWebEnginePage::WebAction webAction) const { return page()->action(webAction)->isEnabled(); } QMenu* WebView::getHistoryBackMenu() const { QWebEngineHistory *h = history(); const int cur = h->currentItemIndex(); if (cur <= 0) { return Q_NULLPTR; } auto ret = new WebViewBackMenu(); for (int i = cur - 1 ; i >= 0 ; i--) { addHistoryItemAction(ret, h->itemAt(i), i); } return ret; } QMenu* WebView::getHistoryForwardMenu() const { QWebEngineHistory *h = history(); const int cur = h->currentItemIndex(); if (cur + 1 >= h->count()) { return Q_NULLPTR; } auto ret = new WebViewForwardMenu(); for (int i = cur + 1 ; i < h->count() ; i++) { addHistoryItemAction(ret, h->itemAt(i), i); } return ret; } namespace { /** * @brief Get the Zim Item object corresponding to the given url. * * @param url QUrl * @return zim::Item * * @exception throws exception if zimId is invalid, archive doesn't exist, * entry is invalid or not found, or entry is redirect. */ zim::Item getZimItem(const QUrl& url) { const auto app = KiwixApp::instance(); const auto library = app->getLibrary(); const auto archive = library->getArchive(getZimIdFromUrl(url)); const auto entry = getArchiveEntryFromUrl(*archive, url); return entry.getItem(true); } bool isHTMLContent(const zim::Item& item) { auto mimeType = QByteArray::fromStdString(item.getMimetype()); mimeType = mimeType.split(';')[0]; return mimeType == "text/html"; } } void WebView::saveViewContent() { try { const auto item = getZimItem(url()); /* We have to sanitize here, as parsing will start once we pass the file name to either save or download method. */ const QString suggestedFileName = QString::fromStdString(kiwix::getSlugifiedFileName(item.getTitle())); if (isHTMLContent(item)) { const QString fileName = askForSaveFilePath(suggestedFileName + ".pdf"); if (!fileName.isEmpty()) page()->printToPdf(fileName); } else page()->download(this->url(), suggestedFileName); } catch (...) { /* Blank */} } void WebView::onCurrentTitleChanged() { const auto tabbar = KiwixApp::instance()->getTabWidget(); const auto noAnchorUrl = url().url(QUrl::RemoveFragment); const auto headersValid = m_headers["url"].toString() == noAnchorUrl; /* If headers not valid for this webview, then we are loading and the emit will be handled by KiwixWebChannelObject::headersChanged. */ if (tabbar->currentWebView() == this && headersValid) emit headersChanged(m_headers); } void WebView::onHeadersReceived(const QString& headersJSONStr) { const auto tabbar = KiwixApp::instance()->getTabWidget(); m_headers = QJsonDocument::fromJson(headersJSONStr.toUtf8()).object(); if (tabbar->currentWebView() == this) emit headersChanged(m_headers); } void WebView::onNavigationRequested(const QString &url, const QString &anchor) { const auto tabbar = KiwixApp::instance()->getTabWidget(); if (tabbar->currentWebView() == this) emit navigationRequested(url, anchor); } void WebView::addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const { QAction *a = menu->addAction(item.title()); a->setData(QVariant::fromValue(n)); connect(a, &QAction::triggered, this, &WebView::gotoTriggeredHistoryItemAction); } void WebView::gotoTriggeredHistoryItemAction() { QAction *a = qobject_cast(QObject::sender()); if (!a) return; int n = a->data().toInt(); QWebEngineHistory *h = history(); if (n < 0 || n >= h->count()) return; h->goToItem(h->itemAt(n)); } QWebEngineView* WebView::createWindow(QWebEnginePage::WebWindowType type) { if ( type==QWebEnginePage::WebBrowserBackgroundTab || type==QWebEnginePage::WebBrowserTab ) { auto tabWidget = KiwixApp::instance()->getTabWidget(); return tabWidget->createNewTab(false, true)->getWebView(); } return nullptr; } void WebView::onUrlChanged(const QUrl& url) { auto zimId = getZimIdFromUrl(url); auto app = KiwixApp::instance(); app->saveListOfOpenTabs(); if (m_currentZimId == zimId ) { return; } m_currentZimId = zimId; emit zimIdChanged(m_currentZimId); m_icon = app->getLibrary()->getBookIcon(m_currentZimId); auto zoomFactor = app->getSettingsManager()->getZoomFactorByZimId(zimId); this->setZoomFactor(zoomFactor); emit iconChanged(m_icon); } void WebView::wheelEvent(QWheelEvent *event) { if ((event->modifiers() & Qt::ControlModifier) != 0) { if (event->angleDelta().y() > 0) { KiwixApp::instance()->getAction(KiwixApp::ZoomInAction)->activate(QAction::Trigger); } else if (event->angleDelta().y() < 0) { KiwixApp::instance()->getAction(KiwixApp::ZoomOutAction)->activate(QAction::Trigger); } } } void WebView::contextMenuEvent(QContextMenuEvent *event) { QMenu* menu; if (m_linkHovered.isEmpty()) { menu = createStandardContextMenu(); } else { menu = createLinkContextMenu(); } #if defined(QT_TEXTTOSPEECH_LIB) const auto app = KiwixApp::instance(); menu->addAction(app->getAction(KiwixApp::ReadArticleAction)); if (page()->hasSelection()) menu->addAction(app->getAction(KiwixApp::ReadTextAction)); #endif menu->exec(event->globalPos()); } QMenu* WebView::createStandardContextMenu() { auto app = KiwixApp::instance(); QMenu* menu = new QMenu(this); auto backAction = new QAction(gt("back")); backAction->setEnabled(app->getAction(KiwixApp::HistoryBackAction)->isEnabled()); backAction->setIcon(app->getAction(KiwixApp::HistoryBackAction)->icon()); menu->addAction(backAction); connect(menu, &QObject::destroyed, backAction, &QObject::deleteLater); connect(backAction, &QAction::triggered, this, [=](bool checked) { Q_UNUSED(checked); KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Back); }); auto forwardAction = new QAction(gt("forward")); forwardAction->setEnabled(app->getAction(KiwixApp::HistoryForwardAction)->isEnabled()); forwardAction->setIcon(app->getAction(KiwixApp::HistoryForwardAction)->icon()); menu->addAction(forwardAction); connect(menu, &QObject::destroyed, forwardAction, &QObject::deleteLater); connect(forwardAction, &QAction::triggered, this, [=](bool checked) { Q_UNUSED(checked); KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Forward); }); menu->addAction(app->getAction(KiwixApp::SavePageAsAction)); return menu; } QMenu* WebView::createLinkContextMenu() { QMenu* menu = new QMenu(this); if (!m_linkHovered.startsWith("zim://")) { auto openLinkInWebBrowserAction = new QAction(gt("open-link-in-web-browser")); menu->addAction(openLinkInWebBrowserAction); connect(menu, &QObject::destroyed, openLinkInWebBrowserAction, &QObject::deleteLater); connect(openLinkInWebBrowserAction, &QAction::triggered, this, [=](bool checked) { Q_UNUSED(checked); QDesktopServices::openUrl(m_linkHovered); }); } else { auto openLinkNewTab = new QAction(gt("open-link-new-tab")); openLinkNewTab->setIcon(QIcon(":/icons/new-tab-icon.svg")); menu->addAction(openLinkNewTab); connect(menu, &QObject::destroyed, openLinkNewTab, &QObject::deleteLater); connect(openLinkNewTab, &QAction::triggered, this, [=](bool checked) { Q_UNUSED(checked); KiwixApp::instance()->openUrl(m_linkHovered, true); }); } return menu; } bool WebView::eventFilter(QObject *src, QEvent *e) { Q_UNUSED(src) // work around QTBUG-43602 if (e->type() == QEvent::Wheel) { auto we = static_cast(e); if (we->modifiers() == Qt::ControlModifier) return true; } if (e->type() == QEvent::MouseButtonRelease) { auto me = static_cast(e); if (!m_linkHovered.startsWith("zim://") && (me->modifiers() == Qt::ControlModifier || me->button() == Qt::MiddleButton)) { QDesktopServices::openUrl(m_linkHovered); return true; } if (me->button() == Qt::BackButton) { back(); return true; } if (me->button() == Qt::ForwardButton) { forward(); return true; } } return false; } bool WebView::event(QEvent *event) { // work around QTBUG-43602 if (event->type() == QEvent::ChildAdded) { auto ce = static_cast(event); ce->child()->installEventFilter(this); } else if (event->type() == QEvent::ChildRemoved) { auto ce = static_cast(event); ce->child()->removeEventFilter(this); } if (event->type() == QEvent::ToolTip) { return true; } else { return QWebEngineView::event(event); } return true; } kiwix-desktop-2.4.1/src/webview.h000066400000000000000000000041721473106011000167250ustar00rootroot00000000000000#ifndef WEBVIEW_H #define WEBVIEW_H #include #include #include #include #include #include "findinpagebar.h" class QWebEngineHistoryItem; class WebViewBackMenu : public QMenu { Q_OBJECT public: WebViewBackMenu(QWidget* parent=nullptr) : QMenu(parent) {} void showEvent(QShowEvent *); }; class WebViewForwardMenu : public QMenu { Q_OBJECT public: WebViewForwardMenu(QWidget* parent=nullptr) : QMenu(parent) {} void showEvent(QShowEvent *); }; class WebView : public QWebEngineView { Q_OBJECT Q_PROPERTY(const QIcon icon READ icon NOTIFY iconChanged) Q_PROPERTY(QString zimId READ zimId NOTIFY zimIdChanged) public: WebView(QWidget *parent = Q_NULLPTR); virtual ~WebView(); bool isWebActionEnabled(QWebEnginePage::WebAction webAction) const; const QIcon &icon() { return m_icon; } const QString &zimId() { return m_currentZimId; } QMenu* getHistoryBackMenu() const; QMenu* getHistoryForwardMenu() const; void saveViewContent(); public slots: void onUrlChanged(const QUrl& url); signals: void iconChanged(const QIcon& icon); void zimIdChanged(const QString& zimId); void headersChanged(const QJsonObject& headers); void navigationRequested(const QString& url, const QString& anchor); protected: virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type); void wheelEvent(QWheelEvent *event); bool event(QEvent *event); bool eventFilter(QObject *src, QEvent *e); void contextMenuEvent(QContextMenuEvent *event); QString m_currentZimId; QIcon m_icon; QString m_linkHovered; private slots: void gotoTriggeredHistoryItemAction(); void onCurrentTitleChanged(); void onHeadersReceived(const QString& headersJSONStr); void onNavigationRequested(const QString& url, const QString& anchor); private: void addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const; void applyCorrectZoomFactor(); QMenu* createStandardContextMenu(); QMenu* createLinkContextMenu(); QJsonObject m_headers; }; #endif // WEBVIEW_H kiwix-desktop-2.4.1/src/zimview.cpp000066400000000000000000000143221473106011000173000ustar00rootroot00000000000000#include "zimview.h" #include "kiwixapp.h" #include #include #include #if defined(QT_TEXTTOSPEECH_LIB) #include "texttospeechbar.h" #endif ZimView::ZimView(TabBar *tabBar, QWidget *parent) : QWidget(parent), mp_tabBar(tabBar), mp_findInPageBar(new FindInPageBar(this)) { mp_webView = new WebView(); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mp_webView); layout->addWidget(mp_findInPageBar); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); setLayout(layout); // now 'mp_webView' has 'this' as the parent QObject mp_findInPageBar->hide(); auto app = KiwixApp::instance(); #if defined(QT_TEXTTOSPEECH_LIB) mp_ttsBar = new TextToSpeechBar(this); layout->addWidget(mp_ttsBar); mp_ttsBar->hide(); connect(mp_webView, &WebView::zimIdChanged, this, &ZimView::setSpeechLocaleByZimId); connect(app->getAction(KiwixApp::ReadArticleAction), &QAction::triggered, this, &ZimView::readArticle); connect(app->getAction(KiwixApp::ReadTextAction), &QAction::triggered, this, &ZimView::readSelectedText); #endif connect(app->getAction(KiwixApp::ZoomInAction), &QAction::triggered, this, [=]() { if (mp_tabBar->currentZimView() != this) return; auto zoomFactor = mp_webView->zoomFactor(); zoomFactor += 0.1; zoomFactor = std::max(std::min(zoomFactor, 5.0), 0.25); mp_webView->setZoomFactor(zoomFactor); auto key = mp_webView->zimId() + "/zoomFactor"; KiwixApp::instance()->getSettingsManager()->setSettings(key, zoomFactor); }); connect(app->getAction(KiwixApp::ZoomOutAction), &QAction::triggered, this, [=]() { if (mp_tabBar->currentZimView() != this) return; auto zoomFactor = mp_webView->zoomFactor(); zoomFactor -= 0.1; zoomFactor = std::max(std::min(zoomFactor, 5.0), 0.25); mp_webView->setZoomFactor(zoomFactor); auto key = mp_webView->zimId() + "/zoomFactor"; KiwixApp::instance()->getSettingsManager()->setSettings(key, zoomFactor); }); connect(app->getAction(KiwixApp::ZoomResetAction), &QAction::triggered, this, [=]() { if (mp_tabBar->currentZimView() != this) return; auto settingsManager = KiwixApp::instance()->getSettingsManager(); mp_webView->setZoomFactor(settingsManager->getZoomFactor()); auto key = mp_webView->zimId() + "/zoomFactor"; settingsManager->deleteSettings(key); }); connect(app->getAction(KiwixApp::SavePageAsAction), &QAction::triggered, this, [=](){ if (mp_tabBar->currentZimView() == this) mp_webView->saveViewContent(); }); connect(KiwixApp::instance()->getSettingsManager(), &SettingsManager::zoomChanged, this, [=]() { auto key = mp_webView->zimId() + "/zoomFactor"; auto zimZoomFactor = KiwixApp::instance()->getSettingsManager()->getSettings(key); if(!zimZoomFactor.toBool()) { mp_webView->setZoomFactor(KiwixApp::instance()->getSettingsManager()->getZoomFactor()); } }); connect(mp_webView->page(), &QWebEnginePage::fullScreenRequested, mp_tabBar, &TabBar::fullScreenRequested); connect(mp_webView, &WebView::titleChanged, mp_tabBar, &TabBar::on_webview_titleChanged); connect(mp_webView, &WebView::iconChanged, this, [=](const QIcon& icon) { mp_tabBar->setIconOf(icon, this); }); connect(mp_webView->page()->action(QWebEnginePage::Back), &QAction::changed, [this]() { emit webActionEnabledChanged(QWebEnginePage::Back, this->mp_webView->isWebActionEnabled(QWebEnginePage::Back)); }); connect(mp_webView->page()->action(QWebEnginePage::Forward), &QAction::changed, [this]() { emit webActionEnabledChanged(QWebEnginePage::Forward, this->mp_webView->isWebActionEnabled(QWebEnginePage::Forward)); }); connect(mp_webView->page(), &QWebEnginePage::linkHovered, this, [=](const QString& url) { if (mp_tabBar->currentIndex() == 0) { return; } if (url.isEmpty()) { QToolTip::hideText(); } else { auto link = url; if (url.startsWith("zim://")) { link = QUrl(url).path(); } /* because we use QWebEnginePage::linkHovered signal, * we can be sure the current tab is a web page * (mp_tabBar->currentWebView() is not nullptr) */ auto pos = mp_tabBar->mapToGlobal(QPoint(-3, mp_tabBar->currentWebView()->height() - mp_tabBar->PdmHeightMM + 2)); QToolTip::showText(pos, link); } }); } void ZimView::openFindInPageBar() { mp_findInPageBar->show(); mp_findInPageBar->getFindLineEdit()->setFocus(); } #if defined(QT_TEXTTOSPEECH_LIB) void ZimView::readArticle() { if (mp_tabBar->currentZimView() != this) return; mp_webView->page()->toPlainText([=](const QString& articleText){ mp_ttsBar->speak(articleText); mp_ttsBar->speechShow(); }); } void ZimView::readSelectedText() { if (mp_tabBar->currentZimView() != this || !mp_webView->page()->hasSelection()) return; mp_ttsBar->speak(mp_webView->page()->selectedText()); mp_ttsBar->speechShow(); } void ZimView::setSpeechLocaleByZimId(const QString& zimId) { try { const auto book = KiwixApp::instance()->getLibrary()->getBookById(zimId); const auto iso3 = QString::fromStdString(book.getLanguages().at(0)); const auto iso2 = iso3.chopped(1); /* Try both 3 letter and 2 letter name. */ const auto iso2Locale = QLocale(iso2); const bool isValidISO2 = iso2Locale.language() != QLocale::C; mp_ttsBar->setLocale(isValidISO2 ? iso2Locale : QLocale(iso3)); } catch (...) { /* Blank */ } } #endif kiwix-desktop-2.4.1/src/zimview.h000066400000000000000000000017671473106011000167560ustar00rootroot00000000000000#ifndef ZIMVIEW_H #define ZIMVIEW_H #include #include class FindInPageBar; class TabBar; class WebView; #if defined(QT_TEXTTOSPEECH_LIB) class TextToSpeechBar; #endif class ZimView : public QWidget { Q_OBJECT public: explicit ZimView(TabBar* tabBar, QWidget *parent = nullptr); WebView *getWebView() { return mp_webView; } FindInPageBar *getFindInPageBar() { return mp_findInPageBar; } #if defined(QT_TEXTTOSPEECH_LIB) TextToSpeechBar *getTextToSpeechBar() { return mp_ttsBar; } #endif void openFindInPageBar(); public slots: #if defined(QT_TEXTTOSPEECH_LIB) void readArticle(); void readSelectedText(); void setSpeechLocaleByZimId(const QString& zimId); #endif signals: void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled); private: WebView *mp_webView; TabBar *mp_tabBar; FindInPageBar *mp_findInPageBar; #if defined(QT_TEXTTOSPEECH_LIB) TextToSpeechBar *mp_ttsBar; #endif }; #endif // ZIMVIEW_H kiwix-desktop-2.4.1/subprojects/000077500000000000000000000000001473106011000166545ustar00rootroot00000000000000kiwix-desktop-2.4.1/subprojects/QtSingleApplication/000077500000000000000000000000001473106011000225665ustar00rootroot00000000000000kiwix-desktop-2.4.1/subprojects/QtSingleApplication/common.pri000066400000000000000000000012471473106011000245760ustar00rootroot00000000000000exists(config.pri):infile(config.pri, SOLUTIONS_LIBRARY, yes): CONFIG += qtsingleapplication-uselib TEMPLATE += fakelib greaterThan(QT_MAJOR_VERSION, 5)|\ if(equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4))|\ if(equals(QT_MAJOR_VERSION, 5):equals(QT_MINOR_VERSION, 4):greaterThan(QT_PATCH_VERSION, 1)) { QTSINGLEAPPLICATION_LIBNAME = $$qt5LibraryTarget(QtSolutions_SingleApplication-head) } else { QTSINGLEAPPLICATION_LIBNAME = $$qtLibraryTarget(QtSolutions_SingleApplication-head) } TEMPLATE -= fakelib QTSINGLEAPPLICATION_LIBDIR = $$PWD/lib unix:qtsingleapplication-uselib:!qtsingleapplication-buildlib:QMAKE_RPATHDIR += $$QTSINGLEAPPLICATION_LIBDIR kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/000077500000000000000000000000001473106011000233555ustar00rootroot00000000000000kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/QtLockedFile000066400000000000000000000000321473106011000256010ustar00rootroot00000000000000#include "qtlockedfile.h" kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/QtSingleApplication000066400000000000000000000000411473106011000272050ustar00rootroot00000000000000#include "qtsingleapplication.h" kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlocalpeer.cpp000066400000000000000000000157601473106011000264050ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtlocalpeer.h" #include #include #include #include #if defined(Q_OS_WIN) #include #include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif #if defined(Q_OS_UNIX) #include #include #include #endif namespace QtLP_Private { #include "qtlockedfile.cpp" #if defined(Q_OS_WIN) #include "qtlockedfile_win.cpp" #else #include "qtlockedfile_unix.cpp" #endif } const char* QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) : QObject(parent), id(appId) { QString prefix = id; if (id.isEmpty()) { id = QCoreApplication::applicationFilePath(); #if defined(Q_OS_WIN) id = id.toLower(); #endif prefix = id.section(u'/', -1); } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) prefix.remove(QRegExp("[^a-zA-Z]")); #else prefix.remove(QRegularExpression("[^a-zA-Z]")); #endif prefix.truncate(6); QByteArray idc = id.toUtf8(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) quint16 idNum = qChecksum(idc.constData(), idc.size()); #else QByteArrayView v = QByteArrayView(idc); quint16 idNum = qChecksum(v); #endif socketName = QLatin1String("qtsingleapp-") + prefix + u'-' + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { QLibrary lib("kernel32"); pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); } if (pProcessIdToSessionId) { DWORD sessionId = 0; pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); socketName += QLatin1Char('-') + QString::number(sessionId, 16); } #else socketName += u'-' + QString::number(::getuid(), 16); #endif server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + u'/' + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); } bool QtLocalPeer::isClient() { if (lockFile.isLocked()) return false; if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) return true; bool res = server->listen(socketName); #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) // ### Workaround if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { QFile::remove(QDir::cleanPath(QDir::tempPath())+u'/'+socketName); res = server->listen(socketName); } #endif if (!res) qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); return false; } bool QtLocalPeer::sendMessage(const QString &message, int timeout) { if (!isClient()) return false; QLocalSocket socket; bool connOk = false; for(int i = 0; i < 2; i++) { // Try twice, in case the other instance is just starting up socket.connectToServer(socketName); connOk = socket.waitForConnected(timeout/2); if (connOk || i) break; int ms = 250; #if defined(Q_OS_WIN) Sleep(DWORD(ms)); #else struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; nanosleep(&ts, NULL); #endif } if (!connOk) return false; QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); if (res) { res &= socket.waitForReadyRead(timeout); // wait for ack if (res) res &= (socket.read(qstrlen(ack)) == ack); } return res; } void QtLocalPeer::receiveConnection() { QLocalSocket* socket = server->nextPendingConnection(); if (!socket) return; while (true) { if (socket->state() == QLocalSocket::UnconnectedState) { qWarning("QtLocalPeer: Peer disconnected"); delete socket; return; } if (socket->bytesAvailable() >= qint64(sizeof(quint32))) break; socket->waitForReadyRead(); } QDataStream ds(socket); QByteArray uMsg; quint32 remaining; ds >> remaining; uMsg.resize(remaining); int got = 0; char* uMsgBuf = uMsg.data(); do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); if (got < 0) { qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); delete socket; return; } QString message(QString::fromUtf8(uMsg)); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); socket->waitForDisconnected(1000); // make sure client reads ack delete socket; emit messageReceived(message); //### (might take a long time to return) } kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlocalpeer.h000066400000000000000000000052051473106011000260430ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTLOCALPEER_H #define QTLOCALPEER_H #include #include #include #include "qtlockedfile.h" class QtLocalPeer : public QObject { Q_OBJECT public: QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); bool sendMessage(const QString &message, int timeout); QString applicationId() const { return id; } Q_SIGNALS: void messageReceived(const QString &message); protected Q_SLOTS: void receiveConnection(); protected: QString id; QString socketName; QLocalServer* server; QtLP_Private::QtLockedFile lockFile; private: static const char* ack; }; #endif // QTLOCALPEER_H kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlockedfile.cpp000066400000000000000000000137421473106011000265360ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtlockedfile.h" /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. \value ReadLock A read lock. \value WriteLock A write lock. \value NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Opens the file in OpenMode \a mode. This is identical to QFile::open(), with the one exception that the Truncate mode flag is disallowed. Truncation would conflict with the advisory file locking, since the file would be modified before the write lock is obtained. If truncation is required, use resize(0) after obtaining the write lock. Returns true if successful; otherwise false. \sa QFile::open(), QFile::resize() */ bool QtLockedFile::open(OpenMode mode) { if (mode & QIODevice::Truncate) { qWarning("QtLockedFile::open(): Truncate mode not allowed."); return false; } return QFile::open(mode); } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. The file must be opened before it can be locked. If \a block is true, this function will block until the lock is aquired. If \a block is false, this function returns \e false immediately if the lock cannot be aquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */ kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlockedfile.h000066400000000000000000000063071473106011000262020ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTLOCKEDFILE_H #define QTLOCKEDFILE_H #include #ifdef Q_OS_WIN #include #endif #if defined(Q_OS_WIN) # if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) # define QT_QTLOCKEDFILE_EXPORT # elif defined(QT_QTLOCKEDFILE_IMPORT) # if defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # endif # define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) # elif defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) # endif #else # define QT_QTLOCKEDFILE_EXPORT #endif namespace QtLP_Private { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: enum LockMode { NoLock = 0, ReadLock, WriteLock }; QtLockedFile(); QtLockedFile(const QString &name); ~QtLockedFile(); bool open(OpenMode mode); bool lock(LockMode mode, bool block = true); bool unlock(); bool isLocked() const; LockMode lockMode() const; private: #ifdef Q_OS_WIN Qt::HANDLE wmutex; Qt::HANDLE rmutex; QVector rmutexes; QString mutexname; Qt::HANDLE getMutexHandle(int idx, bool doCreate); bool waitMutex(Qt::HANDLE mutex, bool doBlock); #endif LockMode m_lock_mode; }; } #endif kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlockedfile_unix.cpp000066400000000000000000000066141473106011000276010ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "qtlockedfile.h" bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; int cmd = block ? F_SETLKW : F_SETLK; int ret = fcntl(handle(), cmd, &fl); if (ret == -1) { if (errno != EINTR && errno != EAGAIN) qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; int ret = fcntl(handle(), F_SETLKW, &fl); if (ret == -1) { qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = NoLock; return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); } kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtlockedfile_win.cpp000066400000000000000000000146611473106011000274140ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtlockedfile.h" #include #include #define MUTEX_PREFIX "QtLockedFile mutex " // Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS #define MAX_READERS MAXIMUM_WAIT_OBJECTS #if QT_VERSION >= 0x050000 #define QT_WA(unicode, ansi) unicode #endif Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) { if (mutexname.isEmpty()) { QFileInfo fi(*this); mutexname = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower(); } QString mname(mutexname); if (idx >= 0) mname += QString::number(idx); Qt::HANDLE mutex; if (doCreate) { QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); if (!mutex) { qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); return 0; } } else { QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); if (!mutex) { if (GetLastError() != ERROR_FILE_NOT_FOUND) qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); return 0; } } return mutex; } bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock) { Q_ASSERT(mutex); DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0); switch (res) { case WAIT_OBJECT_0: case WAIT_ABANDONED: return true; break; case WAIT_TIMEOUT: break; default: qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed"); } return false; } bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); if (!wmutex && !(wmutex = getMutexHandle(-1, true))) return false; if (!waitMutex(wmutex, block)) return false; if (mode == ReadLock) { int idx = 0; for (; idx < MAX_READERS; idx++) { rmutex = getMutexHandle(idx, false); if (!rmutex || waitMutex(rmutex, false)) break; CloseHandle(rmutex); } bool ok = true; if (idx >= MAX_READERS) { qWarning("QtLockedFile::lock(): too many readers"); rmutex = 0; ok = false; } else if (!rmutex) { rmutex = getMutexHandle(idx, true); if (!rmutex || !waitMutex(rmutex, false)) ok = false; } if (!ok && rmutex) { CloseHandle(rmutex); rmutex = 0; } ReleaseMutex(wmutex); if (!ok) return false; } else { Q_ASSERT(rmutexes.isEmpty()); for (int i = 0; i < MAX_READERS; i++) { Qt::HANDLE mutex = getMutexHandle(i, false); if (mutex) rmutexes.append(mutex); } if (rmutexes.size()) { DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), TRUE, block ? INFINITE : 0); if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) { if (res != WAIT_TIMEOUT) qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed"); m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky unlock(); return false; } } } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; if (m_lock_mode == ReadLock) { ReleaseMutex(rmutex); CloseHandle(rmutex); rmutex = 0; } else { foreach(Qt::HANDLE mutex, rmutexes) { ReleaseMutex(mutex); CloseHandle(mutex); } rmutexes.clear(); ReleaseMutex(wmutex); } m_lock_mode = QtLockedFile::NoLock; return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); if (wmutex) CloseHandle(wmutex); } kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsingleapplication.cpp000066400000000000000000000270101473106011000301330ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtsingleapplication.h" #include "qtlocalpeer.h" #include /*! \class QtSingleApplication qtsingleapplication.h \brief The QtSingleApplication class provides an API to detect and communicate with running instances of an application. This class allows you to create applications where only one instance should be running at a time. I.e., if the user tries to launch another instance, the already running instance will be activated instead. Another usecase is a client-server system, where the first started instance will assume the role of server, and the later instances will act as clients of that server. By default, the full path of the executable file is used to determine whether two processes are instances of the same application. You can also provide an explicit identifier string that will be compared instead. The application should create the QtSingleApplication object early in the startup phase, and call isRunning() to find out if another instance of this application is already running. If isRunning() returns false, it means that no other instance is running, and this instance has assumed the role as the running instance. In this case, the application should continue with the initialization of the application user interface before entering the event loop with exec(), as normal. The messageReceived() signal will be emitted when the running application receives messages from another instance of the same application. When a message is received it might be helpful to the user to raise the application so that it becomes visible. To facilitate this, QtSingleApplication provides the setActivationWindow() function and the activateWindow() slot. If isRunning() returns true, another instance is already running. It may be alerted to the fact that another instance has started by using the sendMessage() function. Also data such as startup parameters (e.g. the name of the file the user wanted this new instance to open) can be passed to the running instance with this function. Then, the application should terminate (or enter client mode). If isRunning() returns true, but sendMessage() fails, that is an indication that the running instance is frozen. Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does not make use of all QtSingleApplication's functionality (see the examples for that). \code // Original int main(int argc, char **argv) { QApplication app(argc, argv); MyMainWidget mmw; mmw.show(); return app.exec(); } // Single instance int main(int argc, char **argv) { QtSingleApplication app(argc, argv); if (app.isRunning()) return !app.sendMessage(someDataString); MyMainWidget mmw; app.setActivationWindow(&mmw); mmw.show(); return app.exec(); } \endcode Once this QtSingleApplication instance is destroyed (normally when the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. The next instance to call isRunning() or sendMessage() will assume the role as the new running instance. For console (non-GUI) applications, QtSingleCoreApplication may be used instead of this class, to avoid the dependency on the QtGui library. \sa QtSingleCoreApplication */ void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a GUIenabled are passed on to the QAppliation constructor. If you are creating a console application (i.e. setting \a GUIenabled to false), you may consider using QtSingleCoreApplication instead. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) : QApplication(argc, argv, GUIenabled) { sysInit(); } /*! Creates a QtSingleApplication object with the application identifier \a appId. \a argc and \a argv are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) : QApplication(argc, argv) { sysInit(appId); } #if QT_VERSION < 0x050000 /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a type are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) : QApplication(argc, argv, type) { sysInit(); } # if defined(Q_WS_X11) /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be \a appId. \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(appId); } # endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 /*! Returns true if another instance of this application is running; otherwise false. This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session). \sa sendMessage() */ bool QtSingleApplication::isRunning() { return peer->isClient(); } /*! Tries to send the text \a message to the currently running instance. The QtSingleApplication object in the running instance will emit the messageReceived() signal when it receives the message. This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within \a timeout milliseconds, this function return false. \sa isRunning(), messageReceived() */ bool QtSingleApplication::sendMessage(const QString &message, int timeout) { return peer->sendMessage(message, timeout); } /*! Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application. */ QString QtSingleApplication::id() const { return peer->applicationId(); } /*! Sets the activation window of this application to \a aw. The activation window is the widget that will be activated by activateWindow(). This is typically the application's main window. If \a activateOnMessage is true (the default), the window will be activated automatically every time a message is received, just prior to the messageReceived() signal being emitted. \sa activateWindow(), messageReceived() */ void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) { actWin = aw; if (activateOnMessage) connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); else disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); } /*! Returns the applications activation window if one has been set by calling setActivationWindow(), otherwise returns 0. \sa setActivationWindow() */ QWidget* QtSingleApplication::activationWindow() const { return actWin; } /*! De-minimizes, raises, and activates this application's activation window. This function does nothing if no activation window has been set. This is a convenience function to show the user that this application instance has been activated when he has tried to start another instance. This function should typically be called in response to the messageReceived() signal. By default, that will happen automatically, if an activation window has been set. \sa setActivationWindow(), messageReceived(), initialize() */ void QtSingleApplication::activateWindow() { if (actWin) { actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); } } /*! \fn void QtSingleApplication::messageReceived(const QString& message) This signal is emitted when the current instance receives a \a message from another instance of this application. \sa sendMessage(), setActivationWindow(), activateWindow() */ /*! \fn void QtSingleApplication::initialize(bool dummy = true) \obsolete */ kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsingleapplication.h000066400000000000000000000076171473106011000276130ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTSINGLEAPPLICATION_H #define QTSINGLEAPPLICATION_H #include class QtLocalPeer; #if defined(Q_OS_WIN) # if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) # define QT_QTSINGLEAPPLICATION_EXPORT # elif defined(QT_QTSINGLEAPPLICATION_IMPORT) # if defined(QT_QTSINGLEAPPLICATION_EXPORT) # undef QT_QTSINGLEAPPLICATION_EXPORT # endif # define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) # elif defined(QT_QTSINGLEAPPLICATION_EXPORT) # undef QT_QTSINGLEAPPLICATION_EXPORT # define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) # endif #else # define QT_QTSINGLEAPPLICATION_EXPORT #endif class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication { Q_OBJECT public: QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); QtSingleApplication(const QString &id, int &argc, char **argv); #if QT_VERSION < 0x050000 QtSingleApplication(int &argc, char **argv, Type type); # if defined(Q_WS_X11) QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); # endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 bool isRunning(); QString id() const; void setActivationWindow(QWidget* aw, bool activateOnMessage = true); QWidget* activationWindow() const; // Obsolete: void initialize(bool dummy = true) { isRunning(); Q_UNUSED(dummy) } public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message); private: void sysInit(const QString &appId = QString()); QtLocalPeer *peer; QWidget *actWin; }; #endif // QTSINGLEAPPLICATION_H kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsingleapplication.pri000066400000000000000000000011101473106011000301340ustar00rootroot00000000000000include(../common.pri) INCLUDEPATH += $$PWD DEPENDPATH += $$PWD QT *= network greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets qtsingleapplication-uselib:!qtsingleapplication-buildlib { LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME } else { SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h } win32 { contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT } kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsinglecoreapplication.cpp000066400000000000000000000123551473106011000310120ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtsinglecoreapplication.h" #include "qtlocalpeer.h" /*! \class QtSingleCoreApplication qtsinglecoreapplication.h \brief A variant of the QtSingleApplication class for non-GUI applications. This class is a variant of QtSingleApplication suited for use in console (non-GUI) applications. It is an extension of QCoreApplication (instead of QApplication). It does not require the QtGui library. The API and usage is identical to QtSingleApplication, except that functions relating to the "activation window" are not present, for obvious reasons. Please refer to the QtSingleApplication documentation for explanation of the usage. A QtSingleCoreApplication instance can communicate to a QtSingleApplication instance if they share the same application id. Hence, this class can be used to create a light-weight command-line tool that sends commands to a GUI application. \sa QtSingleApplication */ /*! Creates a QtSingleCoreApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc and \a argv are passed on to the QCoreAppliation constructor. */ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) : QCoreApplication(argc, argv) { peer = new QtLocalPeer(this); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Creates a QtSingleCoreApplication object with the application identifier \a appId. \a argc and \a argv are passed on to the QCoreAppliation constructor. */ QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv) : QCoreApplication(argc, argv) { peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Returns true if another instance of this application is running; otherwise false. This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session). \sa sendMessage() */ bool QtSingleCoreApplication::isRunning() { return peer->isClient(); } /*! Tries to send the text \a message to the currently running instance. The QtSingleCoreApplication object in the running instance will emit the messageReceived() signal when it receives the message. This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within \a timeout milliseconds, this function return false. \sa isRunning(), messageReceived() */ bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) { return peer->sendMessage(message, timeout); } /*! Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application. */ QString QtSingleCoreApplication::id() const { return peer->applicationId(); } /*! \fn void QtSingleCoreApplication::messageReceived(const QString& message) This signal is emitted when the current instance receives a \a message from another instance of this application. \sa sendMessage() */ kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsinglecoreapplication.h000066400000000000000000000050251473106011000304530ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTSINGLECOREAPPLICATION_H #define QTSINGLECOREAPPLICATION_H #include class QtLocalPeer; class QtSingleCoreApplication : public QCoreApplication { Q_OBJECT public: QtSingleCoreApplication(int &argc, char **argv); QtSingleCoreApplication(const QString &id, int &argc, char **argv); bool isRunning(); QString id() const; public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); Q_SIGNALS: void messageReceived(const QString &message); private: QtLocalPeer* peer; }; #endif // QTSINGLECOREAPPLICATION_H kiwix-desktop-2.4.1/subprojects/QtSingleApplication/src/qtsinglecoreapplication.pri000066400000000000000000000005041473106011000310130ustar00rootroot00000000000000INCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp QT *= network win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport) } kiwix-desktop-2.4.1/ui/000077500000000000000000000000001473106011000147265ustar00rootroot00000000000000kiwix-desktop-2.4.1/ui/about.ui000066400000000000000000000041571473106011000164060ustar00rootroot00000000000000 AboutDialog 0 0 850 650 1 1 About false true 0 0 0 0 0 0 0 QFrame::NoFrame Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse qrc:/texts/about.html true kiwix-desktop-2.4.1/ui/kiwixchoicebox.ui000066400000000000000000000054531473106011000203130ustar00rootroot00000000000000 kiwixchoicebox 0 0 268 54 0 0 0 0 Form 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 TextLabel 50 16777215 Clear 0 0 250 0 Qt::Vertical QSizePolicy::Expanding 20 5 kiwix-desktop-2.4.1/ui/kiwixmessagebox.ui000066400000000000000000000127651473106011000205110ustar00rootroot00000000000000 kiwixmessagebox 0 0 368 166 0 0 474 16777215 Dialog Qt::Horizontal QSizePolicy::Expanding 250 20 0 0 100 0 PointingHandCursor Yes true 0 0 100 0 PointingHandCursor Ok true 0 0 100 0 PointingHandCursor No true 0 0 600 16777215 Would you like to confirm doing xyz? 0 0 Confirm title Qt::Horizontal 40 20 0 0 20 16777215 PointingHandCursor :/icons/close.svg:/icons/close.svg kiwix-desktop-2.4.1/ui/localkiwixserver.ui000066400000000000000000000134041473106011000206640ustar00rootroot00000000000000 LocalKiwixServer 0 0 594 271 0 0 0 0 Local Kiwix Server Settings - Kiwix false true QLayout::SetFixedSize 12 75 true Local Kiwix Server 11 75 true PointingHandCursor Close true Qt::Horizontal 40 20 11 75 true PointingHandCursor false Start Kiwix Server false true 0 0 50 50 0 0 0 0 0 true 11 75 true PointingHandCursor Open in browser true 0 0 450 0 12 TextLabel true kiwix-desktop-2.4.1/ui/mainwindow.ui000066400000000000000000000137161473106011000174510ustar00rootroot00000000000000 MainWindow 0 0 968 576 Kiwix true QMainWindow::AnimatedDocks true 0 0 0 0 0 0 0 40 40 24 24 40 40 :/icons/new-tab-icon.svg:/icons/new-tab-icon.svg 16 16 40 40 24 24 true 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 background-color: rgb(255, 255, 255); false false TopToolBarArea false TopWidget QToolBar
src/topwidget.h
TabBar QWidget
src/tabbar.h
1
ContentManagerSide QWidget
src/contentmanagerside.h
1
ReadingListBar QWidget
src/readinglistbar.h
1
TableOfContentBar QWidget
src/tableofcontentbar.h
1
kiwix-desktop-2.4.1/ui/settings.ui000066400000000000000000000304361473106011000171330ustar00rootroot00000000000000 Settings 0 0 1029 580 true 0 0 1029 580 Qt::AlignCenter 0 0 1029 580 0 0 600 450 Form 16777215 16777215 0 0 Settings Qt::Horizontal Zoom level: Qt::Horizontal 40 20 false % 30 500 10 100 QFrame::Plain Qt::Horizontal Download directory: Qt::Horizontal 40 20 Qt::Horizontal 40 20 true true Reset true true true Browse true Qt::Horizontal TextLabel ? Qt::AutoText Qt::AlignCenter -5 Qt::Horizontal 40 20 TextLabel Qt::Horizontal 40 20 Reset Browse Qt::Horizontal 0 Move deleted files to trash Qt::Horizontal 40 20 true Qt::Horizontal 0 0 Re-open closed tabs Qt::Horizontal 40 20 Qt::Vertical 20 40