Repository: jh0ker/mau_mau_bot Branch: master Commit: 33e195a0963e Files: 70 Total size: 445.8 KB Directory structure: gitextract_qwkuwrf5/ ├── .github/ │ └── workflows/ │ └── docker-publish.yml ├── .gitignore ├── AUTHORS.md ├── Dockerfile ├── LICENSE ├── Pipfile ├── README.md ├── TRANSLATORS.md ├── actions.py ├── bot.py ├── card.py ├── chart/ │ ├── .helmignore │ ├── Chart.yaml │ ├── templates/ │ │ └── common.yaml │ └── values.yaml ├── commandlist.txt ├── config.json.example ├── config.py ├── database.py ├── deck.py ├── docker-compose.yml ├── errors.py ├── game.py ├── game_manager.py ├── genpot.sh ├── images/ │ ├── api_auth.json.sample │ ├── build_classic_colorblind_deck.py │ ├── classic/ │ │ └── source.txt │ ├── colorblind_overlay/ │ │ └── colorblind_overlay.ai │ ├── options/ │ │ └── xcf/ │ │ ├── bluff.xcf │ │ ├── draw.xcf │ │ ├── info.xcf │ │ └── pass.xcf │ ├── sticker_config.json.sample │ └── sticker_uploader.py ├── internationalization.py ├── locales/ │ ├── __init__.py │ ├── available.py │ ├── ca_CA/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── compile.sh │ ├── de_DE/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── es_ES/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── hn_IN/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── id_ID/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── it_IT/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── ml_IN/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── pt_BR/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── ru_RU/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── tr_TR/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── unobot.pot │ ├── uz_UZ/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── vi_VN/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── zh_CN/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ ├── zh_HK/ │ │ └── LC_MESSAGES/ │ │ └── unobot.po │ └── zh_TW/ │ └── LC_MESSAGES/ │ └── unobot.po ├── mwt.py ├── player.py ├── promotions.py ├── renovate.json ├── requirements.txt ├── results.py ├── settings.py ├── shared_vars.py ├── simple_commands.py ├── start_bot.py ├── test/ │ ├── __init__.py │ ├── test_game_manager.py │ └── test_player.py ├── user_setting.py └── utils.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/docker-publish.yml ================================================ name: Docker build on: push: branches: - master workflow_dispatch: jobs: build: name: "Build and push the container" permissions: contents: read packages: write # This is used to complete the identity challenge # with sigstore/fulcio when running outside of PRs. id-token: write uses: JuniorJPDJ/containers/.github/workflows/docker-parallel-multiarch-build.yml@master with: title: mau_mau_bot platforms: 'linux/amd64,linux/386,linux/arm/v7,linux/arm64' buildkit-mount-caches: '{"home-cache": "/root/.cache", "home-cargo": "/root/.cargo"}' buildkit-mount-cache-ids-append-platform: true registry: ghcr.io registry-username: ${{ github.actor }} image-name: ${{ github.repository }} secrets: registry-password: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ # Config file config.json # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg venv/ # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover .hypothesis/ # Translations *.mo # *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ #Ipython Notebook .ipynb_checkpoints # PyCharm .idea # Helm resources chart/charts # Database file uno.sqlite3 data/ images/api_auth.json images/sticker_config.json images/sticker_uploader.session ================================================ FILE: AUTHORS.md ================================================ # Credits `mau_mau_bot` is written and maintained by [Jannes Höke](https://github.com/jh0ker) ## Contributors The following wonderful people contributed directly or indirectly to this project: - [divadsn](https://github.com/divadsn) - [imlonghao](https://github.com/imlonghao) - [Iuri Guilherme](https://github.com/iuriguilherme) - [JuniorJPDJ](https://github.com/JuniorJPDJ) - [pan93412](https://github.com/pan93412) - [qubitnerd](https://github.com/qubitnerd) - [SYHGroup](https://github.com/SYHGroup) Please add yourself here alphabetically when you submit your first pull request. ================================================ FILE: Dockerfile ================================================ FROM python:3.11.13-alpine@sha256:8068890a42d68ece5b62455ef327253249b5f094dcdee57f492635a40217f6a3 # renovate: datasource=repology depName=alpine_3_22/gettext versioning=loose ARG GETTEXT_VERSION="0.24.1-r0" WORKDIR /app ADD requirements.txt . RUN --mount=type=cache,sharing=locked,target=/root/.cache,id=home-cache-$TARGETPLATFORM \ apk add --no-cache \ gettext=${GETTEXT_VERSION} \ && \ pip install -r requirements.txt && \ chown -R nobody:nogroup /app COPY --chown=nobody:nogroup . . USER nobody RUN cd locales && \ find . -maxdepth 2 -type d -name 'LC_MESSAGES' -exec ash -c 'msgfmt {}/unobot.po -o {}/unobot.mo' \; VOLUME /app/data ENV UNO_DB=/app/data/uno.sqlite3 ENTRYPOINT [ "python", "bot.py" ] ================================================ FILE: LICENSE ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 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 Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are 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. 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. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. 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 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 work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. 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 AGPL, see . ================================================ FILE: Pipfile ================================================ [[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] telethon = "*" [packages] python-telegram-bot = "==13.15" pony = "*" [requires] python_version = "3.11" ================================================ FILE: README.md ================================================ # UNO Bot [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](./LICENSE) Telegram Bot that allows you to play the popular card game UNO via inline queries. The bot currently runs as [@unobot](http://telegram.me/unobot). To run the bot yourself, you will need: - Python (tested with 3.4+) - The [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) module - [Pony ORM](https://ponyorm.com/) ## Setup - Get a bot token from [@BotFather](http://telegram.me/BotFather) and change configurations in `config.json`. - Convert all language files from `.po` files to `.mo` by executing the bash script `compile.sh` located in the `locales` folder. Another option is: `find . -maxdepth 2 -type d -name 'LC_MESSAGES' -exec bash -c 'msgfmt {}/unobot.po -o {}/unobot.mo' \;`. - Use `/setinline` and `/setinlinefeedback` with BotFather for your bot. - Use `/setcommands` and submit the list of commands in commandlist.txt - Install requirements (using a `virtualenv` is recommended): `pip install -r requirements.txt` You can change some gameplay parameters like turn times, minimum amount of players and default gamemode in `config.json`. Current gamemodes available: classic, fast and wild. Check the details with the `/modes` command. Then run the bot with `python3 bot.py`. Code documentation is minimal but there. ================================================ FILE: TRANSLATORS.md ================================================ # Translators The following awesome people contributed to this project by translating it: | Locale | Translators | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | ca_CA | [retiolus](https://github.com/retiolus) | | de_DE | [Jannes Höke](https://github.com/jh0ker) | | es_ES | [José.A Rojo](https://github.com/J4RV), [Ricardo Valverde Hernández](https://telegram.me/rivh1), Victor, Yuga | | id_ID | [Erwin Guo](https://www.facebook.com/erwinfransiscus) | | it_IT | Carola Mariano, ɳick | | ml_IN | [Adhith T](https://github.com/adhitht123) | | pt_BR | [Iuri Guilherme](https://github.com/iuriguilherme), [João Rodrigo Couto de Oliveira](http://twitter.com/JoaoRodrigoJR) | | uz_UZ | [Shohrux V](https://www.instagram.com/shohrux.v/) | | vi_VN | [Lê Minh Sơn](https://github.com/leminhson06) | | zh_CN | [imlonghao](https://github.com/imlonghao), [XhyEax](https://github.com/XhyEax) | | zh_HK | [Jed Cheng](https://www.facebook.com/profile.php?id=100002258388821) | | zh_TW | [Eugene Lam](https://www.facebook.com/eugenelam1118), [jimchen5209](https://www.youtube.com/user/jimchen5209), [pan93412](https://www.github.com/pan93412) | Please add yourself here alphabetically when you submit your first translation. ================================================ FILE: actions.py ================================================ import random import logging import card as c from datetime import datetime from telegram import Message, Chat from telegram.ext import CallbackContext from apscheduler.jobstores.base import JobLookupError from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME from errors import DeckEmptyError, NotEnoughPlayersError from internationalization import __, _ from shared_vars import gm from user_setting import UserSetting from utils import send_async, display_name, game_is_running logger = logging.getLogger(__name__) class Countdown(object): player = None job_queue = None def __init__(self, player, job_queue): self.player = player self.job_queue = job_queue # TODO do_skip() could get executed in another thread (it can be a job), so it looks like it can't use game.translate? def do_skip(bot, player, job_queue=None): game = player.game chat = game.chat skipped_player = game.current_player next_player = game.current_player.next if skipped_player.waiting_time > 0: skipped_player.anti_cheat += 1 skipped_player.waiting_time -= TIME_REMOVAL_AFTER_SKIP if (skipped_player.waiting_time < 0): skipped_player.waiting_time = 0 try: skipped_player.draw() except DeckEmptyError: pass n = skipped_player.waiting_time send_async(bot, chat.id, text=__("Waiting time to skip this player has " "been reduced to {time} seconds.\n" "Next player: {name}", multi=game.translate) .format(time=n, name=display_name(next_player.user)) ) logger.info("{player} was skipped! " .format(player=display_name(player.user))) game.turn() if job_queue: start_player_countdown(bot, game, job_queue) else: try: gm.leave_game(skipped_player.user, chat) send_async(bot, chat.id, text=__("{name1} ran out of time " "and has been removed from the game!\n" "Next player: {name2}", multi=game.translate) .format(name1=display_name(skipped_player.user), name2=display_name(next_player.user))) logger.info("{player} was skipped! " .format(player=display_name(player.user))) if job_queue: start_player_countdown(bot, game, job_queue) except NotEnoughPlayersError: send_async(bot, chat.id, text=__("{name} ran out of time " "and has been removed from the game!\n" "The game ended.", multi=game.translate) .format(name=display_name(skipped_player.user))) gm.end_game(chat, skipped_player.user) def do_play_card(bot, player, result_id): """Plays the selected card and sends an update to the group if needed""" card = c.from_str(result_id) player.play(card) game = player.game chat = game.chat user = player.user us = UserSetting.get(id=user.id) if not us: us = UserSetting(id=user.id) if us.stats: us.cards_played += 1 if game.choosing_color: send_async(bot, chat.id, text=__("Please choose a color", multi=game.translate)) if len(player.cards) == 1: send_async(bot, chat.id, text="UNO!") if len(player.cards) == 0: send_async(bot, chat.id, text=__("{name} won!", multi=game.translate) .format(name=user.first_name)) if us.stats: us.games_played += 1 if game.players_won == 0: us.first_places += 1 game.players_won += 1 try: gm.leave_game(user, chat) except NotEnoughPlayersError: send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) us2 = UserSetting.get(id=game.current_player.user.id) if us2 and us2.stats: us2.games_played += 1 gm.end_game(chat, user) def do_draw(bot, player): """Does the drawing""" game = player.game draw_counter_before = game.draw_counter try: player.draw() except DeckEmptyError: send_async(bot, player.game.chat.id, text=__("There are no more cards in the deck.", multi=game.translate)) if (game.last_card.value == c.DRAW_TWO or game.last_card.special == c.DRAW_FOUR) and \ draw_counter_before > 0: game.turn() def do_call_bluff(bot, player): """Handles the bluff calling""" game = player.game chat = game.chat if player.prev.bluffing: send_async(bot, chat.id, text=__("Bluff called! Giving 4 cards to {name}", multi=game.translate) .format(name=player.prev.user.first_name)) try: player.prev.draw() except DeckEmptyError: send_async(bot, player.game.chat.id, text=__("There are no more cards in the deck.", multi=game.translate)) else: game.draw_counter += 2 send_async(bot, chat.id, text=__("{name1} didn't bluff! Giving 6 cards to {name2}", multi=game.translate) .format(name1=player.prev.user.first_name, name2=player.user.first_name)) try: player.draw() except DeckEmptyError: send_async(bot, player.game.chat.id, text=__("There are no more cards in the deck.", multi=game.translate)) game.turn() def start_player_countdown(bot, game, job_queue): player = game.current_player time = player.waiting_time if time < MIN_FAST_TURN_TIME: time = MIN_FAST_TURN_TIME if game.mode == 'fast': if game.job: try: game.job.schedule_removal() except JobLookupError: pass job = job_queue.run_once( #lambda x,y: do_skip(bot, player), skip_job, time, context=Countdown(player, job_queue) ) logger.info("Started countdown for player: {player}. {time} seconds." .format(player=display_name(player.user), time=time)) player.game.job = job def skip_job(context: CallbackContext): player = context.job.context.player game = player.game if game_is_running(game): job_queue = context.job.context.job_queue do_skip(context.bot, player, job_queue) ================================================ FILE: bot.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging from datetime import datetime from telegram import ParseMode, InlineKeyboardMarkup, \ InlineKeyboardButton, Update from telegram.ext import InlineQueryHandler, ChosenInlineResultHandler, \ CommandHandler, MessageHandler, Filters, CallbackQueryHandler, CallbackContext from telegram.ext.dispatcher import run_async import card as c import settings import simple_commands from actions import do_skip, do_play_card, do_draw, do_call_bluff, start_player_countdown from config import WAITING_TIME, DEFAULT_GAMEMODE, MIN_PLAYERS from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError, NotEnoughPlayersError, DeckEmptyError) from internationalization import _, __, user_locale, game_locales from results import (add_call_bluff, add_choose_color, add_draw, add_gameinfo, add_no_game, add_not_started, add_other_cards, add_pass, add_card, add_mode_classic, add_mode_fast, add_mode_wild, add_mode_text) from shared_vars import gm, updater, dispatcher from simple_commands import help_handler from start_bot import start_bot from utils import display_name from utils import send_async, answer_async, error, TIMEOUT, user_is_creator_or_admin, user_is_creator, game_is_running logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO ) logger = logging.getLogger(__name__) logging.getLogger('apscheduler').setLevel(logging.WARNING) @user_locale def notify_me(update: Update, context: CallbackContext): """Handler for /notify_me command, pm people for next game""" chat_id = update.message.chat_id if update.message.chat.type == 'private': send_async(bot, chat_id, text=_("Send this command in a group to be notified " "when a new game is started there.")) else: try: gm.remind_dict[chat_id].add(update.message.from_user.id) except KeyError: gm.remind_dict[chat_id] = {update.message.from_user.id} @user_locale def new_game(update: Update, context: CallbackContext): """Handler for the /new command""" chat_id = update.message.chat_id if update.message.chat.type == 'private': help_handler(update, context) else: if update.message.chat_id in gm.remind_dict: for user in gm.remind_dict[update.message.chat_id]: send_async(context.bot, user, text=_("A new game has been started in {title}").format( title=update.message.chat.title)) del gm.remind_dict[update.message.chat_id] game = gm.new_game(update.message.chat) game.starter = update.message.from_user game.owner.append(update.message.from_user.id) game.mode = DEFAULT_GAMEMODE send_async(context.bot, chat_id, text=_("Created a new game! Join the game with /join " "and start the game with /start")) @user_locale def kill_game(update: Update, context: CallbackContext): """Handler for the /kill command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if update.message.chat.type == 'private': help_handler(update, context) return if not games: send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user_is_creator_or_admin(user, game, context.bot, chat): try: gm.end_game(chat, user) send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) except NoGameInChatError: send_async(context.bot, chat.id, text=_("The game is not started yet. " "Join the game with /join and start the game with /start"), reply_to_message_id=update.message.message_id) else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @user_locale def join_game(update: Update, context: CallbackContext): """Handler for the /join command""" chat = update.message.chat if update.message.chat.type == 'private': help_handler(update, context) return try: gm.join_game(update.message.from_user, chat) except LobbyClosedError: send_async(context.bot, chat.id, text=_("The lobby is closed")) except NoGameInChatError: send_async(context.bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) except AlreadyJoinedError: send_async(context.bot, chat.id, text=_("You already joined the game. Start the game " "with /start"), reply_to_message_id=update.message.message_id) except DeckEmptyError: send_async(context.bot, chat.id, text=_("There are not enough cards left in the deck for " "new players to join."), reply_to_message_id=update.message.message_id) else: send_async(context.bot, chat.id, text=_("Joined the game"), reply_to_message_id=update.message.message_id) @user_locale def leave_game(update: Update, context: CallbackContext): """Handler for the /leave command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if player is None: send_async(context.bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) return game = player.game user = update.message.from_user try: gm.leave_game(user, chat) except NoGameInChatError: send_async(context.bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) except NotEnoughPlayersError: gm.end_game(chat, user) send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) else: if game.started: send_async(context.bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id) else: send_async(context.bot, chat.id, text=__("{name} left the game before it started.", multi=game.translate).format( name=display_name(user)), reply_to_message_id=update.message.message_id) @user_locale def kick_player(update: Update, context: CallbackContext): """Handler for the /kick command""" if update.message.chat.type == 'private': help_handler(update, context) return chat = update.message.chat user = update.message.from_user try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(context.bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) return if not game.started: send_async(context.bot, chat.id, text=_("The game is not started yet. " "Join the game with /join and start the game with /start"), reply_to_message_id=update.message.message_id) return if user_is_creator_or_admin(user, game, context.bot, chat): if update.message.reply_to_message: kicked = update.message.reply_to_message.from_user try: gm.leave_game(kicked, chat) except NoGameInChatError: send_async(context.bot, chat.id, text=_("Player {name} is not found in the current game.".format(name=display_name(kicked))), reply_to_message_id=update.message.message_id) return except NotEnoughPlayersError: gm.end_game(chat, user) send_async(context.bot, chat.id, text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) return send_async(context.bot, chat.id, text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) else: send_async(context.bot, chat.id, text=_("Please reply to the person you want to kick and type /kick again."), reply_to_message_id=update.message.message_id) return send_async(context.bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id) else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) def select_game(update: Update, context: CallbackContext): """Handler for callback queries to select the current game""" chat_id = int(update.callback_query.data) user_id = update.callback_query.from_user.id players = gm.userid_players[user_id] for player in players: if player.game.chat.id == chat_id: gm.userid_current[user_id] = player break else: send_async(bot, update.callback_query.message.chat_id, text=_("Game not found.")) return def selected(): back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] context.bot.answerCallbackQuery(update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) context.bot.editMessageText(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "Make sure that you switch to the correct " "group!").format( group=gm.userid_current[user_id].game.chat.title), reply_markup=InlineKeyboardMarkup(back), parse_mode=ParseMode.HTML, timeout=TIMEOUT) dispatcher.run_async(selected) @game_locales def status_update(update: Update, context: CallbackContext): """Remove player from game if user leaves the group""" chat = update.message.chat if update.message.left_chat_member: user = update.message.left_chat_member try: gm.leave_game(user, chat) game = gm.player_for_user_in_chat(user, chat).game except NoGameInChatError: pass except NotEnoughPlayersError: gm.end_game(chat, user) send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) else: send_async(context.bot, chat.id, text=__("Removing {name} from the game", multi=game.translate) .format(name=display_name(user))) @game_locales @user_locale def start_game(update: Update, context: CallbackContext): """Handler for the /start command""" if update.message.chat.type != 'private': chat = update.message.chat try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(context.bot, chat.id, text=_("There is no game running in this chat. Create " "a new one with /new")) return if game.started: send_async(context.bot, chat.id, text=_("The game has already started")) elif len(game.players) < MIN_PLAYERS: send_async(context.bot, chat.id, text=__("At least {minplayers} players must /join the game " "before you can start it").format(minplayers=MIN_PLAYERS)) else: # Starting a game game.start() for player in game.players: player.draw_first_hand() choice = [[InlineKeyboardButton(text=_("Make your choice!"), switch_inline_query_current_chat='')]] first_message = ( __("First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations", multi=game.translate) .format(name=display_name(game.current_player.user))) def send_first(): """Send the first card and player""" context.bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) context.bot.sendMessage(chat.id, text=first_message, reply_markup=InlineKeyboardMarkup(choice), timeout=TIMEOUT) dispatcher.run_async(send_first) start_player_countdown(context.bot, game, context.job_queue) elif len(context.args) and context.args[0] == 'select': players = gm.userid_players[update.message.from_user.id] groups = list() for player in players: title = player.game.chat.title if player == gm.userid_current[update.message.from_user.id]: title = '- %s -' % player.game.chat.title groups.append( [InlineKeyboardButton(text=title, callback_data=str(player.game.chat.id))] ) send_async(context.bot, update.message.chat_id, text=_('Please select the group you want to play in.'), reply_markup=InlineKeyboardMarkup(groups)) else: help_handler(update, context) @user_locale def close_game(update: Update, context: CallbackContext): """Handler for the /close command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user.id in game.owner: game.open = False send_async(context.bot, chat.id, text=_("Closed the lobby. " "No more players can join this game.")) return else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) return @user_locale def open_game(update: Update, context: CallbackContext): """Handler for the /open command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user.id in game.owner: game.open = True send_async(context.bot, chat.id, text=_("Opened the lobby. " "New players may /join the game.")) return else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) return @user_locale def enable_translations(update: Update, context: CallbackContext): """Handler for the /enable_translations command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user.id in game.owner: game.translate = True send_async(context.bot, chat.id, text=_("Enabled multi-translations. " "Disable with /disable_translations")) return else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) return @user_locale def disable_translations(update: Update, context: CallbackContext): """Handler for the /disable_translations command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user.id in game.owner: game.translate = False send_async(context.bot, chat.id, text=_("Disabled multi-translations. " "Enable them again with " "/enable_translations")) return else: send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) return @game_locales @user_locale def skip_player(update: Update, context: CallbackContext): """Handler for the /skip command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if not player: send_async(context.bot, chat.id, text=_("You are not playing in a game in this chat.")) return game = player.game skipped_player = game.current_player started = skipped_player.turn_started now = datetime.now() delta = (now - started).seconds # You can't skip if the current player still has time left # You can skip yourself even if you have time left (you'll still draw) if delta < skipped_player.waiting_time and player != skipped_player: n = skipped_player.waiting_time - delta send_async(context.bot, chat.id, text=_("Please wait {time} second", "Please wait {time} seconds", n) .format(time=n), reply_to_message_id=update.message.message_id) else: do_skip(context.bot, player) @game_locales @user_locale def reply_to_query(update: Update, context: CallbackContext): """ Handler for inline queries. Builds the result list for inline queries and answers to the client. """ results = list() switch = None try: user = update.inline_query.from_user user_id = user.id players = gm.userid_players[user_id] player = gm.userid_current[user_id] game = player.game except KeyError: add_no_game(results) else: # The game has not started. # The creator may change the game mode, other users just get a "game has not started" message. if not game.started: if user_is_creator(user, game): add_mode_classic(results) add_mode_fast(results) add_mode_wild(results) add_mode_text(results) else: add_not_started(results) elif user_id == game.current_player.user.id: if game.choosing_color: add_choose_color(results, game) add_other_cards(player, results, game) else: if not player.drew: add_draw(player, results) else: add_pass(results, game) if game.last_card.special == c.DRAW_FOUR and game.draw_counter: add_call_bluff(results, game) playable = player.playable_cards() added_ids = list() # Duplicates are not allowed for card in sorted(player.cards): add_card(game, card, results, can_play=(card in playable and str(card) not in added_ids)) added_ids.append(str(card)) add_gameinfo(game, results) elif user_id != game.current_player.user.id or not game.started: for card in sorted(player.cards): add_card(game, card, results, can_play=False) else: add_gameinfo(game, results) for result in results: result.id += ':%d' % player.anti_cheat if players and game and len(players) > 1: switch = _('Current game: {game}').format(game=game.chat.title) answer_async(context.bot, update.inline_query.id, results, cache_time=0, switch_pm_text=switch, switch_pm_parameter='select') @game_locales @user_locale def process_result(update: Update, context: CallbackContext): """ Handler for chosen inline results. Checks the players actions and acts accordingly. """ try: user = update.chosen_inline_result.from_user player = gm.userid_current[user.id] game = player.game result_id = update.chosen_inline_result.result_id chat = game.chat except (KeyError, AttributeError): return logger.debug("Selected result: " + result_id) result_id, anti_cheat = result_id.split(':') last_anti_cheat = player.anti_cheat player.anti_cheat += 1 if result_id in ('hand', 'gameinfo', 'nogame'): return elif result_id.startswith('mode_'): # First 5 characters are 'mode_', the rest is the gamemode. mode = result_id[5:] game.set_mode(mode) logger.info("Gamemode changed to {mode}".format(mode = mode)) send_async(context.bot, chat.id, text=__("Gamemode changed to {mode}".format(mode = mode))) return elif len(result_id) == 36: # UUID result return elif int(anti_cheat) != last_anti_cheat: send_async(context.bot, chat.id, text=__("Cheat attempt by {name}", multi=game.translate) .format(name=display_name(player.user))) return elif result_id == 'call_bluff': reset_waiting_time(context.bot, player) do_call_bluff(context.bot, player) elif result_id == 'draw': reset_waiting_time(context.bot, player) do_draw(context.bot, player) elif result_id == 'pass': game.turn() elif result_id in c.COLORS: game.choose_color(result_id) else: reset_waiting_time(context.bot, player) do_play_card(context.bot, player, result_id) if game_is_running(game): nextplayer_message = ( __("Next player: {name}", multi=game.translate) .format(name=display_name(game.current_player.user))) choice = [[InlineKeyboardButton(text=_("Make your choice!"), switch_inline_query_current_chat='')]] send_async(context.bot, chat.id, text=nextplayer_message, reply_markup=InlineKeyboardMarkup(choice)) start_player_countdown(context.bot, game, context.job_queue) def reset_waiting_time(bot, player): """Resets waiting time for a player and sends a notice to the group""" chat = player.game.chat if player.waiting_time < WAITING_TIME: player.waiting_time = WAITING_TIME send_async(bot, chat.id, text=__("Waiting time for {name} has been reset to {time} " "seconds", multi=player.game.translate) .format(name=display_name(player.user), time=WAITING_TIME)) # Add all handlers to the dispatcher and run the bot dispatcher.add_handler(InlineQueryHandler(reply_to_query)) dispatcher.add_handler(ChosenInlineResultHandler(process_result, pass_job_queue=True)) dispatcher.add_handler(CallbackQueryHandler(select_game)) dispatcher.add_handler(CommandHandler('start', start_game, pass_args=True, pass_job_queue=True)) dispatcher.add_handler(CommandHandler('new', new_game)) dispatcher.add_handler(CommandHandler('kill', kill_game)) dispatcher.add_handler(CommandHandler('join', join_game)) dispatcher.add_handler(CommandHandler('leave', leave_game)) dispatcher.add_handler(CommandHandler('kick', kick_player)) dispatcher.add_handler(CommandHandler('open', open_game)) dispatcher.add_handler(CommandHandler('close', close_game)) dispatcher.add_handler(CommandHandler('enable_translations', enable_translations)) dispatcher.add_handler(CommandHandler('disable_translations', disable_translations)) dispatcher.add_handler(CommandHandler('skip', skip_player)) dispatcher.add_handler(CommandHandler('notify_me', notify_me)) simple_commands.register() settings.register() dispatcher.add_handler(MessageHandler(Filters.status_update, status_update)) dispatcher.add_error_handler(error) start_bot(updater) updater.idle() ================================================ FILE: card.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # Colors RED = 'r' BLUE = 'b' GREEN = 'g' YELLOW = 'y' BLACK = 'x' COLORS = (RED, BLUE, GREEN, YELLOW) COLOR_ICONS = { RED: '❤️', BLUE: '💙', GREEN: '💚', YELLOW: '💛', BLACK: '⬛️' } # Values ZERO = '0' ONE = '1' TWO = '2' THREE = '3' FOUR = '4' FIVE = '5' SIX = '6' SEVEN = '7' EIGHT = '8' NINE = '9' DRAW_TWO = 'draw' REVERSE = 'reverse' SKIP = 'skip' VALUES = (ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, DRAW_TWO, REVERSE, SKIP) WILD_VALUES = (ONE, TWO, THREE, FOUR, FIVE, DRAW_TWO, REVERSE, SKIP) # Special cards CHOOSE = 'colorchooser' DRAW_FOUR = 'draw_four' SPECIALS = (CHOOSE, DRAW_FOUR) CARDS_CLASSIC = { "normal": { "b_0": "BQADBAAD2QEAAl9XmQAB--inQsYcLTsC", "b_1": "BQADBAAD2wEAAl9XmQABBzh4U-rFicEC", "b_2": "BQADBAAD3QEAAl9XmQABo3l6TT0MzKwC", "b_3": "BQADBAAD3wEAAl9XmQAB2y-3TSapRtIC", "b_4": "BQADBAAD4QEAAl9XmQABT6nhOuolqKYC", "b_5": "BQADBAAD4wEAAl9XmQABwRfmekGnpn0C", "b_6": "BQADBAAD5QEAAl9XmQABQITgUsEsqxsC", "b_7": "BQADBAAD5wEAAl9XmQABVhPF6EcfWjEC", "b_8": "BQADBAAD6QEAAl9XmQABP6baig0pIvYC", "b_9": "BQADBAAD6wEAAl9XmQAB0CQdsQs_pXIC", "b_draw": "BQADBAAD7QEAAl9XmQAB00Wii7R3gDUC", "b_skip": "BQADBAAD8QEAAl9XmQAB_RJHYKqlc-wC", "b_reverse": "BQADBAAD7wEAAl9XmQABo7D0B9NUPmYC", "g_0": "BQADBAAD9wEAAl9XmQABb8CaxxsQ-Y8C", "g_1": "BQADBAAD-QEAAl9XmQAB9B6ti_j6UB0C", "g_2": "BQADBAAD-wEAAl9XmQABYpLjOzbRz8EC", "g_3": "BQADBAAD_QEAAl9XmQABKvc2ZCiY-D8C", "g_4": "BQADBAAD_wEAAl9XmQABJB52wzPdHssC", "g_5": "BQADBAADAQIAAl9XmQABp_Ep1I4GA2cC", "g_6": "BQADBAADAwIAAl9XmQABaaMxxa4MihwC", "g_7": "BQADBAADBQIAAl9XmQABv5Q264Crz8gC", "g_8": "BQADBAADBwIAAl9XmQABjMH-X9UHh8sC", "g_9": "BQADBAADCQIAAl9XmQAB26fZ2fW7vM0C", "g_draw": "BQADBAADCwIAAl9XmQAB64jIZrgXrQUC", "g_skip": "BQADBAADDwIAAl9XmQAB17yhhnh46VQC", "g_reverse": "BQADBAADDQIAAl9XmQAB_xcaab0DkegC", "r_0": "BQADBAADEQIAAl9XmQABiUfr1hz-zT8C", "r_1": "BQADBAADEwIAAl9XmQAB5bWfwJGs6Q0C", "r_2": "BQADBAADFQIAAl9XmQABHR4mg9Ifjw0C", "r_3": "BQADBAADFwIAAl9XmQABYBx5O_PG2QIC", "r_4": "BQADBAADGQIAAl9XmQABTQpGrlvet3cC", "r_5": "BQADBAADGwIAAl9XmQABbdLt4gdntBQC", "r_6": "BQADBAADHQIAAl9XmQABqEI274p3lSoC", "r_7": "BQADBAADHwIAAl9XmQABCw8u67Q4EK4C", "r_8": "BQADBAADIQIAAl9XmQAB8iDJmLxp8ogC", "r_9": "BQADBAADIwIAAl9XmQAB_HCAww1kNGYC", "r_draw": "BQADBAADJQIAAl9XmQABuz0OZ4l3k6MC", "r_skip": "BQADBAADKQIAAl9XmQAC2AL5Ok_ULwI", "r_reverse": "BQADBAADJwIAAl9XmQABu2tIeQTpDvUC", "y_0": "BQADBAADKwIAAl9XmQAB_nWoNKe8DOQC", "y_1": "BQADBAADLQIAAl9XmQABVprAGUDKgOQC", "y_2": "BQADBAADLwIAAl9XmQABqyT4_YTm54EC", "y_3": "BQADBAADMQIAAl9XmQABGC-Xxg_N6fIC", "y_4": "BQADBAADMwIAAl9XmQABbc-ZGL8kApAC", "y_5": "BQADBAADNQIAAl9XmQAB67QJZIF6XAcC", "y_6": "BQADBAADNwIAAl9XmQABJg_7XXoITsoC", "y_7": "BQADBAADOQIAAl9XmQABVrd7OcS2k34C", "y_8": "BQADBAADOwIAAl9XmQABRpJSahBWk3EC", "y_9": "BQADBAADPQIAAl9XmQAB9MwJWKLJogYC", "y_draw": "BQADBAADPwIAAl9XmQABaPYK8oYg84cC", "y_skip": "BQADBAADQwIAAl9XmQABO_AZKtxY6IMC", "y_reverse": "BQADBAADQQIAAl9XmQABZdQFahGG6UQC", "draw_four": "BQADBAAD9QEAAl9XmQABVlkSNfhn76cC", "colorchooser": "BQADBAAD8wEAAl9XmQABl9rUOPqx4E4C", }, "not_playable": { "b_0": "BQADBAADRQIAAl9XmQAB1IfkQ5xAiK4C", "b_1": "BQADBAADRwIAAl9XmQABbWvhTeKBii4C", "b_2": "BQADBAADSQIAAl9XmQABS1djHgyQokMC", "b_3": "BQADBAADSwIAAl9XmQABwQ6VTbgY-MIC", "b_4": "BQADBAADTQIAAl9XmQABAlKUYha8YccC", "b_5": "BQADBAADTwIAAl9XmQABMvx8xVDnhUEC", "b_6": "BQADBAADUQIAAl9XmQABDEbhP1Zd31kC", "b_7": "BQADBAADUwIAAl9XmQABXb5XQBBaAnIC", "b_8": "BQADBAADVQIAAl9XmQABgL5HRDLvrjgC", "b_9": "BQADBAADVwIAAl9XmQABtO3XDQWZLtYC", "b_draw": "BQADBAADWQIAAl9XmQAB2kk__6_2IhMC", "b_skip": "BQADBAADXQIAAl9XmQABEGJI6CaH3vcC", "b_reverse": "BQADBAADWwIAAl9XmQAB_kZA6UdHXU8C", "g_0": "BQADBAADYwIAAl9XmQABGD5a9oG7Yg4C", "g_1": "BQADBAADZQIAAl9XmQABqwABZHAXZIg0Ag", "g_2": "BQADBAADZwIAAl9XmQABTI3mrEhojRkC", "g_3": "BQADBAADaQIAAl9XmQABVi3rUyzWS3YC", "g_4": "BQADBAADawIAAl9XmQABZIf5ThaXnpUC", "g_5": "BQADBAADbQIAAl9XmQABNndVJSQCenIC", "g_6": "BQADBAADbwIAAl9XmQABpoy1c4ZkrvwC", "g_7": "BQADBAADcQIAAl9XmQABDeaT5fzxwREC", "g_8": "BQADBAADcwIAAl9XmQABLIQ06ZM5NnAC", "g_9": "BQADBAADdQIAAl9XmQABel-mC7eXGsMC", "g_draw": "BQADBAADdwIAAl9XmQABOHEpxSztCf8C", "g_skip": "BQADBAADewIAAl9XmQABDaQdMxjjPsoC", "g_reverse": "BQADBAADeQIAAl9XmQABek1lGz7SJNAC", "r_0": "BQADBAADfQIAAl9XmQABWrxoiXcsg0EC", "r_1": "BQADBAADfwIAAl9XmQABlav-bkgSgRcC", "r_2": "BQADBAADgQIAAl9XmQABDjZkqfJ4AdAC", "r_3": "BQADBAADgwIAAl9XmQABT7lH7VVcy3MC", "r_4": "BQADBAADhQIAAl9XmQAB1arPC5x0LrwC", "r_5": "BQADBAADhwIAAl9XmQABWvs7xkCDldkC", "r_6": "BQADBAADiQIAAl9XmQABjwABH5ZonWn8Ag", "r_7": "BQADBAADiwIAAl9XmQABjekJfm4fBDIC", "r_8": "BQADBAADjQIAAl9XmQABqFjchpsJeEkC", "r_9": "BQADBAADjwIAAl9XmQAB-sKdcgABdNKDAg", "r_draw": "BQADBAADkQIAAl9XmQABtw9RPVDHZOQC", "r_skip": "BQADBAADlQIAAl9XmQABtG2GixCxtX4C", "r_reverse": "BQADBAADkwIAAl9XmQABz2qyEbabnVsC", "y_0": "BQADBAADlwIAAl9XmQABAb3ZwTGS1lMC", "y_1": "BQADBAADmQIAAl9XmQAB9v5qJk9R0x8C", "y_2": "BQADBAADmwIAAl9XmQABCsgpRHC2g-cC", "y_3": "BQADBAADnQIAAl9XmQAB3kLLXCv-qY0C", "y_4": "BQADBAADnwIAAl9XmQAB7R_y-NexNLIC", "y_5": "BQADBAADoQIAAl9XmQABl-7mwsjD-cMC", "y_6": "BQADBAADowIAAl9XmQABwbVsyv2MfPkC", "y_7": "BQADBAADpQIAAl9XmQABoBqC0JsemVwC", "y_8": "BQADBAADpwIAAl9XmQABpkwAAeh9ldlHAg", "y_9": "BQADBAADqQIAAl9XmQABpSBEUfd4IM8C", "y_draw": "BQADBAADqwIAAl9XmQABMt-2zW0VYb4C", "y_skip": "BQADBAADrwIAAl9XmQABIDf-_TuuxtEC", "y_reverse": "BQADBAADrQIAAl9XmQABm9M0Zh-_UwkC", "draw_four": "BQADBAADYQIAAl9XmQAB_HWlvZIscDEC", "colorchooser": "BQADBAADXwIAAl9XmQABY_ksDdMex-wC", }, } CARDS_CLASSIC_COLORBLIND = { "normal": { "colorchooser": "CAADBAADrg4AAvX2mVEpx_BiDIE5nQI", "draw_four": "CAADBAADYRAAArnkmVGmqXHhjWEBxAI", "r_0": "CAADBAAD6A8AAn_ckVHPWHqiBR_3jAI", "r_1": "CAADBAAD5Q0AAg-ImVEx-blQI88RrQI", "r_2": "CAADBAAD1g0AAuMjmVEkQsVhN49DMAI", "r_3": "CAADBAADlhAAAqy4mVHWovoaWfQG_gI", "r_4": "CAADBAADCRoAAqf_kVFnl8ACL1rjpwI", "r_5": "CAADBAADVw8AAjmamVEEv2TVeL9cpQI", "r_6": "CAADBAADHQ4AAuuUkVH2I-yn6nRBVAI", "r_7": "CAADBAADNQ8AArP1kVF5rqHtk0pQ-AI", "r_8": "CAADBAAD1BAAAuQDkVEPiIodUi6WvwI", "r_9": "CAADBAAD2Q4AAq1nkFHM6z5C0Kff2QI", "r_draw": "CAADBAADvQ8AAqZukFGEmkRSoSZQEwI", "r_reverse": "CAADBAAD5RAAAg89mVE8-EY_2DifcAI", "r_skip": "CAADBAADRg4AAp8bmVFOC6xdEZZRwwI", "g_0": "CAADBAADTg4AAoQxmFF07jR_vfB4xgI", "g_1": "CAADBAADQg4AAhkgmFGlsif9nNtXwgI", "g_2": "CAADBAAD2BUAAue_mFGENiPSjZxbiQI", "g_3": "CAADBAADpw4AAjO9mFHAOz8KD2n7BwI", "g_4": "CAADBAADRhAAAqF7kFEcwLalLfDfaAI", "g_5": "CAADBAADAg8AAqXLmFHJyg2F_ybbvwI", "g_6": "CAADBAADVhYAAtK7mVGigRq_EkCuVgI", "g_7": "CAADBAAD2RIAArccmFEj-8LIVNAbsgI", "g_8": "CAADBAAD6AwAAuvmmFHBRarMimOWawI", "g_9": "CAADBAADExEAAsNkmVFr8DaHGOwsggI", "g_draw": "CAADBAADhA8AArxYmVH9ch5Jp00AAboC", "g_reverse": "CAADBAADMhAAAvVOmFGH284LIY7cegI", "g_skip": "CAADBAADbBcAAqinkVEOwkJtDRfk2gI", "b_0": "CAADBAAD-BAAAkj8kFG61GJdw29QOAI", "b_1": "CAADBAADcRMAAu-EmFFT1i4LcqO4OQI", "b_2": "CAADBAAD0xQAAqVhmVHyrFSAbxtfjwI", "b_3": "CAADBAADNg0AAn-xmFHev8IdF_ie0wI", "b_4": "CAADBAADlQ4AAjZamVFcIL_pVB5cFwI", "b_5": "CAADBAADrgwAAuL5mVHvEBZ8CG5p5QI", "b_6": "CAADBAADDhUAAuGRmVGQYvmEOxczBAI", "b_7": "CAADBAADIxEAAv_dmFEuVt39kkgZgwI", "b_8": "CAADBAAD2w0AAoE6kVHG7WscV4F2hwI", "b_9": "CAADBAADvQ0AArRMmVErWaSRP_giKQI", "b_draw": "CAADBAADlw4AAjF_kFHPWSoYKBwtwQI", "b_reverse": "CAADBAADog8AAqDJmVEJQp5WocnUnQI", "b_skip": "CAADBAAD-QwAAgbZmFGltUlnslDNUQI", "y_0": "CAADBAADrQ4AAr5WmVHNf69eBn2YOAI", "y_1": "CAADBAADcg8AAmqKmVHfVeUI3u_i7AI", "y_2": "CAADBAADkA4AAuDImFEQ8qjFlcKplQI", "y_3": "CAADBAAD-QwAAmromFGAqVn-Y8N72wI", "y_4": "CAADBAADjQ4AAmNLmFG80k7kfgx1NAI", "y_5": "CAADBAADqQ8AAmgYmFH1_ey_bMQNYwI", "y_6": "CAADBAADdQ0AAuWcmFEbG_gm1wGYCQI", "y_7": "CAADBAAD6QwAApQAAZhRI8OfRvLX3vkC", "y_8": "CAADBAADARAAAi-2kVEifJ-O9WVilgI", "y_9": "CAADBAADxA0AAhQ8mFHjnl9tUCHSLAI", "y_draw": "CAADBAADzw4AAncZmVEhLhX17eqX8AI", "y_reverse": "CAADBAADTxAAAqgFmVEJRBw4eWgnDwI", "y_skip": "CAADBAADPhYAAiGbkFG9hptFPLgj7wI", }, "not_playable": { "colorchooser": "CAADBAADpQ4AAlfDmFFHGkwyGFeCFQI", "draw_four": "CAADBAADMRMAAv7amFHvKGLoNyFbNQI", "r_0": "CAADBAADsBMAAuGdkFHTZ-jl4eNn-gI", "r_1": "CAADBAADVA4AAhpfkFEKt19qveGSPgI", "r_2": "CAADBAADrw0AAoWsmVHguULNoYJwUwI", "r_3": "CAADBAADzxMAAjvkkFFdtKJu5WGwUgI", "r_4": "CAADBAAD1Q8AAoHZkFFvyQnFHzfwiQI", "r_5": "CAADBAADWxEAAvkHkFGUo86qxKV0kwI", "r_6": "CAADBAAD_hIAAjx0mVGmlm-b_FHQBAI", "r_7": "CAADBAADmhEAAslomFHOv7bqcDJkDAI", "r_8": "CAADBAADtw0AAgqVmVG2HdSbcJYxZgI", "r_9": "CAADBAADNxEAAuF6mVE3WzTMJkSVAgI", "r_draw": "CAADBAADVxAAAiNukFE1K2xORNnfMwI", "r_reverse": "CAADBAADQxMAAvH0mVHKznpt-uu9ngI", "r_skip": "CAADBAADZA4AApbPkFFB9E2Px-HFpgI", "g_0": "CAADBAAD8w4AAjDEmFG7DwKggUEj9QI", "g_1": "CAADBAAD2g0AAo_DmVHIPG84WdIo1wI", "g_2": "CAADBAADEhEAAoRXmVGIG2nuN45P6AI", "g_3": "CAADBAADug8AAsSRmFFzk0TcRuG8VAI", "g_4": "CAADBAADrQ8AAvgmkFESfo9BjF7-3gI", "g_5": "CAADBAADVhAAAnPqkFFtxtFX9HlT-AI", "g_6": "CAADBAADMg8AAiSBmFHIQw1jFjv6UwI", "g_7": "CAADBAADvREAAv0BkVGDq3H1DCq_DQI", "g_8": "CAADBAADWQ4AAhOEkVG96JDgCtFrEwI", "g_9": "CAADBAAD2xYAAruDmFFAUMFryEwjoAI", "g_draw": "CAADBAADLA4AAu9tkVGTzBbeeYydIQI", "g_reverse": "CAADBAADVAwAAhYYmFExJS0ozE8-rAI", "g_skip": "CAADBAADYg4AAulsmFHxOkaz9OsTiwI", "b_0": "CAADBAADVxUAAtnOkFEIAAGw5CZEIxgC", "b_1": "CAADBAAD1RAAAnQqkFF9kDqD0wp3ngI", "b_2": "CAADBAADZg4AAvcUmVHTXwldirf1hAI", "b_3": "CAADBAADfBAAAkX1mVHw0CWX0h31iQI", "b_4": "CAADBAADPBAAAuTCmFFDpvXzes4qjwI", "b_5": "CAADBAADTQ4AAsWQmVHcrxDQUWOB4AI", "b_6": "CAADBAAD_hAAAoUhmVG8kjd65J8EngI", "b_7": "CAADBAADlRAAArtjkFGko5TuFNnncwI", "b_8": "CAADBAADZQ8AAltEmFE_fDYIXBrV3QI", "b_9": "CAADBAADrhAAAtM-mVGwhrWTD9IaYgI", "b_draw": "CAADBAADtQ0AAnVbmFGC1hI60JaOQQI", "b_reverse": "CAADBAADShEAAlcOmFHStPeFzfVIEwI", "b_skip": "CAADBAAD_xEAAgZFmVFMRA1J8Y1gxAI", "y_0": "CAADBAAD7xAAAqjjmFHnCu7eKJvSBgI", "y_1": "CAADBAADJQwAAp6tmFE2zDPVMieQ2QI", "y_2": "CAADBAADNA4AAl2mmVFpQOxJ41gk_gI", "y_3": "CAADBAAD3A4AAsxPmFGyZFv42UlxAQI", "y_4": "CAADBAADwg8AAm88kVEc9HZpl2gmzQI", "y_5": "CAADBAAD5hIAAkQ6mFHS-aGVuYZAnAI", "y_6": "CAADBAADvQ8AAs3RmVHVkVBfEF7eIwI", "y_7": "CAADBAAD1gwAAjlbmFGGH6rBdqP8QQI", "y_8": "CAADBAADbg8AAqvXkVH1ESeZFcGVrgI", "y_9": "CAADBAADOQ8AAnjokVG96pmCP7aZ3AI", "y_draw": "CAADBAAD6w4AAgsJmVETUteFwqTVJgI", "y_reverse": "CAADBAADtg8AAqiFmFFwothyN9TrXwI", "y_skip": "CAADBAADSxEAAhcSmFGu_F5LffmsZgI", }, } STICKERS_OPTIONS = { "option_draw": "BQADBAAD-AIAAl9XmQABxEjEcFM-VHIC", "option_pass": "BQADBAAD-gIAAl9XmQABcEkAAbaZ4SicAg", "option_bluff": "BQADBAADygIAAl9XmQABJoLfB9ntI2UC", "option_info": "BQADBAADxAIAAl9XmQABC5v3Z77VLfEC", } # TODO: Support multiple card packs # For now, just use classic colorblind STICKERS = { **CARDS_CLASSIC_COLORBLIND["normal"], **STICKERS_OPTIONS, } STICKERS_GREY = { **CARDS_CLASSIC_COLORBLIND["not_playable"], } class Card(object): """This class represents an UNO card""" def __init__(self, color, value, special=None): self.color = color self.value = value self.special = special def __str__(self): if self.special: return self.special else: return '%s_%s' % (self.color, self.value) def __repr__(self): if self.special: return '%s%s%s' % (COLOR_ICONS.get(self.color, ''), COLOR_ICONS[BLACK], ' '.join([s.capitalize() for s in self.special.split('_')])) else: return '%s%s' % (COLOR_ICONS[self.color], self.value.capitalize()) def __eq__(self, other): """Needed for sorting the cards""" return str(self) == str(other) def __lt__(self, other): """Needed for sorting the cards""" return str(self) < str(other) def from_str(string): """Decodes a Card object from a string""" if string not in SPECIALS: color, value = string.split('_') return Card(color, value) else: return Card(None, None, string) ================================================ FILE: chart/.helmignore ================================================ # Patterns to ignore when building packages. # This supports shell glob matching, relative path matching, and # negation (prefixed with !). Only one pattern per line. .DS_Store # Common VCS dirs .git/ .gitignore .bzr/ .bzrignore .hg/ .hgignore .svn/ # Common backup files *.swp *.bak *.tmp *.orig *~ # Various IDEs .project .idea/ *.tmproj .vscode/ # helm-docs templates *.gotmpl ================================================ FILE: chart/Chart.yaml ================================================ apiVersion: v2 name: maumaubot description: Telegram Bot that allows you to play the popular card game UNO via inline queries. type: application version: 0.1.0 appVersion: latest kubeVersion: ">=1.22.0-0" keywords: - telegram - uno - telegram-bot dependencies: - name: common repository: https://bjw-s-labs.github.io/helm-charts version: 4.1.1 sources: - https://github.com/jh0ker/mau_mau_bot annotations: artifacthub.io/links: |- - name: App Source url: https://github.com/jh0ker/mau_mau_bot ================================================ FILE: chart/templates/common.yaml ================================================ {{/* Preprocess values and prepare config file */}} {{- define "maumaubot.preprocess" -}} secrets: envs: stringData: TOKEN: {{ required "Bot token is required. Please set config.token" .Values.config.token | quote }} configMaps: config: data: config.json: | {{- omit .Values.config "token" | mustToPrettyJson | nindent 8 }} {{- end -}} {{- $_ := merge .Values (include "maumaubot.preprocess" . | fromYaml) -}} {{/* Render the templates */}} {{- include "bjw-s.common.loader.all" . }} ================================================ FILE: chart/values.yaml ================================================ # # IMPORTANT NOTE # # This chart inherits from our common library chart. You can check the default values/options here: # https://github.com/bjw-s/helm-charts/blob/main/charts/library/common/values.yaml # config: # THIS IS NECESSARY FOR BOT TO START, FILL THIS FIELD # token: admin_list: - 0 open_lobby: true enable_translations: false workers: 32 default_gamemode: fast waiting_time: 120 time_removal_after_skip: 20 min_fast_turn_time: 15 min_players: 2 defaultPodOptions: securityContext: fsGroup: 65534 fsGroupChangePolicy: Always configMaps: config: enabled: true suffix: config data: {} # config.json is autogenerated from config object above secrets: envs: suffix: envs stringData: {} # TOKEN is got from config.token value controllers: main: type: statefulset containers: main: image: repository: ghcr.io/jh0ker/mau_mau_bot pullPolicy: Always tag: latest envFrom: - secret: envs securityContext: capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 65534 runAsGroup: 65534 persistence: config: type: configMap identifier: config globalMounts: - path: /app/config.json readOnly: true subPath: config.json data: type: persistentVolumeClaim suffix: data accessMode: ReadWriteOnce retain: true globalMounts: - path: /app/data/ readOnly: false size: 100Mi ================================================ FILE: commandlist.txt ================================================ new - Start a new game join - Join the current game start - Start the game leave - Leave the game you're in close - Close the game lobby open - Open the game lobby kill - Terminate the game kick - Kick players out of the game enable_translations - Enable multi-translations disable_translations - Disable multi-translations skip - Skip the current player notify_me - Get a message when there's a new game in this group help - How to use this bot? modes - Explanation of game modes settings - Language and other settings stats - Show statistics source - See source information news - All news about this bot ================================================ FILE: config.json.example ================================================ { "token": "token_here", "admin_list": [0], "open_lobby": true, "enable_translations": false, "workers": 32, "default_gamemode": "fast", "waiting_time": 120, "time_removal_after_skip": 20, "min_fast_turn_time": 15, "min_players": 2 } ================================================ FILE: config.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import os import json try: with open("config.json", "r") as f: config = json.load(f) except FileNotFoundError: config = {} TOKEN = os.getenv("TOKEN", config.get("token")) WORKERS = int(os.getenv("WORKERS", config.get("workers", 32))) ADMIN_LIST = os.getenv("ADMIN_LIST", config.get("admin_list", None)) if isinstance(ADMIN_LIST, str): ADMIN_LIST = set(int(x) for x in ADMIN_LIST.split()) OPEN_LOBBY = os.getenv("OPEN_LOBBY", config.get("open_lobby", True)) ENABLE_TRANSLATIONS = os.getenv("ENABLE_TRANSLATIONS", config.get("enable_translations", False)) if isinstance(OPEN_LOBBY, str): OPEN_LOBBY = OPEN_LOBBY.lower() in ("yes", "true", "t", "1") if isinstance(ENABLE_TRANSLATIONS, str): ENABLE_TRANSLATIONS = ENABLE_TRANSLATIONS.lower() in ("yes", "true", "t", "1") DEFAULT_GAMEMODE = os.getenv("DEFAULT_GAMEMODE", config.get("default_gamemode", "fast")) WAITING_TIME = int(os.getenv("WAITING_TIME", config.get("waiting_time", 120))) TIME_REMOVAL_AFTER_SKIP = int(os.getenv("TIME_REMOVAL_AFTER_SKIP", config.get("time_removal_after_skip", 20))) MIN_FAST_TURN_TIME = int(os.getenv("MIN_FAST_TURN_TIME", config.get("min_fast_turn_time", 15))) MIN_PLAYERS = int(os.getenv("MIN_PLAYERS", config.get("min_players", 2))) ================================================ FILE: database.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from pony.orm import Database # Database singleton db = Database() ================================================ FILE: deck.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from random import shuffle import logging import card as c from card import Card from errors import DeckEmptyError class Deck(object): """ This class represents a deck of cards """ def __init__(self): self.cards = list() self.graveyard = list() self.logger = logging.getLogger(__name__) self.logger.debug(self.cards) def shuffle(self): """Shuffles the deck""" self.logger.debug("Shuffling Deck") shuffle(self.cards) def draw(self): """Draws a card from this deck""" try: card = self.cards.pop() self.logger.debug("Drawing card " + str(card)) return card except IndexError: if len(self.graveyard): while len(self.graveyard): self.cards.append(self.graveyard.pop()) self.shuffle() return self.draw() else: raise DeckEmptyError() def dismiss(self, card): """Returns a card to the deck""" if card.special: card.color = None self.graveyard.append(card) def _fill_classic_(self): # Fill deck with the classic card set self.cards.clear() for color in c.COLORS: for value in c.VALUES: self.cards.append(Card(color, value)) if not value == c.ZERO: self.cards.append(Card(color, value)) for special in c.SPECIALS: for _ in range(4): self.cards.append(Card(None, None, special=special)) self.shuffle() def _fill_wild_(self): # Fill deck with a wild card set self.cards.clear() for color in c.COLORS: for value in c.WILD_VALUES: for _ in range(4): self.cards.append(Card(color, value)) for special in c.SPECIALS: for _ in range(6): self.cards.append(Card(None, None, special=special)) self.shuffle() ================================================ FILE: docker-compose.yml ================================================ services: maumaubot: # build: . image: ghcr.io/jh0ker/mau_mau_bot restart: unless-stopped volumes: - ./data:/app/data ================================================ FILE: errors.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . class NoGameInChatError(Exception): pass class AlreadyJoinedError(Exception): pass class LobbyClosedError(Exception): pass class NotEnoughPlayersError(Exception): pass class DeckEmptyError(Exception): pass ================================================ FILE: game.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging from config import ADMIN_LIST, OPEN_LOBBY, DEFAULT_GAMEMODE, ENABLE_TRANSLATIONS from datetime import datetime from deck import Deck import card as c class Game(object): """ This class represents a game of UNO """ current_player = None reversed = False choosing_color = False started = False draw_counter = 0 players_won = 0 starter = None mode = DEFAULT_GAMEMODE job = None owner = ADMIN_LIST open = OPEN_LOBBY translate = ENABLE_TRANSLATIONS def __init__(self, chat): self.chat = chat self.last_card = None self.deck = Deck() self.logger = logging.getLogger(__name__) @property def players(self): """Returns a list of all players in this game""" players = list() if not self.current_player: return players current_player = self.current_player itplayer = current_player.next players.append(current_player) while itplayer and itplayer != current_player: players.append(itplayer) itplayer = itplayer.next return players def start(self): if self.mode == None or self.mode != "wild": self.deck._fill_classic_() else: self.deck._fill_wild_() self._first_card_() self.started = True def set_mode(self, mode): self.mode = mode def reverse(self): """Reverses the direction of game""" self.reversed = not self.reversed def turn(self): """Marks the turn as over and change the current player""" self.logger.debug("Next Player") self.current_player = self.current_player.next self.current_player.drew = False self.current_player.turn_started = datetime.now() self.choosing_color = False def _first_card_(self): # In case that the player did not select a game mode if not self.deck.cards: self.set_mode(DEFAULT_GAMEMODE) # The first card should not be a special card while not self.last_card or self.last_card.special: self.last_card = self.deck.draw() # If the card drawn was special, return it to the deck and loop again if self.last_card.special: self.deck.dismiss(self.last_card) self.play_card(self.last_card) def play_card(self, card): """ Plays a card and triggers its effects. Should be called only from Player.play or on game start to play the first card """ self.deck.dismiss(self.last_card) self.last_card = card self.logger.info("Playing card " + repr(card)) if card.value == c.SKIP: self.turn() elif card.special == c.DRAW_FOUR: self.draw_counter += 4 self.logger.debug("Draw counter increased by 4") elif card.value == c.DRAW_TWO: self.draw_counter += 2 self.logger.debug("Draw counter increased by 2") elif card.value == c.REVERSE: # Special rule for two players if self.current_player == self.current_player.next.next: self.turn() else: self.reverse() # Don't turn if the current player has to choose a color if card.special not in (c.CHOOSE, c.DRAW_FOUR): self.turn() else: self.logger.debug("Choosing Color...") self.choosing_color = True def choose_color(self, color): """Carries out the color choosing and turns the game""" self.last_card.color = color self.turn() ================================================ FILE: game_manager.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging from game import Game from player import Player from errors import (AlreadyJoinedError, LobbyClosedError, NoGameInChatError, NotEnoughPlayersError) from promotions import send_promotion_async class GameManager(object): """ Manages all running games by using a confusing amount of dicts """ def __init__(self): self.chatid_games = dict() self.userid_players = dict() self.userid_current = dict() self.remind_dict = dict() self.logger = logging.getLogger(__name__) def new_game(self, chat): """ Create a new game in this chat """ chat_id = chat.id self.logger.debug("Creating new game in chat " + str(chat_id)) game = Game(chat) if chat_id not in self.chatid_games: self.chatid_games[chat_id] = list() # remove old games for g in list(self.chatid_games[chat_id]): if not g.players: self.chatid_games[chat_id].remove(g) self.chatid_games[chat_id].append(game) return game def join_game(self, user, chat): """ Create a player from the Telegram user and add it to the game """ self.logger.info("Joining game with id " + str(chat.id)) try: game = self.chatid_games[chat.id][-1] except (KeyError, IndexError): raise NoGameInChatError() if not game.open: raise LobbyClosedError() if user.id not in self.userid_players: self.userid_players[user.id] = list() players = self.userid_players[user.id] # Don not re-add a player and remove the player from previous games in # this chat, if he is in one of them for player in players: if player in game.players: raise AlreadyJoinedError() try: self.leave_game(user, chat) except NoGameInChatError: pass except NotEnoughPlayersError: self.end_game(chat, user) if user.id not in self.userid_players: self.userid_players[user.id] = list() players = self.userid_players[user.id] player = Player(game, user) if game.started: player.draw_first_hand() players.append(player) self.userid_current[user.id] = player def leave_game(self, user, chat): """ Remove a player from its current game """ player = self.player_for_user_in_chat(user, chat) players = self.userid_players.get(user.id, list()) if not player: games = self.chatid_games[chat.id] for g in games: for p in g.players: if p.user.id == user.id: if p == g.current_player: g.turn() p.leave() return raise NoGameInChatError game = player.game if len(game.players) < 3: raise NotEnoughPlayersError() if player is game.current_player: game.turn() player.leave() players.remove(player) # If this is the selected game, switch to another if self.userid_current.get(user.id, None) is player: if players: self.userid_current[user.id] = players[0] else: del self.userid_current[user.id] del self.userid_players[user.id] def end_game(self, chat, user): """ End a game """ self.logger.info("Game in chat " + str(chat.id) + " ended") send_promotion_async(chat, chance=0.15) # Find the correct game instance to end player = self.player_for_user_in_chat(user, chat) if not player: raise NoGameInChatError game = player.game # Clear game for player_in_game in game.players: this_users_players = \ self.userid_players.get(player_in_game.user.id, list()) try: this_users_players.remove(player_in_game) except ValueError: pass if this_users_players: try: self.userid_current[player_in_game.user.id] = this_users_players[0] except KeyError: pass else: try: del self.userid_players[player_in_game.user.id] except KeyError: pass try: del self.userid_current[player_in_game.user.id] except KeyError: pass self.chatid_games[chat.id].remove(game) if not self.chatid_games[chat.id]: del self.chatid_games[chat.id] def player_for_user_in_chat(self, user, chat): players = self.userid_players.get(user.id, list()) for player in players: if player.game.chat.id == chat.id: return player return None ================================================ FILE: genpot.sh ================================================ #!/usr/bin/bash currentVer='1.0' xgettext *.py -o ./locales/unobot.pot --foreign-user \ --package-name="uno_bot" \ --package-version="$currentVer" \ --msgid-bugs-address='uno@jhoeke.de' \ --keyword=__ \ --keyword=_ \ --keyword=_:1,2 \ --keyword=__:1,2 ================================================ FILE: images/api_auth.json.sample ================================================ { "api_id": 0, "api_hash": "" } ================================================ FILE: images/build_classic_colorblind_deck.py ================================================ """ Script to build the classic colorblind deck from the classic deck. Requires imagemagick to be installed and in the path. """ from pathlib import Path from shutil import copyfile from subprocess import run IMAGES_DIR = Path(__file__).resolve().parent CLASSIC_DIR = IMAGES_DIR / "classic" COLORBLIND_DIR = IMAGES_DIR / "classic_colorblind" COLORBLIND_OVERLAY_DIR = IMAGES_DIR / "colorblind_overlay" COLORS = ["r", "g", "b", "y"] NUMBERS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "draw", "reverse", "skip"] SPECIALS = ["colorchooser", "draw_four"] def overlay_image(color, number): base = CLASSIC_DIR / "png" / f"{color}_{number}.png" overlay = COLORBLIND_OVERLAY_DIR / f"{color}.png" out = COLORBLIND_DIR / "png" / f"{color}_{number}.png" run(["magick", "convert", str(base), str(overlay), "-composite", str(out)]) def create_not_playable(card): base = COLORBLIND_DIR / "png" / f"{card}.png" overlay = COLORBLIND_OVERLAY_DIR / "not_playable.png" out = COLORBLIND_DIR / "png_not_playable" / f"{card}.png" run( [ "magick", "convert", str(base), "-modulate", "75,20", "-brightness-contrast", "0x10", str(overlay), "-composite", str(out), ] ) def convert_png_to_webp(suffix): for color in COLORS: for number in NUMBERS: card = f"{color}_{number}" png = COLORBLIND_DIR / f"png{suffix}" / f"{card}.png" webp = COLORBLIND_DIR / f"webp{suffix}" / f"{card}.webp" run(["magick", "convert", str(png), "-define", "webp:lossless=true", str(webp)]) for special in SPECIALS: png = COLORBLIND_DIR / f"png{suffix}" / f"{special}.png" webp = COLORBLIND_DIR / f"webp{suffix}" / f"{special}.webp" run(["magick", "convert", str(png), "-define", "webp:lossless=true", str(webp)]) def main(): (COLORBLIND_DIR / "png").mkdir(parents=True, exist_ok=True) (COLORBLIND_DIR / "png_not_playable").mkdir(parents=True, exist_ok=True) (COLORBLIND_DIR / "webp").mkdir(parents=True, exist_ok=True) (COLORBLIND_DIR / "webp_not_playable").mkdir(parents=True, exist_ok=True) for color in COLORS: for number in NUMBERS: overlay_image(color, number) for special in SPECIALS: copyfile( CLASSIC_DIR / "png" / f"{special}.png", COLORBLIND_DIR / "png" / f"{special}.png", ) for color in COLORS: for number in NUMBERS: create_not_playable(f"{color}_{number}") for special in SPECIALS: create_not_playable(special) convert_png_to_webp("") convert_png_to_webp("_not_playable") if __name__ == "__main__": main() ================================================ FILE: images/classic/source.txt ================================================ https://commons.wikimedia.org/wiki/File:UNO_cards_deck.svg ================================================ FILE: images/colorblind_overlay/colorblind_overlay.ai ================================================ %PDF-1.6 % 1 0 obj <>/OCGs[21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream Adobe Illustrator 27.4 (Windows) 2023-04-08T18:52:11+02:00 2023-04-08T18:52:11+02:00 2023-04-08T18:52:11+02:00 256 72 JPEG /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgASAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A7Jret6dDp2natq2nHXtT 14htI0hhyhihajxqsbh0WRUdfUk4lmYkA8KBdhoNAdQZEyEYRFkljKVJXrvmFdBt47jVfy5s7aCU 8Ul9S2kXkRWhMcDcT7HNhpux8GckY81kf0D+ksDMjmEng/NPys88aDyTYqWZQGDQ1BJ6/wC8+Zcv Zihfif7H/jyPG8ln/K1fKv8A1JFj/wAFD/2TZL/Qv/tn+x/48vjeScaX5ottUtBd2H5fWE1uX9IN 69op59l4tCrVPYU3zDzdi4sUuGeWjz+g/rSMhPRPvL2sadJpw1zRLNtLW3uks9b0U/DCoZ1R3WNQ FSSL1OfJVBcAqwrxK6vXaI6efCTxAiwR1DOMrZNrkt3cXllo9rM1sbwSz3VzHQSLbW5QSJG2/F5H mReVKheRUhuJzCZMNtLzS76a5j0DyRb6pZ2rmJr6YwRtI69SWmR2cnrUsWPfMcZifpFu9l2RixRj 42UQlIXXCZfcUkufPvl21uJLe48j2cU8TFZI39IMrDqCDb5WdXXR2EPZeM4iUctg/wBH/jzR/MTy sIEb/BtjQswC1hoCAu/+8/euD835J/0K714n+x/48utPPnly7uY7aDyVYNNKeMaloFBJ7VaADCNX fT7UZPZgQiZSy7D+h/x5ORqOiR3ttbaz5Ot9JhuJvq8eoW7ws8U52WkkCRvEw/mDBh1GWDOQdxTr 5djwlAyxZOOURdcJjt5WzXQpruKW70q8la4msGQwXL/bltpgTE7025qyvGT+1x5bVpmQ6Ji+q6hp /wBQh17WbU6w+pyD9B6QwDwpCw/csIyGUySJR2cqzAtwXYZVly8A72nNmEB3koHVdQg0m1W61DyB Zw27kAScrdwCegbhC3H6cpnqJRFmP2tE9VOAsw+1KP8AH3lX/qTbH/kj/wBk+V/nvL7Wn+Uf6P2/ sXzefPKyzSKfJ9ixViCx9GpIPX+4xOt8vtSe0P6P2/sRmm+YdK1JHktPI9i8UZCvK7W0aciKheUk KgsfAb5OOqMuUftZw1kpco/am2n3llFZXOtaPZHR7jSZCNc0VKLDJCN5m9NQE9VUq6OqhmK8T8Jy /Fl4h3EOThzcY5UQyjXZrySWz0uylME98zGe4X7cVtEAZXSoI5FmSMHty5dqZa3MfitNCluJoNN8 r2+orbtwlvLj02eR12JeWZZHkbb7TMWPfNMO1Mk5yjhxmYjtfEA7H8jGMQck+EnpVoCfU/LlvM8M /lKyjlQ0dGjhBB/5E5g5PaKUJGMsVEf0v+OuVDsgSFidj3ftWjWvK3psf8L2NKiq8IaE0O/9zkP9 E3+1/wCy/wCOp/kXf6/s/a6PV/K8kixr5VsOTkKtVhAqTTqYqYY+0pJoY/8AZf8AHVPY1CzP/Y/t R6QeX5JpYbvyvaWiQMqz3EXoCSFmFVZWRY3B3qChqO2+ZsO2J8RE8fCI1xHiBq/L9Tiz0EeEGM+I nlsd2QaHLd297e6NdTPcmzEU9rcyUMjW1wXCJIwpyeN4XXlSpXiSS3I5vHWvlL80vO+v+fvOlzpl vI0mk29zJbaVpys/oskLGP6xIoWrPKRUclqvIKO5MtNpp6nL4cDXUk8gB1L0uCGHSacZskeOc+QQ Wr/kb510ewW/1KwhgtGoDJxV+JbpzCFin+yAzY6fsSGWXBDNEy9x/Baj7QQH+RH2fqSL/A9x/Pbf 8izmd/oSyf6oPkWP+iPH/qUfx8F0vkO5jleMvbEoxWvpnsaYI+ymQi/EHyK/6I8f+pR/HwW/4HuP 57b/AJFnD/oSyf6oPkV/0R4/9Sj+Pgmvkzzn5i/LfzFHc20h+pVV9R05GJt7m3Jo/wAB4hZVCng9 KqfFSQdHrtDk0eQQmbB5Fyv3GvwSnCPBkh+Pjb6Uj4fpf8suVKfUrnr4/UY6fjmy0X+KZ/8AM/3T ykvqDDIl1Rfy+85fpMTAm8thD9Y5V9X6wPU48/2qU5UzoZGH5vBwV9MuXdw7NX8Jef2f+9cH/GRf +JDN9k+k+5qCjk1Z/wCUNQ0zTfLvp313b21yNRhvFiu7a5lASFGXbhGV5kn4fizRa/FPJmuIkRwG PplEcz5nl3tkTQZZ5MubS68t+arqzMjWs+qGSFpTWQq7RsC3ua5oO3ISiccZVxDGOTbj6s/uf+Uq 07/mBvv+T1pmibHlmqJqr+SNA/RQmLi9u/V+r8q+t67ely496dM18r4BXeXu9OcY1eXxK+iNX3cI tLPzU9P/ABvfcKV4w86fzekvX6MhqfrLl+z9/lI35/eWMN/vJH/xkf8AUmUu2H1H3D9KI0RAdVtH dvTijmR5JSrsFVWBqQiu3bwww5tWqP7uQG5IPd+mmZ65ruk38wgsZIoZP0yLiSKOOZfrKOR6crGR dnTkwZTQeHbMicweXe6PS6TLjHFMEjwa3MfSeo26Hajv5vUrb/lKtR/5gbH/AJPXebB4Riyenw/L 3nTj6K0r4/VU4/jmPl+uLi5/rh7ykNuupjRvOh1ETegWXj63Lj6vqmnHl3+z09sxRfDO3DHFw5Le f5hOAq3X+9U3+u36zhPNMubI9Mm02fQbfTtQkFoLW8NyfWSb0po5FVSOUKswZeO2XxIMaO1FyIEG AB2osl0Kaxn0TzzLYM72jwSGF5SzOR6Eu7FyWNffMzSkEyrk52jIJlXK2dXP/KVad/zA33/J60zL c5il4Lk+Wx9WDlv0hJz9Ota78a8foziMwkdJ6b/vTy+x6TFw+P6v9THNCedP+O2a/b9KPn41498o 7b/xg9/DH7m7sz+6+JSUf3Lf6y/qOaro53VaqsxooJPtvgASTSealqKz2OnxCZXuBx+uqFcOXT4Y y5YAHim3XrXNpqtSJ44CwZfxc7sbRuxvUdvm4GDDwzma2/h5fGviza2/5SrUf+YGx/5PXeegPKvk n8q+P/K37HlSn1yTr4/W46Zm9kc83/CpfeHoe2P8Vw/jo9ht11hP+VifpITC3Mc3Ez8vTMhkb0uP L4fskcadqUzpZHGfy3BV2OXu3/a8vvu8qzp2lWvP965/+Mjf8SOQx/SPcpWtBOqc2jYJ/MVIG/vh EhytWF+eP96E/wCYaT9ecT7W/wB5j9x+96v2c/u8v9X9b378zrie28ueRLi3kaKeKzLxyISrKyxW xBBGZXszESGUEWDw/wC+eby9GH6j5m83eZ2ttPu7ua/bmBb2yqo5OdgeKBeTe5zoMWj0+mucQI95 /tajIl6L5T/JmztI4tQ803AVwVZbJHCIp7CSX9o+y0+Zzn9d7QSmTDAPj+ofrbY4u96Vo+ieX9Pg Q6TZ28EZHwywKtWHjzG7fSc5zUajLkP7yUifP9TaAByR88EFxC8M8aywyDi8bgMrDwIOxymMjE2D RSw8+WLLy/pGuQWI4Wl1NFdRQ/775FFZBXtyQke2Zms1ks4iZfVEV72MY0n1z/ylWnf8wN9/yetM wWTwey81eYdGluotMvXt4pZGLxgKy1rTkA4YA+4zUxySjyL6hl7PwZxE5IiRA/HJGeWvJuvebLyS 5LlbdnJudQmq1WO5493b/MnJY8Uplo13aeHRxEf4ukR+Ng9V0LyF5O0vhb+nFfXiEsWuSsj8qCtI z8I6eFczYYYDzLx+r7X1Wa5WYR/o7fayqOOONAkahEXYKoAA+gZe6cyJNlIvNflfTtXthcPEq39o VmguQAH/AHZ5cCe6tSm+VZcYkPN2HZ+vyYZcIPolsR7+qKtv+Uq1H/mBsf8Ak9d5a655x54kki8o eTpY2KSJaxsjqaEMIYiCCO4zB1p5Ou7QNcLF7/zL5m1uOKxuruW7SoEcCqBybtUIAXPzrmHLLOex NuDLNOexNsz8uflREkK3vmOb012b6mjBQB/xZJ/BfvzKxaTrJzMOh2ub0LTdI0O0Xnp9rBHX/dsa qWJ936n78zYwiOQc+GOI5AI2SOORGjkUPGwoyMAQR4EHJkNhFsQv/Ltno2keazZJ6dreWDyrEOiO IZgwX26HKseMRJrq0YsQhI1yKeXP/KVad/zA33/J60y1vefprGp6feXQs52iDyPyUUIO53owIrnn MNblwzl4cqsl7A6bHkjHiF7L9L0bVNdu3kqSpas91JUgH+J9snpNFm1cyfnIsc+px6eNfIM003yt oNlSNwtzc7EmYg7+ydBnVaXsnTYtjU5+f6nRZ9fmybj0x8v1p5HHHGvGNQijoqgAfhm3jERFAUHX kk80v1zRrTUbVuaAXEY5QzAfECu9K+B75g9oaGGeBseoci5Ol1MsUtjseYWW3/KVaj/zA2P/ACeu 82Divi3Q2ZfN14ykqy/WirDYgi4TcZuvZYXqZ/1D98Xf9t/4nh/HR6NqXnLzdrdpHpl7fzXcBKql uAKu1fhDcAGkNenKudjh7P0+GRnGIie/8cnlTIlnflL8llNuuo+aZvq0VA/1FGCkL/xdJ+z8l+8Z pNd7Q78GAWe/9QbI4u96jo+geWbFPU0qztk3P7+JVZya71k3Y/Sc5nUarNPbJKXuP6m4AdE0dEdG R1DIwoysKgg9iDmMDW4S+TP+cmPK+n6H5pt5NPjEFtf2MkpgXZUkDkPwHZTsaZZr9ZPNGAmbMbF+ T0XYEahl/q/regfmr/yi3kf/AJgW/wCTNtnT+y/+U/zf988vm6M1/LDyHb+XtLGr6hHXV7iPm3Ib wREV9MD+Yj7X3fPB7Z7TOon4cD+7B+Z7/wBXzZY4VuwbRdO1v8zPM13f3d4bawsmV0UjmI1Zj6cU aVUVonxNm61GXF2dhEIxuUvt7yWsAyKpaw63+W3nazsRdG60q/ZOYAKrJG78CShJCyId9j+vIzli 7R00pVwzj9h58+4rvEvdM4lyEg8xXEcthqkaGrQC3ST2YuH/AOIsMslAiIPfaEVc/wDKVad/zA33 /J60ytLxLyn5Um8yeY5LYkpZQu0l5MOoTkaKv+Ux2H39s1eLHxyp9K7R7QGlwCX8RFRH47noP5n6 zL5c0Cx0nRx9TW65xq0XwlIogvJVI3BYuN+vXMrUT4IgB5rsHSjVZpZMvq4a59Sf7EhuPyk1OHy+ b43w/ScKtctb8TSvEMUEnKvIcetOv35UdMeG73djD2jxyz8HD+7Ppv8ATXcyr8q/Mt7rOiSw3zmW 6sHEZnbdnjYVQse7ChFcv02QyG/R0/tBoYYMwMBUZi67j1ZXqk6QadcysaBY2pXxIoo+knLpGg6f BAymB5oS2/5SrUf+YGx/5PXeSaXm3nz/AJQzyj/zCJ/yYizB13IOu7R5Bkv5a+TI9Nsk1a9jB1G5 XlCrD+5iYbU/ymHX228cnpcHCOI82ej0/COI8yxaG31X8wfMd1zujb6bbEtGPtKiV4oFSoqzUqT/ AGDMcA5pHfZxgJaiZ32C69i1XyD5mgkjujPp943qSIAVV05UdWSp+Ja7H+0YyEsM+exWQlgnz2L2 DNm7dIPNE4bSPMMANTHpbsR4c45x/wAa5EHdiD6iPx1RVz/ylWnf8wN9/wAnrTJMmB6do8uq65Lb KeMYkdppP5UDb/SegzzzS6KWo1BgOVmz3B63NqRhwiXWtmVeabz9CaNBZ6cPQMpKKy9VVRViD/Ma 9c6PtfP+UwRx4vTxbfDr8fN1GgxePlMp70lUXka8k0v6yLkfW5FEyw09iQvOvXfwzWw7AySw8fF6 yLr9ve5cu1YjJw16Rtf7E38j6xcX1nNb3LmSS1K8ZGNWKNWlfGnHNn2BrZZYGEjZhW/kf1OH2rpo 45CUeUmQXkqxWk0jdERmP0CubrPPhxykegLrccbkB5pfbf8AKVaj/wAwNj/yeu8tYPizRf8AlLL3 5Xf/AFEJm69lv8an/UP+6i7/ALb/AMTw/jo+mvyg8gR2FnH5h1GOt/crWyjYf3MTdH3/AG3H3L8z mV292mckjhgfSOfmf1D73m8cOrGbqHW/zJ87Xlibo2ulWDPwBBZY40fgCEBAaRzvuf1ZsoSxdnaa Mq4py+08+fcGG8ip61p2t/ln5mtL+0vDc2F6zO6gcBIqsPUikSrCtH+Fslp8uLtHCYSjUo/Z3EKQ Yl7vG6yIrrurgMp9jvnEEUach8w/85aTqfM2lQftJpkrkezysB/xDKc0dgfP9T0fYX0Zf6v63rba DBrM/wCX6Sxl7e0sHu5ASKUiituIbb4quy5u9DqTh0+UjnLhj8+L9FvMyFkM+vf945/+Mb/8ROaz H9Q97MvLvyDaE2usiNWWjwVDMG7SeAXOm9pweKF+f6GnD1UfzhaEebvLwdWZqLTiwFP3w7EHJ9g3 +Xy1+Nlycw9ZuLiG2t5LidxHBCpklkbYKqipJ+QzlYRMiAOZbnm/lnXBrugeZ9VKsoudQUorEEhF ESxjYdkUZuO2NN4Hh4+6H6Tf2teM3ZZxc0/xTp+2/wBRvaHtT1rTNK2JX+XeiQ6boInCFZ9QdrmU k1PEk+mK0G3Df6cpwQqPvdv21qjlzVe0BX6/tYt+d5iH6F9RWb/emnFgv++fENlGr6O39lb/AHlf 0f8AfPR9Vp+i7yvT0JP+IHMuXIvL6f8AvI+8fe89/JMxG11b01ZfjhryYN2fwC5i6Tq9L7U3xY77 j+hN/wAydfhtIdP0lTWe/uYmkVTQiKORWqdj9pwB9+WaidUO9wuxNGZmeXpCJ+ZH6mQW1P8AFOoe P1Gy/wCT13mQ6FizaPDq1l5HtpULW6WyTSiopwjgiajbbhjRfpzHzQ4pRDi58fHKILPsyHKeX/k0 Yjc6pwVl+CGvJg3d/ALmv0XMus7P5l35ymIXOl81ZvgmpxYL3TxDY63mF7Q5h6e7oiM7kKiglmOw AG5JzYOzedWGtJrOl+eL9A3pPbusVT/utLeVUoKbVArmLp58UpFw9Nk45SLMbmn+KdP8fqN7/wAn rTMpzFHyrp0dtaTXPGkt3K7sTueKsQo7e5+nNP2NphDGZ9ZyPyB2c/X5jKQj0iAlX5iFPSseQJ+K SlDTsvsc1/tLVY/879DmdjXcvgyqx/3it/8AjGn/ABEZ0Wm/u4/1R9zqMv1n3sP/AC74etfcQR8M damvdvYZzHs19U/cP0u67Zuo/FNvOWppbWCWoNZbtwtAaEIpBY9/lmx7d1Qx4hDrM/Z+NnD7NwGc zLpH70XbU/xTqHj9Rsv+T13m8da+TPyq0KLXPzXGnTKWt3a7ecA0/dxzq7A7ftBeP05mdkak4Z5J jn4Zr3mUXoe2Bekw/jo+yFUKAqgBQKADoBmG888i/J5oT5u8whFZWo1eTA1/fHsAM6zt6/y+K/xs 04+ZVvz8aEWujCRWarz0CsF7R+IbIezAPFOvL9K5uj1G0ZVsoWJooiUknsOIzmZj1H3tofHX59eY o9f85XN9CSbZLd4LYk1BiiPEMuwoGNW+nM3tjSHBDFE86JPvJ/Aeh9n5XDL7v1vrHyrbo3l/Qrg/ bj02GNflJHET/wAmxmCJekj8df1vPp0yqylWAKkUIO4IORV4mPL/AJ48g+ZJp9CtmvdJu2C1WNpk MXL4RKqEMrJX7X9SM7L81ptdhAynhyR8638vf3NFGJ2VdB8secvOPmu31/zNA1pZWpR1jkQxBljb msUUbfHxLblj9+R1Os0+kwHFhPFKXx59SeSiJkbLf5ufmNFdo/l7R5hJb1/3IXUZqHIP90hHUA/a I69PHHsLskx/fZBv/CP0/qXJPoF/5Xf+S/1r/mMT9UWYftN/fR/q/pLLDyenXP8AylWnf8wN9/ye tM5ttR9lGsVnBGv2UjRV+QUDAOTZllcifNi/5keULjzFpUTWdDf2TM8CMQA6uAHSp6E8QR8spz4u Mbcw7bsTtKOmyHj+iXPy7iwuTXPzQl0caCdPm9Vw1u8/oOJvTAA3krwoQSOVPpzH48lcNO+jpOzx l8bjFc64hV+7n8PsZN5etbL8vvKkt1q8g+u3L85IkILM9KJCnjTuenXtl0AMUbPN1OsyT7S1IjiH pj1+8l5fda5e655qh1G7P7yW4i4IPsogccUX2A/rmEZmUrL10NJDT6Y448hE/E1ze723/KVaj/zA 2P8Ayeu82z5ehvK0QOjeX5abppcaV/1kgP8Axrka3Ykbp9kmTye/0TzZ5P1+41HQrdrqwuC1FVDK vBjy4SIvxDiejD7+ozXSxzxSuO4dVLHkwzJiLC6DQvNXm/zHFea1A1rp1q1KMhiUxq1eEat8RL92 /sGIxzySuXJIxZMs7lsAivzM89RGKXQtMk5s3w386nYDvEpHf+b7vHJarP8AwhlrNT/BH4pb5D/5 Qzzd/wAwj/8AJiXDoeRT2dyL0m5/5SrTv+YG+/5PWmZzsUwtECWsKjoEUfhlWCNQiPIM8huRSvzV oj6rp4SGguYW5xV2B2oVr75r+19AdRiqP1x3H6nL0GqGGdn6TzY0up+cY7A6b9Vk5ACJZPSYycKE bN9noPtZoBqtcMfg8J7r4Tde/l8ftdocGlM/E4h389k30Ozh8taRNdai4SaYgvGCCfhB4ovi25zZ 6DDHQYDPKalLp9w97h6rIdVlEcfIfi2HajqlxqeqfWptuTAInUKgOyjOX1Wrlny8cv7B3O7w6eOL Hwh6Hbf8pVqP/MDY/wDJ67z0l4585f8AON6I35uasWFSlhfsp8D9dtxX7icpxH1F6Ttb/FcP46Pq LLnm3jGveWPOXk7zXca/5Zga7srou7RxoZQqyNzaKWNfj4htww+/Ow02s0+rwDFmPDKPw5dQeTQY mJsKR8v+ePP3mSGfXbZrLSbRitWjaFBFy+IRK5LMz0+1/QDJfmtNocJGI8WSXne/n7u5aMjumv5s /mNBb203lrR5Abhx6V/cJ9mNOhhWn7R6N4Dbr0xuw+yTKQzZOX8I7/P9Sck+gfM/nj/ehP8AmGk/ XmP7W/3mP3H73pPZz+7y/wBX9b6ruPOsXlfT/JbXYZtOvdP9O6KipQrFblJKd+NTUeBzE7P7OOpx 5OH648Nf7LZ56UqIZRF558mywiZdbsgjCoDzxo1PdGIYfKmY0uzdQDXhz+RTxjvSzUfzX8k2bCNL 367MxCrFbKXqSafbPFP+GzJxdiame5jwjz/FoOQPLPOP5ua5rsb2dkv6N05wVdEassins8m1AfBf prnT6DsLFgPFL1z+wfBplkJS/RPy11vVtOgvlubO0+u8v0fb3Uvpy3HA0PpqA3+ftvl+o7XxYpmN Slw/UQNo+9AgSzT8uLW4tPJPmC1uUMVxBfiOaM9VdPTDA/IjOd9o5ieSEo7gw/SW3Fyek3P/AClW nf8AMDff8nrTOdbUg8qfmPod3Zra6ldR2V/bfupPWYIjhDxDq5+HcDcHvmPizxIo83fdodiZoS4s cTKEt9uY8qTq487eUbdOUmr2rD/iuVZT90ZY5Yc0B1cCHZepkdscviK+9iuvfnFpdvARo8DXkrFl WaUGOIEAGvE/G3XptlE9UBydxpPZrJI/vTwjuG5/V97zdpvMfnHXY4nkN1fTkiNSeMcaD4jQdFUD /MnMS5ZJeb1Ajg0OEkDhgPmf1lH3XkvUdGudPvjcW19ZPdRwtc2knqKkoYVRthQ7ZI4jGjzDj4+1 IZ4zhUoT4SakKsd72i2/5SrUf+YGx/5PXebR84Yw3mdPL+jeULidS1pPYrDcBd2CmGEhgP8AJI+7 MfNl4CD0cbPm8MxJ5Mlh83+VpollTVrQKwqA8yI30q5Vh9IyYzQPUNgz4z/EEBqP5j+UbJSfrouX 7R26mQn/AGWyfe2QlqYDq1z1eOPW2A+a/wAztW1Ay2Vgv1C0qUdlNZnANN224g+A+/MPNqpS2Gwc DPrJS2GwSnRvI2q6pYx3ontrSGdjHaC5k4NM4NCIwA1dxTK4YDIXsGrHppSF7D3si8oWVzY+V/Ol pdIY7iC2kSRD2IglzL0cSOIFzdDEx4gXodz/AMpVp3/MDff8nrTM12CC0XzXp7q1peSrb3EDGMM5 ojKpoDyOwNOtc0Wg7YxkcGQ8Mo7b8i7PU9nzHqiLBTKXzDocS8mvoCP8l1c/ctTmwn2lp4izOPwN /c4sdHmP8Mvkk+pefLCKNvqCG4kBADsCib133+I9PAZqtV7Q44j90OI952H6/uc7B2TMn1nhH2sQ mutV17UY0djNPIeMUY2VR1NB2AHXOanlzavKAfVI8g7mOPHp4EjYBXvfLl5YIlyZYbiESCOR4H58 Hr9lthTLNR2bkwjjuMo3R4TdHza8WtjkJjRBq9+rO7b/AJSrUf8AmBsf+T13nobyb5Q/KbzYPLH5 nXOoSRmW1kjvILtF+36T3MbErXuGUH36Zldk6H8zknAGpcNj32Hoe2JVpMP46Pqe089+TLqBZo9a s0VtwssyROPmkhVh92WT7N1ETRxy+AJ+55zjHel2p/mt5GsEJ/SIupB0itVaUn5Nsn3tl+HsTUzP 08Pv2/ag5AHm/nP849Z1EzWGkIdNtASjzBq3DgGmzD+7/wBjv750XZ/YGPHU8nrl9n7fxs1SyE8m P+Xvy+1fW7BdQ+tWlhazSehayXsvp+vL04RgBid9sz9V2pjwz4KlKQFnhF0PNjGBLzD8zdLvdK1m XT76P0rq2gkSVOu9agg9wRuDnK+02aOU4pxNxMT971Ps6Khl93630X5gtrW5P5aW91bi6glg4NAx AVqw24HKpFQDQkd+mWdjzlHBnMTwkCO/+mebnzDF/P0SxeXdJZYLZZJbm7W4uILGOyZvR4CMUChw AHbvQ/Rm97Lleae8toxoGZlzu+vua58mEWf+9cH/ABkX/iQzc5PpPuawo5NXrK6Fq2tw+Q7/AEmP 6xa2UcMd3MjACF4ZVL896inE5yx1OPCdRDIalImvOw3UTVJ7oc8M+m+cpoXEkT6u5R1NQRyj3BzT 9rRMY4QefhhnDqzS5P8AztWnD/lxvv8Ak9aZp2x515R0uwuYNMkvreJ3fULlIGW1SYSRAUeO5YgB fjNUZqnwzBxRBq+97PtHUTgZiBP93G/URR6GPw5jZ5tdPI9zK8ihZGdi6qqoASdwEUKq/IDMQvVY wBEAcq9/2tt/vJH/AMZH/UmKB9R9w/Syj8rZI182RozhGmgmiiqaVdk2H4Zdp/qdR2/EnTE90gU4 tNJ1DRfJgtNUiNrc3WsW5ghcgswXjUgKTt8JywRMYUe9wcuohn1XFjPFGOKVn5vTbb/lKtR/5gbH /k9d5nvEMI1ZIZNI8hiW1N7C0MQa2XifUrBHRfiKrv7nMTU847W4WrHqjYvdjetxw3Xl6a/mtEtJ 4r70bJxAlq8kTKWdXjjAU8KDfMTILjdVv7nByAGFkVvttTE8xnFVbr/eqb/Xb9ZwnmmXNncWjanq +heUpdOj+sRWckqXPFh+6Yzq1WBO2w/z2zMEDKMK6OcMcpxhw9P1p4Z4pofzBljYNH6LrzHSqWrq 2/sRmVhNzk5mA3OfvZXc/wDKVad/zA33/J60zIcpiGl2RkfUPVWMfW3kt7Iyxq1Z92HFmB47bfMj OF0mDiM7r13GNgH1eV8u73kdz0ufLQhV+mjKj0/H3MddHR2RwVdTRlPUEZpiCDRdoCCLDY/uW/1l /UceiOqb+TpY4/MNsZGChuagnbdkIA+nNn2LIR1UL8/uLhdpRJwSr8bo+GwvNM8v6hHfJ6T3E8CQ qSCWKOGYj6Myo6eeDS5BkHCZSiB8DZceWaOXNAw3qMr+TKrYj/FWojv9Rsdv+e13nbPOPizRiB5s va9/rYHz+sIc3Xssf8Kl/UP3xd/23/ieH8dGU537ybsVVrz/AHrn/wCMjf8AEjkMf0j3KXosGian r/kDyrHpEX1t9PurlL1EZQYjJOXXkCRtx3zn5amGDV5jkPDxRjXnQptq4inl/wDzkbcQXH5kao8L iRVgVGKmtGSFEYfQyEfRnK9pRMcOAHnwy+2Rep7A+nN7v0Po3VfLti2nQ6JrVlc3Gm2TV0jVLFHl lhQbRxMkQeZWjWicuLKwAYkNtkdJrMmnlxQ68x0LzkogpXeeTPKV7EIry88xXMStyWOaG+kUMARW jWxFaHM/H25lgbjHGD5RpicYQsX5bfl4kqOq61yVgVraXdKg9/8ARctPtFqCKqPy/avhBb/yrP8A Lr+XWv8ApEu/+yXD/oj1PdH5ftXwgiLfyL5LtopIba48wQxS/wB7HHb3qK21PiAtgDlc+3s0iCYw JH9H9q+GE+0bQLUWdtpGk2U2n6BBOl3dXFyrRz3UkTK6osclJVBdF9RpFX4RxVSG5LrNVqsmefHM 2WYiAnutWN68trqOnBWv7EsBC7cVmgloJoS1DxJ4K6mn2lFdicx0sVbRPLb3E1ykeuaPNcMZLmzt obsIJD9reCOaJv8AYOV8MpOAXtYdtHtnKIiMhCfDsDKNlASeRvIksjSyjWnkclndrS8LMxNSSTbb k5D8rHzcmPtJqAKAhXu/a2fInkIxKvDWOIYkf6Jd1qQK/wDHt7Y/lYp/0Sam79Py/atXyH5CVgyr rIYGoItLwEEf9G2P5WPmp9pdSekfl+1MLbQvLNvfwX6W2s6vfwEG0huobmgcbgh7iOCJadau4GTG CIN83Fy9s5pQMAIwjLnwimV6Jp91ALm8v+H6Rv5BLcLGS0caqoSOFGYAsqIu5oOTFmotaC51KQ3+ kRxW7aRqtlPc6LHL62lX9kryTW1SSIXiiDSj0y3GNkRl4UDcSKtCeMSFFryYhMUUtvPLHlO9ZWvJ tduWQUQy2185A8Bytz4ZTLSxPMlolo4nmSfih/8ABHkP+TWP+kO8/wCybI/k4ebH8hj810nkryK0 jsyavyYkmlneUqT/AMw2H8nDzSdDDzVbfyv5RtldLeXXYUk+2sdtfIG+YFuK4RpYjkSkaOI5E/NM tP0O3ksRoukWU9poryBtUvbtHiluEWhaBI5AktJKcJGZFXhULUmq3Y8YgKDfixRgKCf65YXc6293 Ycf0hYSGa3SQlY5QylJIXYAlQ6Nsd+LBWo1KGbYklz+iLqUS3MGr2NwG5Pax29zIqSb1KtAk8JJr 1jcj8c1mfsrHklxcU49djtfe5mLXTgKqJ94Q0ml+VpHLyDVndt2ZrK9JPzJt8xZez+CRsmZPvH6m 8dq5QKAj8mho/lPgRw1SlRX/AEK8r3/5d8H+h3T98vmP1J/lbL5Nfofyl/Jqv/SFef8AZPj/AKHd P3z+Y/Uv8r5v6KIWDQFmjmFvq2oTxbwW8ttdAFhuBymjhiX/AGbhfHL4di4RISkZTr+cbapdo5DE gCMb7gnmiWN8sl1qWpKiahfFQYYzzWG3i5ejDzovIjmzsf5mIHwgZt3AfOP5t/kn5r0rzNd+YPLF pPqWl3s73ipaIJLm1mmYtJH6CDk8ZZzw4KaL8LDbkwx5MmHIMmM1IPQaPXYMmHwNR9I5Fhf6B/Nf /qw6z/3DJ/8Aqhmy/wBEGu7/APYhl+Q7M/nn5/sd+gfzX/6sOs/9wyf/AKoY/wCiDXd/+xC/kOzP 55+f7G30T82XdnbQtZLMSSf0XP1O/wDvjAO39aBV/wCxC/kOzP55+f7Fe0svzms+f1TS9et/UFJP S0+5TkPfjCK5Cfbern9XCffGP6k/kezP55+f7E48hfkl51816/DceY7K507REcHULi/RoJpY4yCb eGA+nIPU5U58Qq/EalhxOFnz5dRPjymyubWabT4Ti0+5lzL/AP/Z 1 False False 193.599991 289.599976 Pixels RobotoSlab-Bold Roboto Slab Bold TrueType Version 2.001 False RobotoSlab-Bold.ttf Cyan Magenta Yellow Black Default Swatch Group 0 Document AIRobin application/pdf colorblind_overlay uuid:d0e88164-e54a-43f1-9176-e4b67b8944dd xmp.did:0c5f72c6-954f-6a4d-8cba-e740cb0ca04d xmp.did:6aa152a9-2e2b-ef49-b9a6-6c5e8b86b26c proof:pdf saved xmp.iid:6aa152a9-2e2b-ef49-b9a6-6c5e8b86b26c 2023-04-08T17:06:15+02:00 Adobe Illustrator 27.4 (Windows) / saved xmp.iid:0c5f72c6-954f-6a4d-8cba-e740cb0ca04d 2023-04-08T18:51:30+02:00 Adobe Illustrator 27.4 (Windows) / xmp.iid:0f37ae40-281b-5247-ba02-870759ad3e47 xmp.did:6aa152a9-2e2b-ef49-b9a6-6c5e8b86b26c xmp.did:6aa152a9-2e2b-ef49-b9a6-6c5e8b86b26c Adobe PDF library 17.00 endstream endobj 3 0 obj <> endobj 5 0 obj <>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 193.6 289.6]/Type/Page/PieceInfo<>>> endobj 18 0 obj <>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 193.6 289.6]/Type/Page/PieceInfo<>>> endobj 19 0 obj <>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 193.6 289.6]/Type/Page/PieceInfo<>>> endobj 20 0 obj <>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 193.6 289.6]/Type/Page/PieceInfo<>>> endobj 23 0 obj <>/Properties<>>>/TrimBox[0.0 0.0 193.6 289.6]/Type/Page/PieceInfo<>>> endobj 30 0 obj <>stream HVn1 +t.@YHk"'Hs `Hz JC×>VtEYjvkd]}?>݃O? n->No J\r\\Lʁ > S~IdЈ2&6e8+py0]]T6x妘YZ~6A+|S}*ћ~G^>rӄgr8:UC2%dQC6.!Yٛ* (;]% g17Q BSt֐SWk 5iEf-[Rtsw@6TQ25(br5nGdEP&i~(*qH)n&:ɕУg?-+*ƾA+`^Zk1|`>0Lvvyh̟>~nw:zhN8sWkD}~d:ٺȴL@9شI?ㇻ5l^FmP> endobj 9 0 obj <> endobj 10 0 obj <>stream %!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 24.0 %%AI8_CreatorVersion: 27.4.0 %%For: (jhoeke) () %%Title: (colorblind_overlays.aic) %%CreationDate: 4/8/2023 6:52 PM %%Canvassize: 16383 %%BoundingBox: 0 -1 1048 290 %%HiResBoundingBox: 0 -0.077777730093658 1047.99995112419 289.600155067434 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 14.0 %AI12_BuildNumber: 669 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 854.399963378906 0 1047.99995422363 289.599975585938 %AI3_TemplateBox: 97.5 145.099975585938 97.5 145.099975585938 %AI3_TileBox: 645.19995880127 -251.200012207031 1257.19995880127 540.799987792969 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI24_LargeCanvasScale: 1 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:24 4 %AI10_OpenToVie: -487 864.599975585938 1 0 8629 8116.5 2052 1274 18 0 0 78 121 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -487 864.599975585938 1 2052 1274 18 0 0 78 121 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %AI17_Begin_Content_if_version_gt:24 4 %AI17_Alternate_Content %AI17_End_Versioned_Content %%PageOrigin:-286 16.5999755859375 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 11 0 obj <>stream %AI24_ZStandard_Data(/X,:'$D:\F7uwwS5 kjX  n r[ -@ #@M`M 4]6__?3XӾ;\sAsyu{ ڴ廍_6 QvEl6d{W8 -`veAZ@ q;1e׵vy-\5W6f6]{ԭ @|kǮ08se3eЦ[-8Λ[WQ%}Z|P$bK"n[F/3-Òa.q08]5ȳaw :Jْ%oOlInf*|lǶMfˏ\b.3݆ʼpcW;SLo^/6KxxQ>X>1?@± |5#v/,9ueL@/6@8oQ76ғђ!gm5k4e`-0כӳh8vߵpn-Wnֵh[_F59[A9a]e,<ďa-mm}o%kw6a[H$n8]-?[gͶu;J mhaPops6ivVdz;0z-c?۸6tKo%c0_Kb z-,$ 7E/Ų{n@l!ڻMWVYmÛg@p?€j'ZijĴ($Խ=m}랍 \篿6s5z@61q 7\{r'ɶInM~i[Bލ6V-3`@@O!vA JYBH?:G8:cˇ(r|8Q hcچSop};L 7aygnm@3|pZ{bãRkyۯgE.lޢp)B&mR; gm'uSYMH&2 M`5`x-kl4ٿ] dzk6@\bM6&^6ӳo&+v62nVn㏷)6^MaG)n<v)|qE.qk:Oytר)ym1VW~d[v{6Ŷ &ۏ7 /C暕aX- t#=`kh{e00xX[&ʪg5{ʐ:jP kam yyaw߶m۶aڱYa\ϱQ"H0f 4|ǵ'xt>\"ze߭\;FY} HƇ'H;d+2: 26ȇKH>rXX/ug KaztͬցܵxkߙS-}XnXwleRZq5", Ewι;weYv1Ar >1=#X|eIo^B(RGElYV3 ~(-RaC[Ć}ч3 E>I,vBplfõ w ڷcxe7+ W{v͡-b6lqQ[{r6`"v=dzŶ;ן[;]7 pp;ⷲw,|o!rK7" L_6Wn@!olm|6OF!Eݦ +\m\3Uz[7<Am/s"E_bA0h y|mmz_[n@8(6k~цu#4|`oj NEl[-Z@Qj9n#?$ tu&X,.XOP@HQh$T?h]reyn@]*71^ oP:R,!5:DYFrmkXbmbF)%t*N y׏]P\Y4$VP \SMMᔄgp& .C”n@pM Z@;D?$4)@_ u鏅{|>sjh &^,8\J^6"D][!y ] c򬶚EG L]'6 '{x? `ƕG+V>FJفf^ b xEh|]V#zZPc*I_7 jU  @]N'd',#0^ v&DYwݮIjPnDJ%2Uf~XcLp{opBn4(L'8n`2 y\hhm"8!h Z% 6L؊@=06c;J; ( dQJr4*wM  Cf 'bxw P4ɠt<@j KEYFr,[[…ޑ !WDPw, co_>bwB' j 1,$Df Z#dwB^!vƻdKR]] B"^wqPu 8D7 lD.g:R2$x7 ϓyOX|U,n@8! T% <`! `BTL ^B1QuV^2(5*E1TaB[UIA4N l v7 "].3 Y)WHsߔ &6SĻ8'SEՑ<eIt3Q54݀`2MjDEZX6%Xqx7 8@æ] /'/G-_s`6(Ld"?:5PccФP'P΢j/=f6R($Z BvirZ=P ]} hA _9@ONZ vMuTBuB&rgE|@;X݀PZtN֐D xbdD E]o<rǕ|'XFcĘ%͏B~o"F!(e O<40hXA6" 5s'J?$Pɂf,4U@L3A"/ (+~R  4?EmyT:Q8eduF8!bBEZit[ƈO&n@-i]8Xs[TEbtv1G3 !5 J^C*Rjt,jwy8B"^z7 12>e/$ #HaHf 8kA Fq mp݀ݏ̏y$-袻tv|@Uq`^Abڥthz8jE09iNH5CNE M m#0lmNc628uUbp݀|?~.y$1fTGM`-k`FL܀bp38U"lp^\|݀Z>ːg y)Bq\Pz OI֙ N*(Ŭܚum 7[y7l?`Ė]n6>mH:sn@߆ӼF|$ &86GU`%VS/KC = G 6"ذ|n;~nTcpu@}]dtE&HGCu ,Kit6P愔:Er!Q2 DҐgivDuB93Am΍*f[l.wa{(JIp+#(9_;FBU|i~;?%!E[dn;X5x[ Kov1ʮY-6w[}}k~h@[k?\VsG$[ G?Gr@[km5'uQ-N, c&݀`7܏[ hS(h6Q֑byQh#-UBCV"MwBG̝fʲ fWx)݀F ߋ /݀ Z\{ҦR'rg ƙ%;gsrjL|{5QA,^;Qx#b*6^? ]ܔ H#TQ݀`F6EQ49?kbr"/Ʃ4:1q1RF2::d'{NjaBE=&g8!=퇸}]kyn@ n@43n@fT7 pǻrD^P ύbREFQQKAG p8I(ZK_*4! -E ݀Z'Q3ͷ$;<ap68SDh J .P b 74 !\#+)͊=Eϙh |LW 84t r[J-b@#^)(݀PP%O^SVL%9,+0WF7 @CMNtT{Pلen@P$0%*W#gh18 ""*Xk"DXSD[ F+ʍvl_pZq !J;;!YFrv@0&!k `bw@mnB#D.jSiO օK'4 n' joZH| NMpvØЍ̃. 8Z*7Y+f)dк/;$䍙ۉ$| Ä$CjrNS$ӪTt8.hD0 a2DZf&ثn,٨0۹#=g{BzTBuͱ֐:ɧLǕu<'xƐ{VVZV%>F@,SfF+XJm+V'A,X\BatN1* TwB)OE.`cLV]g+τ(h0ϝJyLb5E7 `0W`=tL\!uG{hGI 4Q ^Fv(frpD/$ UZ#!ԀqG|P2y8Bv݀pj4*Q hvZ%5 T暉Hܐ=bLI}\&f'6$F o@k13nJP2!OTp⎶i]f^$$%dM$,$Mb1!~-XB4kIx- ZŠ%^4U<'?BK'|ggaMiҺpi]غp \=:E@JG(Bр"QCk HD2$E{D3 J*|CjʄKI7 &ZTցJҴ7^ FZiNX5!Aql/]]-S]* ԩI;jk֬v/"z4kR$/Z9-iE.L%[Hee8XFBѺ[xօ[هgvaMi)@QCZYtJf捑eAjN';(;U]BP= ` 8MԣSN/CPr_`liI—J/' `W"2>ھX׼)}.u+N3PʠR]]ffЧ>M>Mk3cVبF #bpĒ@>j|cZSQVO|'N2aHH < 9㽰|CvG R?5HE.96< +hL#Md'v=輤Pة9;Dã(8at" 518sB.d[~3KqP^ES\R9pQE "ƒ߆OGʷdXNIx=JꚘu}L>e+ )An@(*_v_ ~H‰+hګh9D!g,ՀQu|8(c4ȨZI|΋ g톄5q(]7 t%ℊq >H:U葃HrM-r1F-EGb{j10CEuS>F!F6LFD i~0fxԩl^(PpuN<9dQ FK#ZC13"'J*6+'>xr]PeGEb Y \ $7$=pD49AF)g-9!{Acvw9bi:!KQQ1lj1BRϡ\>QwHlO't %;NPt<g- Ε$< !zPh"'1z]1"iNv$vy9! "* C^( ͐51q^{ mOd9^9XxQU!wZX+_oX+Sc ^r܎F‡E/!Ê> .:)*R>i#U 7# 8Ԉ"BZIQ7bY4,EI5M %8 . .! Qpq2PuD'9!" ؆#Ҥ& 4t[u|eйt$zAk#49xt su6DNZ`{Mq;sa{4q~A ٟBMIt( UuSń']'Ct@Eo8PsfcŶ(8l^!\J"yh9X< (x\ā4 )ȋ_j7'zqĚP)tE8Y& - 9ԐB槢>@JZREkdspþCqSZ*xЉ9ǁhyq8Ԫ\!H\)pI/{Z;#Ն Ut!js, FVNꁖ`U,~n< 4R8̜p:3viȓSDPKsپ ^@ˋ3./oXlR N٩BqR)(U*+dK^`[Ȳ#<tىD<#@FQL|숇vI$* -NOCH#fuaBU)TpN(Xׅ yxCl/ W-hBv 9}O'X+),gI 52~>Z4YI#ྪȓo Ӯ>pғj9)CE$@|vFOyqQ2ZPg;^X(|(9K8 8KXl:y'8TPP8 bmO" 8Q2F;ᩪ6AGi'$n"aʓ!R!] F݀Pc袇օ+!jR 8uᎈsrvR몀|Ujqq|' 3̏= f(t(qɹR 1@B^dz- -5@c&QGi~=W>4n"OA2?n MP&AI8Wi~&Ba>7Yl@E+{8&ݼq%$9) ?"ͯ16P. `0?rAA0 AIÌ<.D\ {4?qm\åc;qyE4v i~0 ǪqޥBÊ%s! y:1&diL C2^O"(dkLr*_7 Ls\PթӤ~drvx^Kq n@8u Y:y14F/ .\93'vXA`( "33z=)tB7 0B[VoN"lp؏K](Û )ޚz 49g:f*'$_4,݀ۨuX:222ms %D@&R>R,0"$ECq`1@( 2g5.QaMeNPj$}*tYj0?C;@'qgN|J-c-LnB65aL[p&KKS+(& ؟eMԆTUc4H Ie/:He)NzZHB|Dt>J3J{(a_8'JSR u|H<ʘ q)%Tc{sF*L >bQT*yV ,KJI4P1|S@=ڐTϑhai$GR$k,yb*V:.։T~޴TT1LH*;$RE 9;w}xuҳA(o9гOQ-N,FQݲwq޵$EdL1XG܏]fJXɦ3bk)FjD3!'Wb"4Ԏe =nt5c\<,SK' YmXgJXiͲNzx 3p(qK?YU2$M X n4Qg1K<(!zN9 }<}B$M3 HJ!=KRBBDV QD^!J*7CkܡPο) 7L-,BȿyZGW klcC#u+B,g:PD}v;gm:D[7v͡ɞM:K~ SM-P2"MЁfPq'K'B/% !mCQ# Jf*Ms6TPB|TLIX]}#c"D5諡$4 :B4!H!}ChVQJk'z9ϖ"| CO=Am97 {߭~C`Y0&6I:no`*Ip4ȃ('CPB4Z~0e:y t,f) >z( d!"?5CvsZ-?^A@r&:Hn-r&TWכ3M\f5@.JG{g1Az1-DdׇJj8ASbÅBV,A0[vHJPG gu.B+6˘mF~ZeR(4 D7T2' '2 86 8 d>D?۷&p]N-WSw荩zm{ԔJ5"%n$qe$c,B^ўWzт- mCXl4PVZu8:>u94T.QggkصVUezݐ`rAbE*tfZ&^*s9w+B.Y95&"87hVxDi% 9ɽ(]l*[:<9neaA*m D12J!b }i5ґa!8Ԣ1xp9|*߱᭜ (P`.@(j${"W7-}ScMQfcݧmh2{tn4tE-I|R] SB &X8Z H^5s)W$*'W~K;OXc5E}x{-%[cXL{R Q]jm#޷FyMaUU*na"tG"z cy'rl6A(¦ iyAZDs?9Uw'6o$${ 9MB|dWJ*^vo@nD:#4MHc-.5qJ88kH" )MWG(   9pE|?J%\LFW"u?(tԉ׀j">~*aL=:83^ :T:a{e4!+rj񥟸ބZ'. _޳M5,!4)SvqsBo9Eb} oKlN`%uEU^8ꮘ[/S>`qL{u$%eӿkϡ/! hH7yP:ia)}.|rRULGI1>JT? pI A$zM 0lEtuD8$A9/ԑڈW#RN4X{BtDi1XYLցYhkGU PiY/R=]'[.H-Ty!Lg B*A\DN,U0KBDaj?L> J1sH L!ŇܞcJJ<ѻ?fb?sZ.BO4:X^Tӽ|@`=[d 6t l *îږ>j A''|imI!FR}#?3W'*hIӫ1#jqg䫻D'>!>-/ +=n_R<<F2*diNʨWLJ۽ UȲnw9⽣G,w~TWL46Z5Ij fԍ9~ ~o mZvQfJ oR;}<%i/Wln(^PWxk6ͺׅ(3T-*Wat*\A֯Kn(2{ !=َje4Lg{;Zr7vxE n`lBkXg0ϙH ,1R_J@i+d1 EGw *>Od._~T}HOGN4[kahr.$ l4({mk:ZAԈg$aGr'>٪l] !RšiF#!@f1UoX ;6.U~xw[Ng:V vh@\bJ2AE2٢\< (̋ᮼ*8QR {z*ߺ3-śĭ\& c\k,3`V8&`!5䮬O|!+ cpSBO=/JᵌwCkVK*H)k(~5ibI^4N̒ra>/?{-n#BHy O(ZX}t@ʒIqbOeÙu$Ų:>ZCaWp@#:!3<1'̈f({-  q g IM~ 0{/.8R'5 ek5;Ip|$]y9Mxtux<b˞U}s0K@|ZU#]j'0鮆ׄ5uJQs~Y(TJ6ZBLj'M2@d{N UрxT[gx%N0/?c.59GT?"I BN{VO+K.ΐ}JooELmPӦ6I 2FQhR͍I-2X[Lw\8iRז;%p1)? Mj<9Ѥw~1)*X8>!(E1zLΛ.MHXQ*.=W%FQpM~QraQM_tkәpvW5VXCko@9hw bwO6gcr;iOj#4/mҲRb욐N58 .cn^<}]l^ڧ'+S㘁0Yُ_DV>U;ft1wzIA0j `__^*|-Gڌ{ƼL}.54Q/,.cFGW\3^QIlťs2r*yVTۻ$ٛu2X @Xo)=zoX"2 V^eS7㮔UI 8ո)fkNty1Q-[疶z[],)aR @Hn[S#w GuBHQ ? "vҀ %K[ BfA}xط~qzXfC"]HP:/k'0JBxM_SRTaَEܙCw#F͞d3y<%8e'wC)4c8[8XX,x wC,j;D>x#! |L4[ɝcS31c"* :x}D"JKztCHqD5 ie5kз҉(Gi q)`5ރRC QsQa1 W!h}-ل*jiw#[bU}(=sR! d!&PA lz}&/brbCmv@{S0y|:KAچZ$ĴA_L7Tx{:p!/$C_MmM(IEPMBRu@?' e7e =D9D,Op '~եJdn.Bv,2;"Էܗ4@ #k&53pD[SmyQԠn8Xq9s.XӵitFY0#xNWc{؈VB^40rg/.Z+e8i1^m,x&R)&iKmkjQڌ|`=YVAvhTXGU}\OBٳTF84FE#.x)O5hxܖu3|Q;P%KD Cipl@Ll8t+6 n j ,`SۻxLi=_6Iq'|jp5U3x{qy@tEd`eApl usyڼ1 ,v=jNYOg0süF@`ysvuPd> lDgd|  4+&{=ò*luH,KoےÑJ|?떇ֱzSԷ9{ VAye;D<=@!.ծIA"pXoK׭tho]3$]#}Q!$ 6#PXGVX{z83'vëf 8ℵnpĻ wo5W&dñ9qڦ/Z5t3g`H $Iq N$;!JB }̆7a#蹥xb?ظͥ"2$gn' ,l0I@8Fԓ&YC-I ִ7hff,XCJeM:W|76=06 %Vm"Pb=_wsa"]m=4{% ƞ#iuy5؎42p)OJSW#EEY;'2 ɾ#aKj}8. M^Wί5ѹV\=1@P9:\A%PFÓ$f3̳Aș%*Dr bXuWe ZUp:"nrIKJbˣh09cw? 9\[xTBλ3(_~)Þ[+Y:b"g+*ٌK^JYɥH 7L鳚Qf߽8j i(;q@D- fg}T៉+o+#EBp=2@^4"FťR\H@uϓ`O֣C9ad2i`;4/l-c] n`hP F:7P WRcAu_o*Īaz z8Vk\6-#ia^"qٿHZ: 얓Ҽ]kϹh=ws{oHdz_6mN8 8;] ǿRVBgK\m׊_.!H%Aoc<Sx}PzqACD?ȉ.8|FKpxqC=td$hL'P+LgQ5]Q'gr wRwᝁ5;`6U%.ׅ]v_i6iZrDkKϥ/I |}{Ddr1Zo@9?Iv#O[w@QRx<9Ey:N DaR'3B1dt-OvblX '.AWvB.DmHdi2@Z0L2@[AD!|2t`0) ; 6PSC*q)R?+>/uFNjkHhX;Pf/e@5,JWci ampu118u4}HHɋs>7l=`ض6b ->K 2v_(R8n4zݽZMXC1+㔪c ]M6Ԏc 6@Idt lTWS̬8,q/:#ָA,>+Tߧ*_[YlXc~iC-I}%~) W*aE|8!]_O_i`55[Ihd@@ax뿾t|}y׳w7Խ9innY <,wô'񫧥bӥBPy5ЩjDQd'[64>RpX 7qlFV67rxG[F o;?p -4U[ʢns58pO(3NSie)edS_X{ԙgjc~/jliQ!UbHntҚ1I j7+9.bIuRt[%舺L(B۵-:"̬] N2_;H\ZݙGQ5 C2MLh~QܖP 2s2BBfR/BtigŸ8tnyǡ XJNoS,Jo휣/fZ>5ռz+OW Uj& 4;P1w<,߂]dF`HhߛR,.9.V<>N=Fr'O`ǂP`h4teȫ E&G|I^ c3.Z5-!K z[f xgVPuvG9+1]Dy h y>;[NBny2٘΅5g!PnY[h_` 4e[8Hve?D3|hs;9>홄!IK r뗘c05>y[y/6 ! R'.`aXfn.D$&=~ 1H)~;: )# m䚳FlڻҐT 0~A2ć &O,(Ꝗ3:ì;(!?}d̒2Өl>y~UBͯ*QZG] Hb/* ]p*W UUmzKi&A:Q5 A#ؾE1]:gԿciS {s(0` ҪNv3AI.4&Fж z 0^ ?A^U#| 0X0N4lez:Fކ0l:t-'Y;(g(bvΆ{O۱e@4A=>$@ -(4'IS\ JƹJ@;I+ 9DM#~ʢ-JJ : :fj$%pno6GpKF)$!&\u u[M&M87ڇ-H:xյ~B Vm`5t_aL yV:Ra//4*Rǡ4` qB@6m*Irڪ+c]2mbe1pBHφ 0w{i5g 8[oVPmfJe0D;fwPM !zw7Dϊ"MAnۛUluQ{.!T1JYN#+Yn> `Nuj|ToTlTf\3X_Yl(tFڠ_ey}qG̈*s\Y]X#: XR6TCf'o -wt'JZYourSՐ_>dcbv ʗFo2͈( D' .4r{zYJgyܻ\{X8/C@~9t6p+Ddbe 1ȋ1PW s(*M1tf8*DlĞ4֦)T x zTNzأ%݉IWUpN'U:^lh(ZTT^EBVdf$~dXCqq? 5 M#)?}?#NRXGz $1kU`8(&hz6B[[; W.#- efC&xGd]wRqs(Y^=bkЩ[>F"O @jUz H1'? mf_V3^ЈNcfrhsсsQ+?o 8 KtKK!`2JIz>B| (ga$YNǕ g q@,LMMҎ,9 Bi 36UA_ќFKEe)pHZ\axh\!_W%*@,QhuTRK$m!O&oR}'͑"<@w7I|Ugi&C^0a#oF|mCtb-^d gTl;G$DҜR{&i$"hsYvPve>pp\T?ʹy˿N-eVox_6m}ʩ& lZڢ)M؊˜ȼ{i<rAա(9KCN HN`ۻKumRH01pIht"ҥ}\$ iSi\~xyǸj.8A ܬK?vXJ]Aa霣*BK ~A7(]g_NӠ'W2DU8VtٍܿZRn1?EpDm .JHʈV;!_f?gTHA["Q4r0LݎKWҀ0;ui};w|Bwy\A&5$'&09F.l[-w!J@pUs(PʇOl9&Mv [RPa\>_A;kӽH`425@>~7L]y1V9+AEEh%mg6V \؃4VPW6H`%{.0yt K%-0ɼX Cd}")= q1VG$ ̼)H^;HB;̶A0O8[u(h Eن~nPްt \q6;xy v 6eSVדVxZ&aGMA1eGQ|pC΀u|u&uTPo| ޭ&-Pk"TZSdisA3Q-&kJ|'4!b5pعQ?CWQN$j W N6T| A?IwoKkO]Ɲ+ oKJU^clY"mQܒ4IO?*.ndۓʂYޯ]f17#<ɣ0o<ֿ)7Ǎz c ^!q r>|AC=W !aפKPĝWՂ0=p zFծc%.r 6,WnFYyBtUi.ABw=oQ-!UV7za}|/ (wz\Ty"[5 *AZ0W#r+V;bkIn D<'p 0, r,e! 0JWE<ƘWd\tb 7kz2JACqU!Uύ,[ n5< MERXsY% Pa>\e5:~-MCvV`sӝw͞S[1*Bd5֒ZS$H5 WFm9M?UԱ #+=Kl&8(&}Z]x| ^Z(rZƯ9\.꘶a|ޥnYz F1׾AMs oq63"b .2<ïE D-EZġ_MP!OS0Gdߨ"V=SF"#K1CtKw C{e7Fz("Y4Epz ?gxe_(j ED.(iESw6Q)(s605ZaxU3Zno7px"dwX_ES{<}kf䠛P.J&N*>(<``2WFx)q)>ɒL ?6YpP]"S`q'w (By@|܆ۄMJ y*:5W;B fX>ESS?6X‡։/=Q6FF |r#xTڀ!6ՠ}P@Q)eq}E<(G^DYlR s `D9e}G7e]5Yݖ-++S||mn`?D%D| N*r`K:o0jsgU]m<"$Ẳf(wSFɭ:Hut$JMkt!OCupv%lq Ɣnь!љz? Fΰ#Hd$]6m=O{AlT/4[DqW]24.omIoSWZTYAua,Ik(ЖN>- }+dn!Lbo󔞐{\^.908)n/o]uz]n4/WIl+W *L꫺4p׎&N㩤֝Sgw(^ L]{QEKy" ( CQ,dJ>f-C%iW9"Ol1bQ2\*Lhʓ:/ (x~Mv[+/2Y=+J<ش?Zc]C^==-8CjFE--< +SÀ8je<H Uac12k3KMD΀ZVz/ld!<6T;qt(D-X}ƖiVM`m#iJ!?VbDh#n!Hp*]%XjDZdYu,3Zcqa1 X3S?ShrxA:;Mbﱌ7 G}s=q&#^J3 c6Fj,\`t6 JӦ-fDu$%703ɎuG=Zr;]Ʀ< ՎT06J(56&yv~+*4!XD7}  ^ /v~=sox \I ݕ!VHD ۺ Wq6dĘ^$:k, 3銆q%JEi ﷊)D. n9|.Ȓm!BZB+B܎ .}5ď|$Vxb)B8\R:ёUbP ,tY TH\IDhHD%#b»K {@OvyO1ϰ޾Բ A./µsH9]->9 wufH)2|J?[DG4i)?{uhp>@fѷ.sbN5o!)Է:VG>"P\PQ 2KQ> Tu_!b)d^Jj4_W 6VPZ>1Q:Pڅb%`TWsN1Hvݤ߾+Ɛ*n)p}xnxPoF-I-MS?3vnFw[';O7i9{99ZgӔ5ޝm9-RG앑e#n;vq~kzyA% G I-wp77zv&a5?5U ։=%^LVǎ$ҔZ1QkA ǂǂcx6 xD!(T.JGtDF8m2$bɐ0P13 <)(Dm\بhD" & "3ҩtD%J #B$H4!:!@\`DÁsjLZg{/#cM&ixlh0ё4 ! F'ja.Ʌ$}x6QU Jb@Eq#GLԂ(ʇF@9 ’ CD-*# H $H A!"$.:LB>Pa)QG8`㰀"tT0@ǁN$_ .,:!3Q #!H@[ cDB%b@X$lT5L\hp2 ##c(Gp zDBeB I" @ Zd2a4D is` #Bsq`c`h0b&zlRl@ذ""R2Ȑ,> &,l֘l /C %D,ŸnI q?8`DMp` lCyPa"Q",EEFyS.^iڦ}.vrb[6D?2**#iafgzkw[7zmv.HSq:w]rU?44UMM6۽Ck律YTo?Mt˾D#{W kO2}g8%^F覆~Zx7_<|ʗʜxQ/>likƍnmϋ֟o}PC@-u749#TD|gvoRK:3>{߳_9-2ƽx&$UWdDkW =zwxjI-/Z=mv޿~}jHpgǯfxx!C  2DHDdsel{r5C̣o{v)Gٯ1M7wM_s?=kq%j2Fًm9ZY3o7/z9Zag;Ze{ oRKJGl7~Nd6ԒNw[-g|MϪZÏ|lvٜgi(gdܩn߇!sfdjaVݾN6fU돮Qf{cڷ*~h˖}~ު{jMxx_GZR'jcn}]_kdfmOsdn܆ʟݨmy.5IO#۳j^^"&?bm_F٘xgn~Q6o䴘gm)1'DHcxNDz' ?&جu|IGǏc2[2}8=87;c+[8I{n3>ʾxQjqPp0L&ji@,#J<рXFhJ,KD-MH ɅfY@{ t~Qhr5}itlLlL? an69/Kc_WS Éꇽ򜷙u[?ݭ6a4%[ZI=Ku65s4d7UWK_M|ÛӬ}ѕ xy_S ljjvi+AlνMjI{n$MjIy}jjMjqR̿mYWu_8jF8(7П9tѼ[.|}l46@(Ԫi47y|jR&8Hki۩fRKGdKT蜍ZDCcwRK[5odT 3"}b3*rb?Z>uܿ̿Tsڿ햹2 sY."D7U|2S-L9##*3wn[GlljIvguZӤgˉQzj5%"G塿yjMe[jM}nhlX.!@!\,|ĔyKƠ@(t(\R0=/5;; u=HMRomo:$96nvbM;y[YW-N*/9GֹřԒ]uRKWU_Uxwmn빷Z.[#řԒ֛OwRKe>mgc[8{vƪn4š, 9ǐ!0I$j{5R60.Rd c B@Qr^*GEi0Rk3 Z@2= 4!o xƘEA: T(3u` *4c(Hʠ{brXe,˟,n(z}>"s/>ײU3\}Η|ed SZ@:1A H r<>sW ܚ(N{W4Z^y*̷2F X s0qA0U˖!`-jrXɡZhφ "!5o^!"ɻ1Tu_8$ !t_E␉,Q~ # B',"ӊA(T,^T#C:4$YX}(_hcrLAߐg !gzOhy1W{CJ ES!KbU͔Z(5ꔐvrڗJ5#;5:L2sN%[~(vR`Jt%1]M%5bѨZ"ciRW~(lj;fDtڕx 1];"h&\?h4CI6qK!S<#hP?`נ'N!ątE{JIAJ :YidLM`N\ѝo [aU3gf @.;ґ³"IҪ)B蛄7=?ѿ5e,11QS% ڍEʎȨ唌xƅߕcFf5YzP|A6aF ob||`2?2z~wQP kr:,pg$yNXuƕ)ϑOd V^yC !y:%xy](y0D 2=e6SB3ܦioK-] cFI$cM.A/||Qg] XDP(m/dn !eJ<8[WbX i82!PzsO]jkwh$n1P |hz7ROPޡ2#!+ry9A[Hxh!&䃆շȯ&5)v$v/9Ե 0o< d$jhstN>DcTY8ARo3HXsiىbr.IbY~t~A.U4 & 16#{$̳SVhgj&ðAm"Q.VX|/e'bg9ŲbsBeprPyg5hplw"u7F@Ѩ7w2_n3v9Ebi$3 sp"KQeq~9/ۓfCzDJmX* 9t\ *ݹWUlք`jb3EF\\ 4s"bڨe&1uu!PoGFu\Xlƫڣ2嶪Jd#Fp=-3{ilA};*TGCd]d9 Z ;*PԴYKE _Tzܲ|xŔ"c>mgŬ+ĞӻrSgM3ITl9Q=˄cd,GZarKe>CVDr#C ]ϒ/vq(6W/E')5Ӵ?)^G`ovԤӕH 2eqIŴGpt BM-6lj4i8W"D2~*qLȊFyW܋lT)~AH5 %)hDqWDwI'#*=&Ll`7hvB]Yp 527jUA^^2ViF%/alP85t&iAȎPzXL#Vssr9 %_Dn hVݛ>T4>$eYob,q4/^>NY`aJ',akmPU$ceAWUS>ã9(9XV∸&kOa"&K%,1\Nۥ畏2t".DO0x x2/8TVWaBh$O0#2)\ȕν2A2WẔuS;ob)MT?zIF4G0(b:gWT!TG0>\j֓DC;JR8ϘXz sƧOq3xcՍZM/bzGX ˲뺛AޜܤzZeɁ4tP^b{F5~< SQ `VŭT$#k8/̨ЭlkrfyLHF/P9 iGTypZp՜Vxҗ67ݭiɢbװIF{2zrсpB@]0j,'p< ?U9Xμ\" !{h@{ iz6~d OaWOHM_%@(Pd+"H}Jli&uF{XK9t`|u)gÄoVY*hy ,X E:& nPjEni(fX.~tbSNij̮Qr]0 / W6Q "X;V2Gx{,dE@sIr|iTT+†[=C@ƿ[v[8(q[L_ x <\{oPw+>V4ũdѭbZ!m)?vׯ-rII>*/YQo^%N7;")FހM;h!ՌS_¸f7Awa|(/X*,6 ?@Uw`riJTSb3G 7-b(8\łEJP&M΍I_J skXI#B|AltKVuubwr:yJi7P*v;ǔy<_Vaٙy<|<ʞ?{A@@Ė}z[rk+(O]-5^ģݐѓ*/~SPsxf1DPQ3fAP"j,|~|&Q\-"E@Qeo):'m! F)YRӳiVTp0yΠN c/ &oLmR75HjZ}8)a<oWi}?X=mmX>4"&Ԡ0cR OSn 4 u;0팵/ Ỹ,ⲟ~f[4T[Szh]>F Ziy0(He%Kg!AH?$WӮJy,2CdlxwO=S̢&QlsB/.}8ey6Kx~3(p>4K #Ӯ0KF[+YZ#<+qZ}Abu ]KglDϴ7Dp"|t6#*6bX;9}h'L`/R&rPQ|1K L̲l@*@޼4 !0_B!'Cp\ vߧDy2U-6[gs^ߵ+gUA'(l]5řӦI^Ҩ/dXDAub (b鈅[3zY,>yѭ0]̩&y:& 0D!Ӌ0b`O $/Ck$61(՘[|897H\ ʪRC`L՜0W:\f!UB?z_g; 1ZhO!Q\?`jPmn فez/9[׊8UcB",PY q1e\s3ظ5=@$kE@%aܚq͞&&5Zثqk4w[J$|^uX\3F=Gq*ASw#SP'qMI58Vj+ݬR`Q4|t%iu E *oLY]+ _>E L(I nI3[ͻ4ü{6H2_=ֽrչ:ZW<גs?WJMnNʈ+T{IԼ 0xpue Bvi &[qiwaAx&D= /  =6G5`p 2C^rvQQHeȀ@ֆdt.8@D& D.`${k)b]'4cklg7ܸRYX_ 7P0)i8n{eoybɔQr%UP`U\/5Y##DU> endobj 31 0 obj [/View/Design] endobj 32 0 obj <>>> endobj 25 0 obj <> endobj 29 0 obj <>stream HVn@W!iB,!f>ݞ⩶_-Uu;{;쭺yWVLVkY<O;8E#zOx91&tx|zs+dr ViMEp`˧LP6K`⇥TEؘqPUr6$VϾZf8{;p'4U?+< Ydr. Q @.Fq9|1ج _ܸTa5z:Sճ/t6ɒfX QH  jѼQe`k_Ѝ2ɹ.>we1Sw%z;3æ1,mq%hB~5aS:V5$wIs$xWݳtpws:Cn [+b+/bѮXxAv."U&cmRheRdP2ՈxS2Faz<ŕ4&Ŀ[/*'mXuhQW^Exug>v3»3˞XDSZkCG|F.qO{~LG1)aT Z> endobj 33 0 obj <> endobj 34 0 obj <>stream HVy|Mַv 1^'Wb y<BJCTSOP*U5UQTW:QEUK)Ϝܷoڟ~kgoooE'粙ֆOO HE ȱFx' hRS* ˳nl"+qDZz>;ͱq{ $hNi'p5ӓf6Ўw%_;yg32O#?cbjFkYP < Ɯy)\*]RR;lD1_^఼/܆qg Ʃb KbƘ%eM- e?G<ɋFh5N2]tfI=yST1YP-f,z]*;EPxN}'ƉwN3lw / ^7|')q{jy{zR#O?|y>9G<6`({-,3 s6r]uS SD&Y䆻{żbsrlj0ow?yoK>9XO}>h??]_'Sd؜$3#QRC<u^;/x(kk~C}%=k{{׻ӻԛm󮷿7yx[&'1ײ-fӜ{9s.u+5<0LsWl}j[>kZk- ^[jGf@Z,li@> q9?Dm=W>2L%7,;߳,}_")GLE; ")ZtEwE 4L !M؆ث1%醃_;xq> `)%夂x$JSi)%IpIQ2AϚj)w>0ЇFLuS$z&,tnŒ[q-sQQeQ(ʈA5ԴmQC01`2^r*Kg g8oqW=nKDT .Kԑ*)qI]zhI(sVM4>E%|m"q n| hhհ:" wQl>D" hH*cLiaIS%3fK n1WZa|iyK Hg,N X'Ba ś2olT1؅l}2I: ]52qS$Yt5}0LUfI0 M$86mM{t4fkOuѡVtй:ST>13,31s<&ʌ5fo&LviMy@p%q:9>Tp g+9Gspp@ 1KP e-EZ5Kjq.|E\Krp%WiiPeFZZohY+rV:̷z pV&Z[junܮ5Ckq.Z{FqF3[cOp6_ژxKߚ0:8(E& A"X"ȣD6tIۙܛw=s9;?7*ިόrl܇ExŸ9_'18%ΈsqN'TEhr-oKMI߱7 NF{ P/WL1|3[=M4iMo5wI[UY[8lfffFi2.:Ǔ,펉yٙLo%C+#MFO}+-2kֆB{aZ1i{iǮ=~7u^bg^Fǹ"i@3|/]qi Ѳ+[?__'V}dc7 !w !QcEQ͑qbvc4 G>q$"Yy0#vqEjzka Q'0T/W(ԽsFY10^>('d "ىqrG<'=1"c嫜wCbHqi&p|Ft~fQt:? eᨡMS a$iԷ571YEf5^C9~d>J`B8DgEyIA~E{@#G),AU,GO) 1Ezpj S12ƪQ|;1# p{8yR׬&-utbGA'Q\l`p wg,0 bk{[#sԤkpǵI=^ǣr7éDI$\or<| # xݐ#h@ jx)ϸW~3ֆQ$j0K":tz2bּ9qo"_p-ov#*BQ8j51ک纗yyV>(3cXmYH ϕ"W eSldی-XU y aoU|~7ծr= "Wa|OGwOvh92IȲaUYG[1ʕ@]lT?B֋#éh 17Q;>FYvipQ1M.l95F69?bolܬ"~{(eV/*^~Ԟ,:tZm:ZSX˗Ge!z#NpyA&zi[7`Lmڎ)ʦnZWY![d9vXMѱe6AS`ht,8r12(O~ B}&lĭ!k:k臫ji;uc7?/QeB=*x_uw0f=Ę|||GuEf* G,9U捘+y^p uV &Z@=sDZv/4el͠nc9Vlw-c c؍Ah4R%Z[a&c6Y7E,aE)h4_A]n&`YHEFUX<ߥgIUDEn"= (VMM4$bDjC6-fs(BԪBzEzŋx ҃JonRiV)(|3{ b)u,4-bJk8'P} 1%1 q#&)[4gf~{?seg>|՞3y7[~3zLJ9XF0e& -P@¤ױ5yGjr7.P@b݂\ чO-{3|EGnnrt'b)¢)jfs]+b&8텨L>n`QNW endstream endobj 28 0 obj <>stream HUn1}# P)B+%H->s񮷁;vxۻ{;yWVLV|kNozVSjM_3L.* l f _0h16fbA2*\r6wG_\-?3!MUGo Ԅs&^,5! AcTaGQō*ZjʟMh$vw|Q̵_-̆xH *ѼQZ`kЋ²ʹ.?ױe1Sw!Wz^fMi~ق/LH|UPD=tqHL E͑{^R/kٺѧnmSΈ(;ZݻdT^ohҵDGN{̤ɠHԩd ŕ&_Y[/*i'ra%>stream HVn0W ]5nQ8] 顿Y(RYB05pfdr{k!wX&VcBmv,po)a"\JO Q`0|uD>θxOKu6t&Kb7g-5a6TZ?ғ5zE͢d-mBe{swn`b ̧Sz^5eMOo:R=ێu*=2caaE|c3G*ǥSy+P7_< eLׅW* E#>mͽQH #0kDKH8&:5m)'>#F}ARV8-.gz2W8e sZx׭mI1lpY`7R_hg'?S:g"o>aIIR0SEjIxw~ 7*1dRn?|Gl;q]t u߮! # endstream endobj 24 0 obj <>stream HUMo1ϯ{kBSJW" ̇ޔqFhyf}:`AXK5Yp2y~/;8E#nzO88)Yp\.@kp .&@lv?Z-2AٜW?L(ڌgnګ\MjWWp2| 9Đ!_hpG.K`Ȧp1*=2`GՍ~qWC?m=ۄg1,J[tplZ?xɚ\bQZi26²Vȹ;f1Ss)o=o݊&6mEVC&uұp!#Q#Qqg) ޞCntW)[OڋFL},mͽIH #0vDK 4&:k:R&O!cIٯGY%=pZ\I]mUp"' ־yhUne,5g v »9(}s+lTYI:NW@>/>b'߿y&&%JL\kMj4 \T<L戟_ /4 endstream endobj 22 0 obj [21 0 R] endobj 35 0 obj <> endobj xref 0 36 0000000004 65535 f 0000000016 00000 n 0000000147 00000 n 0000023191 00000 n 0000000000 00000 f 0000023270 00000 n 0000000000 00000 f 0000000000 00000 f 0000025899 00000 n 0000025971 00000 n 0000026111 00000 n 0000027705 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000023658 00000 n 0000024047 00000 n 0000024429 00000 n 0000067249 00000 n 0000075758 00000 n 0000024811 00000 n 0000075091 00000 n 0000067447 00000 n 0000068239 00000 n 0000074415 00000 n 0000073739 00000 n 0000067560 00000 n 0000025152 00000 n 0000067331 00000 n 0000067362 00000 n 0000068455 00000 n 0000068717 00000 n 0000075783 00000 n trailer <<933B8A92CC5FF842B9C1E5FDE3818E67>]>> startxref 75979 %%EOF ================================================ FILE: images/sticker_config.json.sample ================================================ { "sticker_dir": "classic_colorblind/webp/", "pack_name": "classic_colorblind_yourname", "sticker_emoji": "🃏" } ================================================ FILE: images/sticker_uploader.py ================================================ """ Script to upload a sticker pack to Telegram. """ import asyncio import json from pathlib import Path from telethon import TelegramClient from telethon.tl.functions.messages import GetAllStickersRequest, GetStickerSetRequest from telethon.tl.types import InputStickerSetID from telethon.utils import pack_bot_file_id IMAGES_DIR = Path(__file__).resolve().parent SESSION_NAME = "sticker_uploader" COLORS = ["r", "g", "b", "y"] NUMBERS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "draw", "reverse", "skip"] SPECIALS = ["colorchooser", "draw_four"] # Create this config file by copying the example file with open(IMAGES_DIR / "sticker_config.json", "r", encoding="utf-8") as f: sticker_config = json.load(f) STICKERS_DIR = IMAGES_DIR / sticker_config["sticker_dir"] # You must get your own api_id and api_hash from https://my.telegram.org, # under API Development, and put them into a file called "api_auth.json" with open(IMAGES_DIR / "api_auth.json", "r", encoding="utf-8") as f: api_auth = json.load(f) api_id = api_auth["api_id"] api_hash = api_auth["api_hash"] # Load the session from disk, or create a new one if it doesn't exist session_file = IMAGES_DIR / f"{SESSION_NAME}.session" session = str(session_file.absolute()) # Create the client and connect client = TelegramClient( session, api_id, api_hash, receive_updates=False, ) client.start() async def delete_if_existing(stickers_bot): sticker_sets = await client(GetAllStickersRequest(0)) for s in sticker_sets.sets: if s.short_name == sticker_config["pack_name"]: print(f'Deleting existing sticker set "{s.short_name}" ({s.id})') await client.send_message(stickers_bot, "/delpack") await client.send_message(stickers_bot, s.short_name) break async def create_sticker_set(stickers_bot): """ Create a new sticker set by conversing with @Stickers. """ await client.send_message(stickers_bot, "/newpack") await client.send_message(stickers_bot, sticker_config["pack_name"]) async def get_sticker_set(): """ Get the sticker set that we just created. """ sticker_sets = await client(GetAllStickersRequest(0)) for s in sticker_sets.sets: if s.short_name == sticker_config["pack_name"]: sticker_set_ref = s break else: raise Exception(f'Could not find sticker set "{sticker_config["pack_name"]}"') sticker_set = await client( GetStickerSetRequest( InputStickerSetID(id=sticker_set_ref.id, access_hash=sticker_set_ref.access_hash), hash=0, ) ) return sticker_set async def get_sticker_ids(sticker_set): """ Get the sticker file IDs of the stickers in the given sticker set, mapped to their sticker ID. """ sticker_ids = [] for special in SPECIALS: sticker_ids.append(special) for color in COLORS: for number in NUMBERS: sticker_ids.append( f"{color}_{number}", ) stickers = {} for sticker_id, document in zip(sticker_ids, sticker_set.documents): file_id = pack_bot_file_id(document) stickers[sticker_id] = file_id return stickers async def save_sticker_ids(): # Get the sticker ids sticker_set = await get_sticker_set() stickers = await get_sticker_ids(sticker_set) # Save the stickers to a file with open(IMAGES_DIR / f"sticker_ids_{sticker_config['pack_name']}.json", "w") as f: json.dump(stickers, f, indent=4) async def upload_sticker(entity, sticker_path): """ Uploads a sticker to the current conversation. """ message = await client.send_file( entity, sticker_path, force_document=True, ) await client.send_message(entity, sticker_config["sticker_emoji"]) return message async def main(): me = await client.get_me() print(f"Logged in as {me.username} ({me.id})") BOT_USERNAME = "Stickers" stickers_bot = await client.get_entity(BOT_USERNAME) ### Uncomment if you missed the prompt to add the sticker pack to your account ### # await save_sticker_ids() # return # Delete the existing sticker set if it exists await delete_if_existing(stickers_bot) await asyncio.sleep(1) # Create a new sticker set await create_sticker_set(stickers_bot) # Upload the stickers async def do_sticker_upload(path): await upload_sticker(stickers_bot, path) await asyncio.sleep(1) for special in SPECIALS: await do_sticker_upload( STICKERS_DIR / f"{special}.webp", ) for color in COLORS: for number in NUMBERS: await do_sticker_upload( STICKERS_DIR / f"{color}_{number}.webp", ) await client.send_message(stickers_bot, "/publish") await client.send_message(stickers_bot, "/skip") await client.send_message(stickers_bot, sticker_config["pack_name"]) # Wait for the user to add the sticker pack to their account print("Please add the sticker pack to your account by clicking the link posted by @Stickers") print(f"https://t.me/addstickers/{sticker_config['pack_name']}") await asyncio.sleep(10) # Save the sticker IDs to a file await save_sticker_ids() if __name__ == "__main__": with client: client.loop.run_until_complete(main()) ================================================ FILE: internationalization.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import gettext from functools import wraps from locales import available_locales from pony.orm import db_session from user_setting import UserSetting from shared_vars import gm GETTEXT_DOMAIN = 'unobot' GETTEXT_DIR = 'locales' class _Underscore(object): """Class to emulate flufl.i18n behaviour, but with plural support""" def __init__(self): self.translators = { locale: gettext.GNUTranslations( open(gettext.find( GETTEXT_DOMAIN, GETTEXT_DIR, languages=[locale] ), 'rb') ) for locale in available_locales.keys() if locale != 'en_US' # No translation file for en_US } self.locale_stack = list() def push(self, locale): self.locale_stack.append(locale) def pop(self): if self.locale_stack: return self.locale_stack.pop() else: return None @property def code(self): if self.locale_stack: return self.locale_stack[-1] else: return None def __call__(self, singular, plural=None, n=1, locale=None): if not locale: locale = self.locale_stack[-1] if locale not in self.translators.keys(): if n == 1: return singular else: return plural translator = self.translators[locale] if plural is None: return translator.gettext(singular) else: return translator.ngettext(singular, plural, n) _ = _Underscore() def __(singular, plural=None, n=1, multi=False): """Translates text into all locales on the stack""" translations = list() if not multi and len(set(_.locale_stack)) >= 1: translations.append(_(singular, plural, n, 'en_US')) else: for locale in _.locale_stack: translation = _(singular, plural, n, locale) if translation not in translations: translations.append(translation) return '\n'.join(translations) def user_locale(func): @wraps(func) @db_session def wrapped(update, context, *pargs, **kwargs): user = _user_chat_from_update(update)[0] with db_session: us = UserSetting.get(id=user.id) if us and us.lang != 'en': _.push(us.lang) else: _.push('en_US') result = func(update, context, *pargs, **kwargs) _.pop() return result return wrapped def game_locales(func): @wraps(func) @db_session def wrapped(update, context, *pargs, **kwargs): user, chat = _user_chat_from_update(update) player = gm.player_for_user_in_chat(user, chat) locales = list() if player: for player in player.game.players: us = UserSetting.get(id=player.user.id) if us and us.lang != 'en': loc = us.lang else: loc = 'en_US' if loc in locales: continue _.push(loc) locales.append(loc) result = func(update, context, *pargs, **kwargs) while _.code: _.pop() return result return wrapped def _user_chat_from_update(update): user = update.effective_user chat = update.effective_chat if chat is None and user is not None and user.id in gm.userid_current: chat = gm.userid_current.get(user.id).game.chat return user, chat ================================================ FILE: locales/__init__.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from .available import available_locales ================================================ FILE: locales/available.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """Defines a dict of all available locales to the language name""" OFFSET = 127462 - ord("A") def flag(code): return chr(ord(code[0]) + OFFSET) + chr(ord(code[1]) + OFFSET) available_locales = { "en_US": flag("US") + " English (US)", "de_DE": flag("DE") + " Deutsch (DE)", "es_ES": flag("ES") + " Español (ES)", "id_ID": flag("ID") + " Bahasa Indonesia", "it_IT": flag("IT") + " Italiano", "pt_BR": flag("BR") + " Português Brasileiro", "ru_RU": flag("RU") + " Русский язык", "tr_TR": flag("TR") + " Türkçe", "zh_CN": flag("CN") + " 中文(简体)", "zh_HK": flag("HK") + " 廣東話", "zh_TW": flag("TW") + " 中文(台灣)", "ca_CA": flag("ES") + " Catalan", "ml_IN": flag("IN") + " Malayalam", "vi_VN": flag("VN") + " Việt Nam", "hn_IN": flag("IN") + " Hindi", "uz_UZ": flag("UZ") + " O'zbek", } ================================================ FILE: locales/ca_CA/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 17:32-0600\n" "PO-Revision-Date: 2016-05-22 21:20-0600\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: ca\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Segueix aquests passos:\n" "\n" "1. Afegeix aquest bot a un grup\n" "2. En el grup, crea una partida nova amb /new o uneixta a una partida iniciada amb /" "join\n" "3. Després que almenys dos jugadors s'han unit, comença la partida " "amb /start\n" "4. Escriu @unobot en la caixa de text i pressiona " "espai o fes clic en el text via @unobotal costat " "dels missatges. Veuràs les teves cartes (algunes de to grisenc), qualsevol opció " "addicional com robar i un ? per a veure l'estat actual de la partida." "Les cartes grisenques són aquelles que no poden utilitzar-se en el " "moment. Pressiona una opció per executar l'acció seleccionada.\n" "Els jugadors poden unir-se en qualsevol moment. Per a abandonar una " "partida, utilitza /leave. Si un jugador triga més de 90 segons a jugar, " "pots utilitzar /skip para saltar el seu torn.\n" "\n" "Idioma i altres ajustos: /settings\n" "Altres comandos (només el creador de la partida pot utilitzar-los):\n" "/close - Tancar la sala\n" "/open - Obrir la sala\t\n" "/enable_translations - Traduir els missatges importants a tots els idiomes " "disponibles en la partida\n" "/disable_translations - Utilitzar l'idioma per defecte (anglès) \n" "\n" "Experimental: Per a jugar en múltiples grups al mateix temps. " "Pressiona el botó Current game: ... i selecciona el grup en " "el qual desitges realitzar una jugada.\n" "Si t'agrada el bot rate me, uneix-te al canal " "d'actualitzacions i compra el joc de cartes UNO." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Aquest bot és programari lliure i està llicenciat sota l'AGPL. El codi està disponible " "aquí: \n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "Nova partida creada! Uniu-vos a la partida amb /join i comenceu amb /start" #: bot.py:152 msgid "The lobby is closed" msgstr "La sala està tancada." #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "" "En aquest moment no hi ha cap partida en marxa. Crea una partida nova amb /new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Ja t'has unit a la partida. Inicia-la amb /start" #: bot.py:167 msgid "Joined the game" msgstr "{name} s'ha unit a la partida" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "No estàs jugant a cap partida en aquest grup." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "Partida acabada!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Okay. Següent jugagor: {name}" #: bot.py:219 msgid "Game not found." msgstr "Partida no trobada." #: bot.py:223 msgid "Back to last group" msgstr "Torna a l'últim grup" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Si us plau canvia al grup que has seleccionat!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Grup seleccionat: {group}\n" "Assegura't d'haver canviat al grup correcte!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Eliminant {name} de la partida." #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "No hi ha cap partida en aquest xat. Crea una nova amb /new." #: bot.py:278 msgid "The game has already started" msgstr "La partida ja ha començat." #: bot.py:281 msgid "At least {minplayers} players must /join the game before you can start it" msgstr "" "Abans de començar la partida, al menys {minplayers} jugadors han de unir-se utilitzant /join." #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Primer jugador: {name}\n" "Utilitza /close per evitar que la gent s'afageixi a la partida.\n" "Habilita multi-traduccions amb /enable_translations." #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Selecciona el grup en el qual vols jugar." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "No hi ha cap partida en execució en aquest xat." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "Sala tancada. No hi ha més jugadors que puguin unir-se a aquesta partida." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Només el creador del joc ({name}) pot fer-ho." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" "Multi-traduccions activades. Desactiva-les amb /disable_translations." #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "Multi-traduccions desactivades. Ativales amb /enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "Sala oberta. Els jugadors nous poden unir-se a la partida amb /join." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "No estàs a cap partida en aquest xat." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Si us plau, espera un segon." msgstr[1] "Si us plau, espera {time} segons." #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "El temps d'espera per saltar aquest jugar s'ha reduit a {time} " "segon.\n" "Següent jugador: {name}" msgstr[1] "" "El temps d'espera per saltar aquest jugador s'ha reduit a {time} " "segons.\n" "Següent jugador: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "S'ha omès quatre vegades seguides {name1} i se l'ha eliminat de la " "partida.\n" "Següent jugador: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "S'ha omès quatre vegades seguides {name1} i se l'ha eliminat de la " "partida.\n" "Partida finalitzada." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Totes les noticies aquí: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "Partida actual: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} ha intentat fer trampes." #: bot.py:562 msgid "Next player: {name}" msgstr "Següent jugador: {name}." #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "El temps d'espera per a {name} s'ha reiniciat a {time} segons" #: bot.py:585 msgid "Please choose a color" msgstr "Si us plau, selecciona un color" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} ha guanyat!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "No hi ha més cartes al plat." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Era un fanal! {name} reb 4 cartes." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} no ha fet cap fanal!, {name2} reb 6 cartes." #: results.py:38 msgid "Choose Color" msgstr "Selecciona un color" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Última carta (prem per a veure l'estat de la partida):" msgstr[1] "Cartes (prem per a veure l'estat de la partida):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Jugador actual: {name}." #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Última carta: {card}." #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Jugador: {player_list}" msgstr[1] "Jugadors: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} carta)" msgstr[1] "{name} ({number} cartes)" #: results.py:81 msgid "You are not playing" msgstr "No estàs jugant." #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "No estàs jugant en aquest moment. Utilitza /new Per començar una partida o /" "join si ja hi ha una partida en curs dins d'aquest grup." #: results.py:95 msgid "The game wasn't started yet" msgstr "La partida encara no ha començat." #: results.py:97 msgid "Start the game with /start" msgstr "Comença la partida amb /start." #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Agafant {number} carta del piló." msgstr[1] "Agafant {number} cartes del piló." #: results.py:136 msgid "Pass" msgstr "Passar" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Es un fanal!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Si us plau, edita els teus ajustos en un xat privat amb el bot." #: settings.py:49 msgid "Enable statistics" msgstr "Activar les estadístiques" #: settings.py:51 msgid "Delete all statistics" msgstr "Esborrar les estadístiques" #: settings.py:53 msgid "Language" msgstr "Idioma" #: settings.py:54 msgid "Settings" msgstr "Configuració" #: settings.py:68 msgid "Enabled statistics!" msgstr "Estadístiques activades!" #: settings.py:70 msgid "Select locale" msgstr "Selecciona la teva llengua" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Estadístiques esborrades i desactivades! " #: settings.py:94 msgid "Set locale!" msgstr "Llengua seleccionada!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "Les teves estadístiques no estan activades. Utilitza /settings en un xat privat amb el " "bot per activarles." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} partida jugada." msgstr[1] "{number} partides jugades." #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} primer lloc ({percent}%)." msgstr[1] "{number} primers llocs ({percent}%)." #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} carta jugada." msgstr[1] "{number} cartes jugades." #: utils.py msgid "{emoji} Green" msgstr "{emoji} Vert" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Vermell" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Blau" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Groc" ================================================ FILE: locales/compile.sh ================================================ #!/bin/bash # This script compiles the unobot.po file for all languages. if [ ${PWD##*/} = "locales" ]; then function compile { cd './'$1'/LC_MESSAGES/' msgfmt unobot.po -o unobot.mo cd ../../ }; else echo 'Only execute this in the "locales" directory' exit 1; fi # Deutsch compile de_DE # Spanish compile es_ES # Indonesian compile id_ID # Italian compile it_IT # Portuguese compile pt_BR # Russian compile ru_RU # Turkish compile tr_TR # Simplified Chinese compile zh_CN # Chinese (Honk Kong) compile zh_HK # Traditional Chinese compile zh_TW # Catalan compile ca_CA #Malayalam compile ml_IN # Việt Nam compile vi_VN # Hindi compile hn_IN # Uzbek compile uz_UZ ================================================ FILE: locales/de_DE/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # Jannes Höke , 2016. # #: bot.py:224 #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-19 22:38+0200\n" "PO-Revision-Date: 2016-05-21 21:16+0200\n" "Last-Translator: Jannes Höke \n" "Language-Team: Deutsch \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: utf-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 2.91.6\n" #: bot.py:60 msgid "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. " "Use /notify_me to receive a private message when a new game is started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all " "languages spoken in a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Folge den folgenden Schritten:\n" "\n" "1. Füge diesen Bot einer Gruppe hinzu\n" "2. In einer Gruppe kannst du mit /new ein neues Spiel erstellen und mit /" "join einem bestehenden Spiel beitreten\n" "3. Nachdem mindestens zwei Spieler beigetreten sind, starte das Spiel mit /" "start\n" "4. Gib @unobot in deine Chatbox ein und drücke die " "Leertaste, oder tippe auf den via @unobot-Text " "neben oder über den Nachrichten. Du siehst deine Karten (einige in grau), " "zusätzliche Optionen wie z. B. Ziehen, und ein ? um den Infos über " "das laufende Spiel anzuzeigen. Die grauen Karten kannst du gerade " "nicht spielen. Tippe eine der Optionen oder Karten an, um diese " "Aktion auszuführen bzw. die Karte zu spielen. \n" "Spieler können dem Spiel jederzeit beitreten. Um das Spiel zu verlassen, " "benutze /leave. Wenn ein Spieler länger als 90 Sekunden braucht, kannst du " "ihn mit /skip überspringen. " "Benutze /notify_me, um über ein neues Spiel in dieser Gruppe per privater " "Nachricht informiert zu werden.\n" "\n" "Sprache und andere Einstellungen: /settings\n" "Weitere Kommandos (nur Spiel-Ersteller):\n" "/close - Lobby schließen\n" "/open - Lobby öffnen\n" "/enable_translations - Übersetze relevante Texte in alle im Spiel gesprochenen" " Sprachen\n" "/disable_translations - Verwende Englisch für diese Texte\n" "\n" "Experimentell: Spiele in mehreren Gruppen gleichzeitig. Um die " "Gruppe, in der du deine Karte spielen willst, auszuwählen, tippe auf den " "Aktuelles Spiel: ...-Button.\n" "Wenn dir dieser Bot gefällt, bewerte ihn, tritt dem News-Channel bei und kaufe ein UNO Kartenspiel." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Dieser Bot ist Freie Software und lizenziert unter der AGPL. Der Quellcode " "ist hier verfügbar:\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "Neues Spiel erstellt! Tritt dem Spiel mit /join bei und starte es mit /start" #: bot.py msgid "Send this command in a group to be notified when a new game is started there." msgstr "Benutze diesen Befehl in einer Gruppe, um über das nächste neu eröffnete " "Spiel informiert zu werden." #: bot.py msgid "A new game has been started in {title}" msgstr "In der Gruppe {title} wurde gerade ein neues Spiel gestartet" #: bot.py:152 msgid "The lobby is closed" msgstr "Die Lobby ist geschlossen" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "Zur Zeit läuft kein Spiel. Erstelle ein neues mit /new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Du bist dem Spiel bereits beigetreten. Starte es mit /start" #: bot.py:167 msgid "Joined the game" msgstr "Spiel beigetreten" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "Du spielst in keinem Spiel in dieser Gruppe." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "Spiel beendet!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Okay. Nächster Spieler: {name}" #: bot.py:219 msgid "Game not found." msgstr "Spiel nicht gefunden." #: bot.py:223 msgid "Back to last group" msgstr "Zurück zur letzten Gruppe" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Bitte wechsele zu der Gruppe, die du gewählt hast!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Ausgewählte Gruppe: {group}\n" "Stell sicher, dass du in die richtige Gruppe wechselst!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Entferne {name} aus dem Spiel" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" "In dieser Gruppe gibt es kein laufendes Spiel. Erstelle ein neues mit /new" #: bot.py:278 msgid "The game has already started" msgstr "Das Spiel hat bereits begonnen" #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "Es müssen mindestens zwei Spieler dem Spiel beitreten, bevor du es " "starten kannst" #: bot.py:297 #, python-format, fuzzy msgid "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Erster Spieler: {name}\n" "Benutze /close, um zu verhindern, dass weitere Spieler beitreten." #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Bitte wähle die Gruppe, in der du spielen willst." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "In dieser Gruppe läuft gerade kein Spiel." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "" "Lobby geschlossen. Diesem Spiel können keine weiteren Spieler beitreten." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Dies kann nur der Ersteller des Spiels ({name}) tun." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Multi-Übersetzungen aktiviert. Deaktivieren mit /disable_translations" #: bot.py:377 #, python-format msgid "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Multi-Übersetzungen deaktiviert. Aktiviere sie wieder mit " "/enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "Lobby geöffnet. Neue Spieler können nun beitreten." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "Du spielst kein Spiel in dieser Gruppe." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Bitte warte {time} Sekunde" msgstr[1] "Bitte warte {time} Sekunden" #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "Die Wartezeit um diesen Spieler zu überspringen wurde auf {time} " "Sekunde reduziert.\n" "Nächster Spieler: {name}" msgstr[1] "Die Wartezeit um diesen Spieler zu überspringen wurde auf {time} " "Sekunden reduziert.\n" "Nächster Spieler: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} wurde vier Mal hintereinander übersprungen und daher aus dem Spiel " "entfernt.\n" "Nächster Spieler: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name1} wurde vier Mal hintereinander übersprungen und daher aus dem Spiel " "entfernt.\n" "Das Spiel wurde beendet." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Alle News hier: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {game}" msgstr "Aktuelles Spiel: {game}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} hat versucht zu schummeln!" #: bot.py:562 msgid "Next player: {name}" msgstr "Nächster Spieler: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "Die Wartezeit für {name} wurde auf 90 Sekunden zurückgesetzt." #: bot.py:585 msgid "Please choose a color" msgstr "Bitte wähle eine Farbe" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} hat gewonnen!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "Es sind keine Karten mehr im Deck." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Bluff gecalled! {name} bekommt 4 Karten." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} hat nicht geblufft! {name2} bekommt 6 Karten." #: results.py:38 msgid "Choose Color" msgstr "Wähle Farbe" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Letzte Karte (tippe für Spielinfo):" msgstr[1] "Karten (tippe für Spielinfo):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Aktueller Spieler: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Letzte Karte: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Spieler: {player_list}" msgstr[1] "Spieler: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} Karte)" msgstr[1] "{name} ({number} Karten)" #: results.py:81 msgid "You are not playing" msgstr "Du spielst gerade nicht" #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "Du spielst gerade nicht. Benutze /new um ein neues Spiel zu starten oder /" "join, um einem bestehenden Spiel beizutreten." #: results.py:95 msgid "The game wasn't started yet" msgstr "Das Spiel wurde noch nicht gestartet." #: results.py:97 msgid "Start the game with /start" msgstr "Starte das Spiel mit /start" #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Ich ziehe {number} Karte" msgstr[1] "Ich ziehe {number} Karten" #: results.py:136 msgid "Pass" msgstr "Passe" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Ich glaube du bluffst!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Bitte ändere deine Einstellungen in einem privaten Chat mit dem Bot." #: settings.py:49 msgid "Enable statistics" msgstr "Statistiken aktivieren" #: settings.py:51 msgid "Delete all statistics" msgstr "Alle Statistiken löschen" #: settings.py:53 msgid "Language" msgstr "Sprache" #: settings.py:54 msgid "Settings" msgstr "Einstellungen" #: settings.py:68 msgid "Enabled statistics!" msgstr "Statistiken aktiviert!" #: settings.py:70 msgid "Select locale" msgstr "Bitte Sprache auswählen" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Alle Statistiken gelöscht und deaktiviert!" #: settings.py:94 msgid "Set locale!" msgstr "Sprache gesetzt!" #: simple_commands.py msgid "You did not enable statistics. Use /settings in " "a private chat with the bot to enable them." msgstr "Du hast die Spiel-Statistiken nicht aktiviert. Aktiviere sie, mit dem " "/settings-Kommando in einem privaten Chat mit dem Bot." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} gespieltes Spiel" msgstr[1] "{number} gespielte Spiele" #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} mal 1. Platz ({percent}%)" msgstr[1] "{number} mal 1. Platz ({percent}%)" #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} gespielte Karte" msgstr[1] "{number} gespielte Karten" #: utils.py msgid "{emoji} Green" msgstr "{emoji} Grün" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Rot" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Blau" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Gelb" ================================================ FILE: locales/es_ES/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 17:32-0600\n" "PO-Revision-Date: 2016-05-22 21:20-0600\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: es\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Sigue estos pasos:\n" "\n" "1. Añade este bot a un grupo\n" "2. En el grupo, crea una partida nueva con /new o únete a una iniciada con /" "join\n" "3. Después de que al menos dos jugadores se han unido, comienza la partida " "con /start\n" "4. Escribe @unobot en la caja de texto y presiona " "espacio o haz clic en el texto via @unobotjunto a " "los mensajes. Verás tus cartas (algunas de tono grisáceo), cualquier opción " "adicional como robar y un ? para ver el estado actual de la partida. " "Las cartas grisáceas son aquellas no pueden usarse en el " "momento. Presiona una opción para ejecutar la acción seleccionada.\n" "Los jugadores pueden unirse en cualquier momento. Para abandonar una " "partida, usa /leave. Si un jugador se tarda más de 90 segundos en jugar, " "puedes usar el /skip para saltar ese jugador.\n" "\n" "Idioma y otros ajustes: /settings\n" "Otros comandos (solo el creador de la partida puede usar):\n" "/close - Cerrar sala\n" "/open - Abrir sala\t\n" "/enable_translations - Traducir mensajes importantes a todos los idiomas " "disponibles en la partida\n" "/disable_translations - Usar el idioma por defecto (idioma inglés) \n" "\n" "Experimental: Para jugar en múltiples grupos al mismo tiempo. " "Presiona el botón Current game: ... y selecciona el grupo en " "el que deseas realizar una jugada.\n" "Si te gusta el bot rate me, únete al canal " "de actualizaciones y compra el juego de cartas UNO." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Este bot es Software Libre y esta licenciado bajo AGPL. El código esta " "disponible aquí:\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "¡Nueva partida creada! Únete con /join. Cuando estéis todos listos, haz /start para empezar." #: bot.py:152 msgid "The lobby is closed" msgstr "La sala está cerrada." #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "" "No hay ninguna partida en curso. Crea una partida con /new." #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Ya te uniste a esta partida. Comienza la partida con /start." #: bot.py:167 msgid "Joined the game" msgstr "Te uniste a la partida." #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "No estas jugando a una partida en este grupo." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "¡Fin de la partida!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Okay. Siguiente Jugador: {name}" #: bot.py:219 msgid "Game not found." msgstr "Partida no encontrada." #: bot.py:223 msgid "Back to last group" msgstr "De vuelta al último grupo." #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "¡Por favor ve al grupo seleccionado!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Grupo seleccionado: {group}\n" "¡Asegúrate de haber cambiado al grupo correcto!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Eliminando a {name} de la partida." #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "No hay ninguna partida en curso en este chat. Crea una nueva con /new." #: bot.py:278 msgid "The game has already started" msgstr "La partida ya ha comenzado." #: bot.py:281 msgid "At least {minplayers} players must /join the game before you can start it" msgstr "" "Antes de iniciar la partida, al menos {minplayers} jugadores deben unirse usando /join." #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Primer Jugador: {name}\n" "Usa /close para evitar que la gente se una a la partida.\n" "Habilita multi-traducciones con /enable_translations." #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Elige el grupo en el que deseas jugar." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "No hay ninguna partida en curso en este grupo." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "Sala cerrada. No podrán unirse más jugadores a la partida." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Solo el creador de la partida ({name}) puede hacer eso." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" "Multi-traducciones habilitadas. Deshabilítalas con /disable_translations." #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "Multi-traducciones deshabilitadas. Habilítalas de nuevo con /" "enable_translations." #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "Sala abierta. Ahora pueden unirse nuevos jugadores usando /join." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "No estás jugando una partida en este chat." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Por favor, espere un segundo." msgstr[1] "Por favor, espere {time} segundos." #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "El tiempo de espera para saltar al jugador actual se ha reducido {time} " "segundo.\n" "Siguiente jugador: {name}" msgstr[1] "" "El tiempo de espera para saltar al jugador actual se ha reducido {time} " "segundos.\n" "Siguiente jugador: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} fue saltado cuatro veces consecutivas y ha sido eliminado de la " "partida.\n" "Siguiente Jugador {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name} fue saltado cuatro veces consecutivas y ha sido eliminado de la " "partida.\n" "Partida finalizada." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Todas las noticias aquí: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "Partida actual: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} intentó hacer trampa." #: bot.py:562 msgid "Next player: {name}" msgstr "Siguiente Jugador: {name}." #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "El tiempo de espera para {name} se ha reiniciado a {time} segundos" #: bot.py:585 msgid "Please choose a color" msgstr "Por favor, selecciona un color" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "¡{name} ganó!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "No hay más cartas en la baraja." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "¡Era un farol! {name} recibe 4 cartas." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "¡{name1} no se había tirado un farol!, {name2} recibe 6 cartas." #: results.py:38 msgid "Choose Color" msgstr "Selecciona un color" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Última carta (pulsa para ver el estado de la partida):" msgstr[1] "Cartas (pulsa para ver el estado de la partida):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Jugador actual: {name}." #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Última carta: {card}." #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Jugador: {player_list}" msgstr[1] "Jugadores: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} carta)" msgstr[1] "{name} ({number} cartas)" #: results.py:81 msgid "You are not playing" msgstr "No estás jugando." #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "No estás jugando en este momento. Usa /new para comenzar una partida o /" "join si hay una partida en curso en este grupo." #: results.py:95 msgid "The game wasn't started yet" msgstr "La partida no ha comenzado todavía." #: results.py:97 msgid "Start the game with /start" msgstr "Comienza la partida con /start." #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Robando {number} carta." msgstr[1] "Robando {number} cartas." #: results.py:136 msgid "Pass" msgstr "Pasar" #: results.py:148 msgid "I'm calling your bluff!" msgstr "¡Es un farol!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Por favor, edita tus ajustes en un chat privado con el bot." #: settings.py:49 msgid "Enable statistics" msgstr "Habilitar estadísticas" #: settings.py:51 msgid "Delete all statistics" msgstr "Borrar estadísticas" #: settings.py:53 msgid "Language" msgstr "Idioma" #: settings.py:54 msgid "Settings" msgstr "Ajustes" #: settings.py:68 msgid "Enabled statistics!" msgstr "¡Estadísticas habilitadas!" #: settings.py:70 msgid "Select locale" msgstr "Selecciona tu idioma" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "¡Estadísticas borradas y deshabilitadas! " #: settings.py:94 msgid "Set locale!" msgstr "¡Idioma seleccionado!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "Tus estadísticas no están habilitadas. Usa /settings en un chat privado con el " "bot para habilitarlas." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} partida jugada." msgstr[1] "{number} partidas jugadas." #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} primer lugar ({percent}%)." msgstr[1] "{number} primeros lugares ({percent}%)." #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} carta jugada." msgstr[1] "{number} cartas jugadas." #: utils.py msgid "{emoji} Green" msgstr "{emoji} Verde" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Rojo" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Azul" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Amarillo" ================================================ FILE: locales/hn_IN/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 17:32-0600\n" "PO-Revision-Date: 2016-05-22 21:20-0600\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: hn_IN\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "इन चरणों का पालन करें:\n" "\n" "1. इस बॉट को किसी समूह में जोड़ें\n" "2. समूह में, के साथ एक नया गेम बनाएँ /new या इसके साथ एक पहल में शामिल हों / join" "join\n" "3. कम से कम दो खिलाड़ियों के शामिल होने के बाद, खेल शुरू होता है। " "के साथ /start\n" "4. लिखता @unobot पाठ बॉक्स में और दबाएँ " "अन्तरिक्षया पाठ पर क्लिक करें via @unobotके साथ-साथ " "संदेश। आपको अपने कार्ड (कुछ भूरे रंग के), कोई भी विकल्प दिखाई देगा। " "चोरी और चोरी के रूप में अतिरिक्त ? खेल की वर्तमान स्थिति देखने के लिए. " "वही ग्रेश चार्ट वे हैं उपयोग नहीं किया जा सकता में " "क्षण। चयनित क्रिया निष्पादित करने के लिए किसी विकल्प पर टैप करें.\n" "खिलाड़ी किसी भी समय शामिल हो सकते हैं। एक को छोड़ना " "खेल, उपयोग करें /leave. यदि कोई खिलाड़ी खेलने के लिए 90 सेकंड से अधिक समय लेता है, " "आप इसका उपयोग कर सकते हैं /skip उस खिलाड़ी को छोड़ दें.\n" "\n" "भाषा और अन्य सेटिंग्सs: /settings\n" "अन्य आदेश (केवल गेम निर्माता उपयोग कर सकता है):\n" "/close - बंद कमरा\n" "/open - खुला कमरा\t\n" "/enable_translations - महत्वपूर्ण संदेशों का सभी भाषाओं में अनुवाद करें " "खेल में उपलब्ध है\n" "/disable_translations - डिफ़ॉल्ट भाषा (अंग्रेज़ी भाषा) का उपयोग करें \n" "\n" "Experimental: एक ही समय में कई समूहों में खेलना. " "दबाएँ Current game: ... और समूह का चयन करें " "जिसे आप आगे बढ़ाना चाहते हैं.\n" "यदि आप बॉट पसंद करते हैं rate me, शामिल हों canal " "अद्यतनों की संख्या और UNO कार्ड गेम खरीदें." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "यह बॉट नि: शुल्क सॉफ्टवेयर है और एजीपीएल के तहत लाइसेंस प्राप्त है। कोड है " "यहाँ उपलब्ध है:\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "नया खेल बनाया गया! शामिल हों /join जब आप सभी तैयार हों, तो शुरू करने के लिए क्लिक करें. /start" #: bot.py:152 msgid "The lobby is closed" msgstr "कमरा बंद है।a." #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "" "कोई खेल प्रगति पर नहीं है /new के साथ एक खेल बनाएँ ." #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "आप पहले ही इस खेल में शामिल हो चुके हैं /start के साथ शुरू करें ." #: bot.py:167 msgid "Joined the game" msgstr "खेल में शामिल हो गए." #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "आप इस समूह में एक खेल में नहीं खेल रहे हैं।." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr " खेल ख़त्म हुआ! " #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Okay. अगला खिलाड़ी: {name}" #: bot.py:219 msgid "Game not found." msgstr "खेल नहीं मिला." #: bot.py:223 msgid "Back to last group" msgstr "अंतिम समूह पर लौटें." #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "कृपया अपने द्वारा चयनित समूह पर स्विच करें!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "चयनित समूह: {group}\n" "सुनिश्चित करें कि आप सही समूह पर स्विच करें!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "निकालने {name} खेल से." #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "इस चैट में कोई गेम नहीं चल रहा है /new के साथ एक नया बनाएँ /new." #: bot.py:278 msgid "The game has already started" msgstr "खेल पहले ही शुरू हो चुका है." #: bot.py:281 msgid "At least {minplayers} players must /join the game before you can start it" msgstr "" "खेल शुरू करने से पहले, कम से कम {minplayers} खिलाड़ियों को उपयोग में शामिल होना चाहिए /join." #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close लोगों को खेल में शामिल होने से रोकने के लिए.\n" "Enable multi-translations with /enable_translations" msgstr "" "पहला खिलाड़ी: {name}\n" "लोगों को खेल में शामिल होने से रोकने के लिए उपयोग करें /close.n" "के साथ बहु-अनुवाद सक्षम करें /enable_translations." #: bot.py:321 msgid "Please select the group you want to play in." msgstr "वह समूह चुनें जिसमें आप खेलना चाहते हैं." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "इस समूह में कोई खेल प्रगति पर नहीं है।." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "बंद कमरा। कोई और खिलाड़ी खेल में शामिल नहीं हो पाएगा." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "केवल खेल के निर्माता ({name}) ऐसा कर सकते हैं." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" "बहु-अनुवाद सक्षम किए गए. उन्हें अक्षम करें /disable_translations." #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "बहु-अनुवाद अक्षम किए गए. उन्हें फिर से सक्षम करें /" "enable_translations." #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "लॉबी खोली। नए खिलाड़ी खेल में /join शामिल हो सकते हैं." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "आप इस चैट में नहीं खेल रहे हैं." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "कृपया प्रतीक्षा करें सेकंड." msgstr[1] "कृपया प्रतीक्षा करें {time} सेकंड." #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "वर्तमान खिलाड़ी को कूदने के लिए प्रतीक्षा समय कम हो गया है {time} " "सेकंड.\n" "अगला खिलाड़ी: {name}" msgstr[1] "" "वर्तमान खिलाड़ी को कूदने के लिए प्रतीक्षा समय कम हो गया है {time} " "सेकंड.\n" "अगला खिलाड़ी: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} उन्हें लगातार चार बार छोड़ दिया गया और खेल से हटा दिया गयाउन्हें लगातार चार बार छोड़ दिया गया और खेल से हटा दिया गया " "partida.\n" "अगला खिलाड़ी {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "खेल समाप्त हुआ." msgstr "" "{name} उन्हें लगातार चार बार छोड़ दिया गया और खेल से हटा दिया गया " "प्रस्थान.\n" "खेल पूरा हुआ." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "सभी समाचार यहाँ: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr " वर्तमान खेल: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} से धोखा देने का प्रयास." #: bot.py:562 msgid "Next player: {name}" msgstr "अगला खिलाड़ी: {name}." #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "प्रतीक्षा समय {name} पुन: प्रारंभ करें {time} सेकंड" #: bot.py:585 msgid "Please choose a color" msgstr "कृपया किसी रंग का चयन करें" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "¡{name} जीत गया!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "डेक में कोई और कार्ड नहीं हैं।." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "यह एक धोखा था! {name} 4 कार्ड प्राप्त करें." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "¡{name1} उसने धोखा नहीं दिया!, {name2} 6 कार्ड प्राप्त करें." #: results.py:38 msgid "Choose Color" msgstr "किसी रंग का चयन करें" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "अंतिम कार्ड (खेल की स्थिति देखने के लिए क्लिक करें):" msgstr[1] "कार्ड (खेल की स्थिति देखने के लिए क्लिक करें):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "वर्तमान खिलाड़ी: {name}." #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "आखिरी कार्ड: {card}." #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "वादक: {player_list}" msgstr[1] "जुआरी: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} carta)" msgstr[1] "{name} ({number} cartas)" #: results.py:81 msgid "You are not playing" msgstr "आप नहीं खेल रहे हैं." #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "आप अभी नहीं खेल रहे हैं। एक खेल शुरू करने के लिए उपयोग /new" "यदि इस समूह में कोई खेल चल रहा है तो शामिल हों." #: results.py:95 msgid "The game wasn't started yet" msgstr "खेल अभी शुरू नहीं हुआ था." #: results.py:97 msgid "Start the game with /start" msgstr " /start से खेल प्रारंभ करें." #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Robando {number} carta." msgstr[1] "Robando {number} cartas." #: results.py:136 msgid "Pass" msgstr "उत्तीर्ण" #: results.py:148 msgid "I'm calling your bluff!" msgstr "मैं आपके धोखे का जवाब दे रहा हूं!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "कृपया बॉट के साथ निजी चैट में अपनी सेटिंग्स संपादित करें." #: settings.py:49 msgid "Enable statistics" msgstr "आँकड़े सक्षम करें" #: settings.py:51 msgid "Delete all statistics" msgstr "सभी आँकड़े हटाएँ" #: settings.py:53 msgid "Language" msgstr "भाषा" #: settings.py:54 msgid "Settings" msgstr "समायोजन" #: settings.py:68 msgid "Enabled statistics!" msgstr "सक्षम आँकड़े!" #: settings.py:70 msgid "Select locale" msgstr "स्थान चुनें" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "हटाए गए और अक्षम आँकड़े! " #: settings.py:94 msgid "Set locale!" msgstr "स्थान निर्धारित करें!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "आपने सांख्यिकी सक्षम नहीं की. उपयोग /settings बॉट के साथ एक निजी बातचीत में " "उन्हें सक्षम करने के लिए." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} खेल खेला गया." msgstr[1] "{number} खेले गए खेल." #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} पहले स्थान पर ({percent}%)." msgstr[1] "{number} प्रथम स्थान ({percent}%)." #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} कार्ड खेला गया." msgstr[1] "{number} कार्ड खेले गए." #: utils.py msgid "{emoji} Green" msgstr "{emoji} हरा" #: utils.py msgid "{emoji} Red" msgstr "{emoji} लाल" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} नीला" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} पीला" ================================================ FILE: locales/id_ID/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # Jannes Höke , 2016. # #: bot.py:224 msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-19 22:38+0200\n" "PO-Revision-Date: 2016-05-23 12:43+0200\n" "Last-Translator: Jannes Höke \n" "Language-Team: Deutsch \n" "Language: in_ID\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: utf-8\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 2.91.6\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Ikuti langkah-langkah berikut:\n" "\n" "1. Tambahkan grup ini ke dalam grup\n" "2. Di dalam grup, Membuat permainan baru dengan /new atau bergabung dengan " "permainan yang sudah berjalan dengan perintah /join\n" "3.Setelah setidaknya dua pemain bergabung, mulailah permainan dengan " "perintah /start\n" "4. Ketik @unobot kedalam chat box dan tekanspasi, " "atau pilih via @unobot dari daftar pemain. Kamu akan " "melihat daftar kartumu (yang beberapa tidak dapat dipilih), pilihan lainnya " "seperti gambar kartu, dan tanda tanya (?) untuk melihat status " "permainan. Kartu yang berwarna abu-abu adalah kartu yang saat ini " "tidak dapat dimainkan. Pilih gambar untuk melakukan aksi seperti " "memilih kartu atau melihat status permainan.\n" "Pemain dapat bergabung ke dalam permainan kapan saja. Untuk meinggalkan " "permainan, gunakan /leave.Apabila seorang pemain melebihi 90 detik dalam " "memilih kartu, kamu bisa menggunakna /skip to melompatipemain tersebut.\n" "\n" "Bahasa dan pengaturan lainnya: /settings\n" "Perintah lainnya (hanya pembuat game):\n" "/close - Menutup lobby\n" "/open - Membuka lobby\n" "/enable_translations - Mengubah tulisan tertulis menjadi semua bahasa pada " "permainan \n" "/disable_translations - Menggunakan bahasa inggris sebagai bahasa utama\n" "\n" "Eksperimental: Bermain dalam lebih dari satu grup pada waktu yang " "bersamaan. Tekan Current game: ... dan pilih grup yang ingin " "kamu mainkan \n" "Kalau kamu menyukai bot ini, beri kami rating, bergabunglah the update channel dan belilah kartu permainan " "UNO ." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Bot ini adalah software gratis dan berlisensi dibawah AGPL. Kode nya " "tersedia disini: \n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "Membuat permmainan baru! Ayo bergabung dengan perintah /join dan mulailah " "permainan tersebut dengan perintah /start" #: bot.py:152 msgid "The lobby is closed" msgstr "Lobby ditutup" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "" "Tidak ada permainan yang berlangsung. Buat permainan baru dengan perintah /" "new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "" "Kamu sudah bergabung dengan permainan. Mulai permainan dengan perintah /start" #: bot.py:167 msgid "Joined the game" msgstr "Tergabung dengan permainan" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "Kamu tidak bermain di grup ini." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "Permainan berakhir!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Baiklah. Pemain berikutnya: {name}" #: bot.py:219 msgid "Game not found." msgstr "Permainan tidak ditemukan." #: bot.py:223 msgid "Back to last group" msgstr "Kembali ke grup sebelumnya" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Silakan pilih grup!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Grup terpilih: {group}\n" "Pastikan kamu sudah memilih grup yang benar!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Mengeluarkan {name} dari permainan" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" "Tidak ada permainan yang berlangsung saat ini. Buat permainan baru dengan " "perintah /new" #: bot.py:278 msgid "The game has already started" msgstr "Permainan sudah dimulai." #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "" "Minimal dua pemain harus bergabung sebelum kamu bisa memulai game ini. " "Gunakan perintah /join untuk bergabung" #: bot.py:297 #, fuzzy, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Pemain pertama: {name}\n" "Gunakan /close untuk menghentikan pemain baru bergabung pada game ini.\n" "Aktifkan translasi multi bahasa dengan /enable_translations" #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Silakan pilih pada grup mana kamu akan bermain." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "Tidak ada permainan yang berjalan pada grup chat ini." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "Lobby ditutup. Tidak ada pemain yang bisa bergabung lagi." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Hanya pembuat permainan: ({name}) yang dapat melakukan itu." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" "Mengaktifkan translasi multi bahasa. Non-aktifkan dengan /" "disable_translations" #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "Menon-aktifkan translasi multi bahasa. Nyalakan kembali dengan perintah /" "enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "Membuka lobby. Pemain baru bisa bergabung dengan perintah /join." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "Kamu sedang tidak bermain." #: bot.py:400 #, python-format msgid "Please wait {time} seconds" msgstr "Mohon menunggu {time} detik" #: bot.py:413 #, python-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" "Waktu tunggu terhadap {name} telah dikurangi menjadi {time} detik.\n" "Next player: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} telah dilewati dan tidak bermain empat kali berturut-turutdan telah " "dikeluarkan dari permainan.\n" "Pemain berikutnya: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name} telah dilewati dan tidak bermain empat kali berturut-turutdan telah " "dikeluarkan dari permainan.\n" "Permainan berkahir." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Semua berita ada di sini: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "Permainan saat ini: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "Percobaan curang dilakukan oleh {name}" #: bot.py:562 msgid "Next player: {name}" msgstr "Pemain berikutnya: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "Waktu tunggu terhadap {name} telah dikembalikan menjadi 90 detik" #: bot.py:585 msgid "Please choose a color" msgstr "Silakan pilih warna" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} menang!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "Tidak ada kartu lagi tersedia." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Ternyata hanya gertakan! Memberikan 4 kartu kepada {name}" #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} tidak hanya menggertak! Memberikan 6 kartu kepada {name2}" #: results.py:38 msgid "Choose Color" msgstr "Pilih warna" #: results.py:56 msgid "Cards (tap for game state):" msgstr "Kartu-kartu (tekan untuk statistik permainan):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Pemain saat ini: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Kartu terakhir: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Players: {player_list}" msgstr "Pemain: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} cards)" msgstr "{name} ({number} kartu)" #: results.py:81 msgid "You are not playing" msgstr "Kamu sedang tidak bermain" #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "Saat ini sedang tidak ada permainan. Gunakan perintah /new untuk memulai " "permainan atau /join untuk bergabung dengan permainan yang sedang " "berlangsung di grup ini" #: results.py:95 msgid "The game wasn't started yet" msgstr "Permainan belum dimulai" #: results.py:97 msgid "Start the game with /start" msgstr "Mulailah permainan dengan perintah /start" #: results.py:108 #, python-format msgid "Drawing 1 card" msgstr "Mengambil satu kartu" msgid "Drawing {number} cards" msgstr "Mengambil {number} kartu" #: results.py:136 msgid "Pass" msgstr "Lewati" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Saya bilang, kamu hanya menggertak!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Silakan ubah pengaturan melalui chat pribadi dengan bot." #: settings.py:49 msgid "Enable statistics" msgstr "Mengaktifkan statistik" #: settings.py:51 msgid "Delete all statistics" msgstr "Menghapus semua statistik" #: settings.py:53 msgid "Language" msgstr "Bahasa" #: settings.py:54 msgid "Settings" msgstr "Pengaturan" #: settings.py:68 msgid "Enabled statistics!" msgstr "Mengaktifkan statistik" #: settings.py:70 msgid "Select locale" msgstr "Memilih lokasi" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Menghapus dan menonaktifkan statisk" #: settings.py:94 msgid "Set locale!" msgstr "Pilih lokasi!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "Kamu belum menyalakan statistik. Gunakan /settings melalui chat pribadi " "kepada bot untuk menyalakannya." #: simple_commands.py msgid "{number} games played" msgstr "{number} permainan dimainkan" #: simple_commands.py msgid "{number} first places ({percent}%)" msgstr "{number} diletakkan pertama ({percent}%)" #: simple_commands.py msgid "{number} cards played" msgstr "{number} kartu dimainkan" #: utils.py msgid "{emoji} Green" msgstr "{emoji} Hijau" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Merah" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Biru" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Kuning" ================================================ FILE: locales/it_IT/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 20:02+0200\n" "PO-Revision-Date: 2016-05-23 01:39+0200\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Language: it_IT\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Segui questi passaggi:\n" "\n" "1. Aggiungi questo bot ad un gruppo\n" "2. Nel gruppo, inizia una nuova partita con /new o unisciti a quella già " "avviata con /join\n" "3. Quando almeno due giocatori si sono uniti alla partita, si può iniziare " "con /start\n" "4. Digita @unobot nella casella di testo e premi " "spazio, o clicca sul testo via @unobot vicino ai " "messaggi. Potrai così vedere le tue carte (alcune in grigio), le opzioni " "extra come pesca e ? per vedere lo stato della partita attuale. Le " "carte in grigio sono quelle che non puoi giocare al momento. " "Premi un'opzione per eseguire l'azione selezionata.\n" "I giocatori possono unirsi alla partita in qualsiasi momento. Per lasciare " "la partita, usa /leave. Se un giocatore impiega più di 90 secondi a giocare, " "puoi usare /skip per saltare il turno di quel giocatore.\n" "\n" "Lingua e altre opzioni: /settings\n" "Altri comandi (utilizzabili solo da chi ha creato la partita):\n" "/close - Chiude la stanza, nessun giocatore può unirsi alla partita dopo che " "questa è già avviata.\n" "/open - Apre la stanza, i giocatori possono unirsi alla partita in qualsiasi " "momento. \v/enable_translations - Traduce i messaggi importanti nelle lingue " "parlate durante la partita\n" "/disable_translations - Usa l'inglese (default) per questi messaggi\n" "\n" "Sperimentale: Gioca in più gruppi allo stesso tempo. Premi il tasto " "Partita in corso: ... e scegli il gruppo dove vuoi giocare la " "carta.\n" "\n" "Se ti piace questo bot, votami, segui gli aggiornamenti e compra il gioco di carte UNO. " #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Questo bot è un software gratuito e distribuito sotto licenza AGPL. Il " "codice è disponibile qui:\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "È stata creata una nuova partita! Unisciti con /join e inizia a giocare con /" "start" #: bot.py:152 msgid "The lobby is closed" msgstr "La stanza è chiusa. Nessun nuovo giocatore può unirsi alla partita." #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "Non c'è nessuna partita aperta al momento. Iniziane una nuova con /new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Ti sei già unito/a alla partita. Inizia a giocare con /start" #: bot.py:167 msgid "Joined the game" msgstr "Si è unito/a alla partita" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "Non stai giocando alcuna partita in questo gruppo." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "La partita è conclusa!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Okay. Prossimo giocatore: {name}" #: bot.py:219 msgid "Game not found." msgstr "Partita non trovata." #: bot.py:223 msgid "Back to last group" msgstr "Vai all'ultimo gruppo." #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Per favore, vai sul gruppo che hai selezionato!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Gruppo selezionato: {group}\n" "Assicurati di spostarti nel gruppo giusto!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Sto rimuovendo {name} dalla partita" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" "Non c'è alcuna partita aperta in questa chat. Creane una nuova con /new" #: bot.py:278 msgid "The game has already started" msgstr "La partita è già iniziata" #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "" "Devono partecipare almeno due giocatori per iniziare la partita. Partecipa " "con /join" #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Primo giocatore: {name}\n" "Usa /close per impedire a nuovi giocatori di unirsi alla partita.\n" "Abilita la funzione di multi-traduzione con /enable_translations" #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Per favore, seleziona il gruppo dove vuoi giocare." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "Non c'è alcuna partita aperta in questa chat." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "" "La stanza è chiusa. Nessun nuovo giocatore può unirsi alla partita in corso." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Solo il creatore della partita ({name}) può farlo. " #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Multi-traduzione abilitata. Disabilitala con /disable_translations" #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Multi-traduzione disabilitata. Abilitala con /enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "" "La stanza è aperta. Nuovi giocatori possono unirsi alla partita con /join" #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "Non stai giocando alcuna partita in questa chat. " #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Per favore, attendi {time} secondi" msgstr[1] "Per favore, attendi {time} secondi" #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "Il tempo di attesa per saltare questo giocatore è stato ridotto a {time} " "secondi.\n" "Prossimo giocatore: {name}" msgstr[1] "" "Il tempo di attesa per saltare questo giocatore è stato ridotto a {time} " "secondi.\n" "Prossimo giocatore: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} è stato saltato per quattro turni ed è stato rimosso dalla partita.\n" "Prossimo giocatore: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name} è stato saltato per quattro turni ed è stato rimosso dalla partita.\n" "La partita è conclusa." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Tutte le novità le trovi qui: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "Partita in corso: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} ha tentato di barare!" #: bot.py:562 msgid "Next player: {name}" msgstr "Prossimo giocatore: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "Il tempo di attesa per {name} è stato reimpostato a 90 secondi" #: bot.py:585 msgid "Please choose a color" msgstr "Per favore, scegli un colore" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} ha vinto!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "Non ci sono più carte sul tavolo." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Il baro è stato scoperto! {name} deve pescare 4 carte!" #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} non ha barato! {name2} deve pescare 6 carte!" #: results.py:38 msgid "Choose Color" msgstr "Scegli il colore" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Carte (clicca per vedere lo stato della partita):" msgstr[1] "Carte (clicca per vedere lo stato della partita):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Giocatore attuale: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Ultima carta: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Giocatori: {player_list}" msgstr[1] "Giocatori: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} carta)" msgstr[1] "{name} ({number} carte)" #: results.py:81 msgid "You are not playing" msgstr "Non stai giocando in questa partita." #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "Non stai giocando in questo momento. Usa /new per iniziare una nuova partita " "o /join per partecipare a quella già avviata in questo gruppo" #: results.py:95 msgid "The game wasn't started yet" msgstr "La partita non è ancora iniziata" #: results.py:97 msgid "Start the game with /start" msgstr "Inizia la partita con /start" #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Sto pescando {number} carta" msgstr[1] "Sto pescando {number} carte" #: results.py:136 msgid "Pass" msgstr "Passo" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Penso che tu stia barando!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "" "Per favore, modifica le tue impostazioni in una chat privata con il bot." #: settings.py:49 msgid "Enable statistics" msgstr "Abilita le statistiche" #: settings.py:51 msgid "Delete all statistics" msgstr "Elimina tutte le statistiche" #: settings.py:53 msgid "Language" msgstr "Lingua" #: settings.py:54 msgid "Settings" msgstr "Impostazioni" #: settings.py:68 msgid "Enabled statistics!" msgstr "Statistiche abilitate!" #: settings.py:70 msgid "Select locale" msgstr "Seleziona la lingua" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Le statistiche sono state eliminate e disabilitate!" #: settings.py:94 msgid "Set locale!" msgstr "Lingua impostata!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "Non hai abilitato le statistiche. Usa /settings in una chat privata col bot " "per abilitarle." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} partite giocate" msgstr[1] "{number} partite giocate" #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} vittorie ({percent}%)" msgstr[1] "{number} vittorie ({percent}%)" #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} carta giocate" msgstr[1] "{number} carte giocate" #: utils.py msgid "{emoji} Green" msgstr "{emoji} Verde" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Rosso" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Blu" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Giallo" ================================================ FILE: locales/ml_IN/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 17:32-0600\n" "PO-Revision-Date: 2021-02-21 10:31+0530\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.4.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Last-Translator: \n" "Language: ml_IN\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "ഈ ഘട്ടങ്ങൾ പിന്തുടരുക:\n" "\n" "1. ഒരു ഗ്രൂപ്പിലേക്ക് ഈ ബോട്ട് ചേർക്കുക\n" "2. ഗ്രൂപ്പിൽ പുതിയ ഗെയിം ആരംഭിക്കിന്നതിന് /new ഉപയോഗിക്കാം. ഇപ്പോൾ നടന്നുകൊണ്ടിരിക്കുന്ന " "ഗെയിമിൽ തുടരാൻ /join ഉപയോഗിക്കാം.\n" "3. ചുരുങ്ങിയത് രണ്ട് കളിക്കാർ ചേർന്നതിന് ശേഷം, ഗെയിം ആരംഭിക്കുന്നതിന് /start \n" "4. നിങ്ങളുടെ ചാറ്റ് ബോക്സിൽ @unobotഎന്നു ടൈപ് ചെയ്ത് സ്പേസ്ഹിറ്റ് " "ചെയ്യുക അല്ലെങ്കിൽ via @unobot എന്ന് മെസേജുകളുടെ അടുത്ത് നിന്ന് ക്ലിക്ക് ചെയ്യുക." "നിങ്ങളുടെ കാർഡുകൾ (ചില ചാരനിറം(grey ) വലിക്കുക പോലുള്ള ഏതെങ്കിലും അധിക ഓപ്ഷനുകൾ, " "നിലവിലെ ഗെയിം സ്റ്റേറ്റ് കാണുന്നതിന് a ? എന്നിവ നിങ്ങൾക്ക് കാണാം. ഈ സമയത്ത് " "കളിക്കാൻ കഴിയാത്ത ചീട്ടുകളാണ് ചാരനിറത്തിലുള്ളത് . ഓപ്ഷൻ ക്ലിക്ക് ചെയ്ത് കളി " "തുടരാം. \n" "കളിക്കാർക്ക് എപ്പോൾ വേണമെങ്കിലും ഗെയിമിൽ ചേരാം. ഒരു കളി വിടാൻ, /leave ഉപയോഗിക്കുക. ഒരു " "കളിക്കാരൻ കളിക്കാൻ 90 സെക്കൻഡിലധികം എടുക്കുകയാണെങ്കിൽ, ആ കളിക്കാരനെ ഒഴിവാക്കാൻ " "നിങ്ങൾക്ക് /skip ഉപയോഗിക്കാം.\n" "\n" " \n" "ഭാഷയും മറ്റ് സജ്ജീകരണങ്ങളും: /settings \n" "മറ്റ് സജീകരണങ്ങൾ (ഗെയിം സ്രഷ്ടാവ് മാത്രം):\n" "/close - ലോബി അടയ്ക്കുക\n" "/open - ലോബി തുറക്കുക\n" "/enable_translations - ഒരു ഗെയിമിൽ സംസാരിക്കുന്ന എല്ലാ ഭാഷകളിലേക്കും ബന്ധപ്പെട്ട " "പാഠങ്ങൾ പരിഭാഷപ്പെടുത്തുക\n" "/enable_translations - ഗെയിം എല്ലാ ഭാഷകളിലും കാണാൻ. \n" "/disable_translations - ഇംഗ്ലീഷിൽ തുടരാൻ \n" "\n" "പരീക്ഷണാത്മകം: ഒരേ സമയം ഒന്നിലധികം ഗ്രൂപ്പുകളിൽ കളിക്കുക. ബട്ടൺ Current " "game: ... ഉപയോഗിക്കുക. പിന്നീട് കളിക്കാൻ ആഗ്രഹിക്കുന്ന ഗ്രൂപ്പ് സെലക്ട് ചെയ്യുക. \n" "ഈ ബോട്ട് ഇഷ്ടപ്പെട്ടുവെങ്കിൽ റേറ്റ് ചെയ്യുക , Rate Me! , uno News Channel അപ്ഡേറ്റുകൾ ജോയിൻ ചെയ്യുക." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "ഈ ബോട്ട് ഒരു സ്വതന്ത്ര സോഫ്റ്റ് വെയർ ആണ്, എജിപിഎൽ കീഴിൽ ലൈസൻസ് ഉള്ളതാണ്. കോഡ് ഇവിടെ " "ലഭ്യമാണ്: \n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "പുതിയ ഗെയിം സൃഷ്ടിച്ചു! /join ഉപയോഗിച്ച് ഗെയിം ജോയിൻ ചെയ്തതിനു ശേഷം /start ഉപയോഗിച്ച് " "ഗെയിം തുടങ്ങു. " #: bot.py:152 msgid "The lobby is closed" msgstr "ലോബി അടച്ചു" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "ഒരു കളിയും ഇപ്പോൾ നടക്കുന്നില്ല /new പുതിയ കളി സൃഷ്ടിക്കുക." #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "നിങ്ങൾ ഇതിനകം ഗെയിമിൽ ചേർന്നു. /start വച്ച് ഗെയിം സ്റ്റാർട്ട് ചെയ്യൂ. " #: bot.py:167 msgid "Joined the game" msgstr "ഗെയിമിൽ ചേർന്നു." #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "നിങ്ങൾ ഈ ഗ്രൂപ്പിൽ ഗെയിം കളിക്കുന്നില്ല." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "കളി അവസാനിച്ചു!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "ശരി. അടുത്ത കളിക്കാരൻ: {name}" #: bot.py:219 msgid "Game not found." msgstr "ഗെയിം കണ്ടെത്താന് ആയില്ല." #: bot.py:223 msgid "Back to last group" msgstr "അവസാന ഗ്രൂപ്പിലേക്ക് മടങ്ങുന്നു. " #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "അവസാന ഗ്രൂപ്പിലേക്ക് മടങ്ങു. " #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "തിരഞ്ഞെടുത്ത ഗ്രൂപ്പ്: {group}n\n" " നിങ്ങൾ ശരിയായ ഗ്രൂപ്പിലേക്ക് മാറുന്നുവെന്ന് ഉറപ്പാക്കുക! " #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "ഗെയിമിൽ നിന്ന് {name} നീക്കംചെയ്യുന്നു." #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" "ഈ ചാറ്റിൽ ഒരു ഗെയിമും പ്രവർത്തിക്കുന്നില്ല. /new പുതിയത് ഉപയോഗിച്ച് പുതിയൊരെണ്ണം തുടങ്ങൂ." #: bot.py:278 msgid "The game has already started" msgstr "ഗെയിം തുടങ്ങി കഴിഞ്ഞു." #: bot.py:281 msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "ഗെയിം ആരംഭിക്കുന്നതിന് മുമ്പ് കുറഞ്ഞത് {miniplayer} /join ചെയ്യണം." #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "ആദ്യ കളിക്കാരൻ: {name}\n" "ആളുകളെ ഗെയിമിൽ ചേരുന്നത് തടയാൻ ഉപയോഗിക്കുക / close \n" "/enable_translations ഉപയോഗിച്ച് ഒന്നിലധികം വിവർത്തനങ്ങൾ ഉപയോഗിക്കൂ." #: bot.py:321 msgid "Please select the group you want to play in." msgstr "നിങ്ങൾ കളിക്കാൻ ആഗ്രഹിക്കുന്ന ഗ്രൂപ്പ് തിരഞ്ഞെടുക്കുക." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "ഈ ചാറ്റിൽ പ്രവർത്തിക്കുന്ന ഗെയിമുകളൊന്നുമില്ല." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "ലോബി അടച്ചു. കൂടുതൽ കളിക്കാർക്ക് ഈ ഗെയിമിൽ ചേരാനാവില്ല." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "ഗെയിം സ്രഷ്ടാവിന് ({name}) മാത്രമേ അത് ചെയ്യാൻ കഴിയൂ." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" "ഭാഷ വിവർത്തനങ്ങൾ ഉപയോഗിക്കുന്നു. വിവർത്തനങ്ങൾ ഒഴിവാക്കാൻ /disable_translations " "ഉപയോഗിക്കുക." #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "മറ്റ് ഭാഷ വിവർത്തനങ്ങൾ പ്രവർത്തനരഹിതമാക്കി. വിവർത്തനങ്ങൾ ഉപയോഗിക്കാൻ /" "enable_translations. " #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "ലോബി തുറന്നു. പുതിയ കളിക്കാർക്ക് ഗെയിം കളിക്കാൻ /join." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "" "നിങ്ങൾ ഈ ചാറ്റിൽ ഗെയിം കളിക്കുന്നില്ല. \n" " " #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "{time} സെക്കൻഡ് വെയിറ്റ് ചെയ്യൂ." msgstr[1] "{time} സെക്കൻഡ് വെയിറ്റ് ചെയ്യൂ. " #: bot.py:413 #, python-format msgid "" "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "ഈ കളിക്കാരനെ ഒഴിവാക്കാനുള്ള സമയം {time} സെക്കൻഡായി ചുരുക്കി. \n" " \n" "അടുത്ത കളിക്കാരൻ : {name}" msgstr[1] "" "ഈ കളിക്കാരനെ ഒഴിവാക്കാനുള്ള സമയം {time} സെക്കൻഡായി ചുരുക്കി. \n" "അടുത്ത കളിക്കാരൻ : {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} ഗെയിമിൽ നിന്ന് തുടർച്ചയായി നാലു തവണ സ്കിപ് ചെയ്യപ്പെട്ടത്തിനാൽ ഗെയിമിൽ നിന്ന് " "അയാളെ പുറത്താക്കി. \n" "അടുത്ത കളിക്കാരൻ: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name} ഗെയിമിൽ നിന്ന് തുടർച്ചയായി നാലു തവണ സ്കിപ് ചെയ്യപ്പെട്ടത്തിനാൽ ഗെയിമിൽ നിന്ന് " "അയാളെ പുറത്താക്കി. \n" "ഗെയിം അവസാനിച്ചു." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "അപ്‌ഡേറ്റുകൾക്കായി ഗ്രൂപ്പ് ജോയിൻ ചെയ്യാം https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "നിലവിലെ ഗെയിം: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "കള്ളകളി കളിക്കാനുള്ള ശ്രമം {name}" #: bot.py:562 msgid "Next player: {name}" msgstr "അടുത്ത കളിക്കാരൻ : {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "{name} നു വേണ്ടി കാതിരിക്കാനുള്ള സമയം {time} ലേക്ക് റീസെറ്റ് ചെയ്തു." #: bot.py:585 msgid "Please choose a color" msgstr "നിറം തിരഞ്ഞെടുക്കുക." #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} ജയിച്ചു!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "ഡെക്കിൽ കൂടുതൽ കാർഡുകളൊന്നുമില്ല." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "ബ്ലഫ് വിളിച്ചു! {name} ന് 4 കാർഡുകൾ നൽകുന്നു." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} bluff ചെയ്തില്ല. {name2} ന് 6 കാർഡ് നല്‍കുന്നു ." #: results.py:38 msgid "Choose Color" msgstr "നിറം തിരഞ്ഞെടുക്കുക." #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "അവസാന കാർഡ് (ഗെയിം നിലയ്ക്കായി ടാപ്പുചെയ്യുക):" msgstr[1] "കാർഡുകൾ (ഗെയിം നിലയ്ക്കായി ടാപ്പുചെയ്യുക):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "നിലവിലെ കളിക്കാരൻ: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "അവസാന കാർഡ് (ഗെയിം നിലയ്ക്കായി ടാപ്പുചെയ്യുക):" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "കളിക്കാരൻ: {player_list}" msgstr[1] "കളിക്കാർ: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} കാർഡ്)" msgstr[1] "{name} ({number} കാർഡുകൾ)" #: results.py:81 msgid "You are not playing" msgstr "നിങ്ങൾ കളിക്കുന്നില്ല." #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "നിങ്ങൾ ഇപ്പോൾ കളിക്കുന്നില്ല. /new ഉപയോഗിച്ച് പുതിയ ഗെയിം തുടങ്ങൂ അല്ലെങ്കില്‍ /join " "ഉപയോഗിച്ച് ഗെയിൽ കളിക്കൂ." #: results.py:95 msgid "The game wasn't started yet" msgstr "ഗെയിം ഇതുവരെ തുടങ്ങിയില്ല." #: results.py:97 msgid "Start the game with /start" msgstr "ഗെയിം തുടങ്ങുന്നതിന് /start." #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "{number} കാർഡ് വലിക്കുന്നു." msgstr[1] "{number} കാർഡുകൾ വലിക്കുന്നു. " #: results.py:136 msgid "Pass" msgstr "പാസ്. " #: results.py:148 msgid "I'm calling your bluff!" msgstr "ഞാന് bluff വിളിക്കുന്നു." #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "നിങ്ങളുടെ ക്രമീകരണങ്ങൾ പ്രൈവറ്റ് ചാറ്റിൽ അപ്ഡേറ്റ് ചെയ്യുക. " #: settings.py:49 msgid "Enable statistics" msgstr "ഗെയിം വിവരങ്ങൾ ലഭ്യമാക്കുന്നതിന്. " #: settings.py:51 msgid "Delete all statistics" msgstr "ഗെയിം വിവരങ്ങൾ ഡിലീറ്റ് ചെയ്യുന്നതിന്." #: settings.py:53 msgid "Language" msgstr "ഭാഷ. " #: settings.py:54 msgid "Settings" msgstr "സജീകരണങ്ങൾ. " #: settings.py:68 msgid "Enabled statistics!" msgstr "ഗെയിം വിവരങ്ങൾ enable ചെയ്തു." #: settings.py:70 msgid "Select locale" msgstr "ഭാഷ തിരഞ്ഞെടുക്കൂ. " #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "ഗെയിം വിവരങ്ങൾ ഡിലീറ്റ് ചെയ്യുകയും disable ചെയ്യുകയും ചെയ്തു." #: settings.py:94 msgid "Set locale!" msgstr "ഭാഷ തിരഞ്ഞെടുക്കൂ. " #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "ഗെയിം വിവരങ്ങൾ enable ചെയ്തിട്ടില്ല. /settings ബോടിന്റെ പ്രൈവറ്റ് ചാറ്റിൽ ഉപയോഗിച്ച് " "ഗെയിം വിവരങ്ങൾ പ്രവർത്തനക്ഷമമാക്കൂ. " #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} ഗെയിം കളിച്ചു. " msgstr[1] "{number} ഗെയിം കളിച്ചു " #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} ഒന്നാം സ്ഥാനം ({percent}%)." msgstr[1] "{number} ഒന്നാം സ്ഥാനങ്ങൾ ({percent}%)." #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} കാർഡ് കളിച്ചു. " msgstr[1] "{number} കാർഡ് കളിച്ചു" #: utils.py msgid "{emoji} Green" msgstr "{emoji} പച്ച. " #: utils.py msgid "{emoji} Red" msgstr "{emoji} ചുവപ്പ്. " #: utils.py msgid "{emoji} Blue" msgstr "{emoji} നീല. " #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} മഞ്ഞ. " ================================================ FILE: locales/pt_BR/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-22 18:56-0300\n" "PO-Revision-Date: 2021-11-01 15:17-0300\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "Language: pt_BR\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or click the " "via @unobot text next to messages. You will see your cards (some greyed out), " "any extra options like drawing, and a ? to see the current game state. The " "greyed out cards are those you can not play at the moment. Tap an option to " "execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a player takes more " "than 90 seconds to play, you can use /skip to skip that player. Use /notify_me to receive " "a private message when a new game is started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the Current " "game: ... button and select the group you want to play a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an " "UNO card game." msgstr "" "Siga esses passos:\n" "\n" "1. Adicione este bot ao grupo\n" "2. No grupo, crie uma nova partida com /new ou entre em uma partida já criada com /join\n" "3. Após pelo menos dois jogadores entrarem, inicie a partida com /start\n" "4. Digite @unobot na janela de conversação e aperte espaço, ou clique " "no texto via @unobot próximo às mensagens. Você verá suas cartas (algumas " "apagadas, na cor cinza), e opções extras como sacar, e um ? para ver o estado da " "partida atual. As cartas acizentadas são as que você não pode jogar no " "momento. Toque em uma das opções para executar a ação desejada.\n" "Jogadores podem entrar na partida a qualquer momento. Para sair do jogo, use /leave. Se um " "jogador levar mais de 90 segundos para jogar, você pode usar /skip para pular a vez deste " "jogador. Use /notify_me para receber uma mensagem privada quando uma nova partida for " "iniciada no grupo.\n" "\n" "Idioma e outras configurações: /settings\n" "Outros comandos (somente para quem criou o jogo):\n" "/close - Fechar o lobby\n" "/open - Abrir o lobby\n" "/enable_translations - Traduz os textos relevantes para todas as linguagens disponíveis no " "jogo\n" "/disable_translations - Receber esses textos em inglês\n" "\n" "Experimental: Jogue em vários grupos ao mesmo tempo. Toque no botão Partida " "atual: ... e selecione o grupo no qual deseja jogar uma carta.\n" "Se gostou deste bot, avalie-o, entre no canal de atualizações e " "compre um jogo de cartas UNO." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Esse bot é um Software livre, grátis e licenciado com AGPL. O código está disponível " "aqui: \n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "Created a new game! Join the game with /join and start the game with /start" msgstr "Novo jogo criado! Entre no jogo com /join e inicie o jogo com /start" #: bot.py msgid "Send this command in a group to be notified when a new game is started there." msgstr "Envie este comando em um grupo para ser notificado quando um novo jogo for iniciado." #: bot.py:152 msgid "The lobby is closed" msgstr "O lobby está fechado" #: bot.py msgid "A new game has been started in {title}" msgstr "Um novo jogo foi iniciado no grupo {title}" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "Nenhuma partida está sendo jogada. Crie um novo jogo com /new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Você já entrou na partida. Inicie o jogo com /start" #: bot.py:167 msgid "Joined the game" msgstr "Entrou na partida" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "Você não está jogando nenhuma partida nesse grupo." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "Fim de jogo!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Ok. Próximo(a) jogador(a): {name}" #: bot.py:219 msgid "Game not found." msgstr "Jogo não encontrado." #: bot.py:223 msgid "Back to last group" msgstr "Voltar ao último grupo" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Por favor, mude para o grupo selecionado!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Grupo selecionado: {group}\n" "Tenha certeza de que mudou para o grupo certo!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Removendo {name} da partida" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "Não há uma partida sendo jogada nesta conversa. Crie um novo jogo com /new" #: bot.py:278 msgid "The game has already started" msgstr "A partida já começou" #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "" "Pelo menos dois jogadores devem entrar no jogo usando /join para que a partida possa " "começar" #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Primeiro jogador: {name}\n" "Use /close para impedir que mais pessoas entrem na partida.\n" "Ative as multi-traduções com /enable_translations" #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Por favor, selecione o grupo em que deseja jogar." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "Não há uma partida sendo jogada nesta conversa." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "O lobby está fechado. Não é permitida a entrada de novos jogadores nessa partida." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Somente quem criou o jogo ({name}) pode fazer isso." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Multi-traduções ativadas. Desative com /disable_translations" #: bot.py:377 #, python-format msgid "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Multi-traduções desativadas. Ative-as novamente com /enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "O lobby está aberto. Novos jogadores podem entrar na partida usando /join." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "Você não está participando de uma partida nesta conversa." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Por favor, aguarde {time} segundo" msgstr[1] "Por favor, aguarde {time} segundos" #: bot.py:413 #, python-format msgid "" "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "O tempo de espera para pular a vez deste(a) jogador(a) foi reduzido para {time} segundo.\n" "Próximo(a) jogador(a): {name}" msgstr[1] "" "O tempo de espera para pular a vez deste(a) jogador(a) foi reduzido para {time} segundos.\n" "Próximo(a) jogador(a): {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} teve suas jogadas puladas quatro vezes seguidas e foi removido(a) do jogo.\n" "Próximo(a) jogador(a): {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name} teve suas jogadas puladas quatro vezes seguidas e foi removido(a) do jogo.\n" "O jogo acabou." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Todas as novidades aqui: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "Partida atual: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "Tentativa de trapaça por {name}" #: bot.py:562 msgid "Next player: {name}" msgstr "Próximo jogador: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "O tempo de espera para {name} foi reiniciado para 90 segundos" #: bot.py:585 msgid "Please choose a color" msgstr "Por favor, escolha uma cor" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} venceu!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "Não há mais cartas no deck." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Blefe revelado! Dando 4 cartas para {name}" #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} não blefou! Dando 6 cartas para {name2}" #: results.py:38 msgid "Choose Color" msgstr "Escolher Cor" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Última carta (toque para ver as estatísticas do jogo):" msgstr[1] "Cartas (toque para ver as estatísticas do jogo):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Jogador atual: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Última carta: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Jogador(a): {player_list}" msgstr[1] "Jogadores(as): {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} carta)" msgstr[1] "{name} ({number} cartas)" #: results.py:81 msgid "You are not playing" msgstr "Você não está jogando" #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current game in this " "group" msgstr "" "Você não está jogando. Use /new para criar uma partida ou /join para entrar na partida " "atual neste grupo" #: results.py:95 msgid "The game wasn't started yet" msgstr "A partida ainda não começou" #: results.py:97 msgid "Start the game with /start" msgstr "Inicie a partida com /start" #: results.py:108 #, python-format msgid "Drawing 1 card" msgstr "Sacando 1 carta" msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Sacando {number} carta" msgstr[1] "Sacando {number} cartas" #: results.py:136 msgid "Pass" msgstr "Passo" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Você está blefando!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Por favor, ajuste suas configurações em uma conversa privada com o bot." #: settings.py:49 msgid "Enable statistics" msgstr "Habilitar estatísticas" #: settings.py:51 msgid "Delete all statistics" msgstr "Apagar todas estatísticas" #: settings.py:53 msgid "Language" msgstr "Idioma" #: settings.py:54 msgid "Settings" msgstr "Configurações" #: settings.py:68 msgid "Enabled statistics!" msgstr "Estatísticas habilitadas!" #: settings.py:70 msgid "Select locale" msgstr "Definir linguagem" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Estatísticas apagadas e desabilitadas!" #: settings.py:94 msgid "Set locale!" msgstr "Linguagem selecionada!" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot to enable them." msgstr "" "Você não habilitou as estatísticas. Use /settings em uma conversa privada com o bot para " "ativá-las." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} partida jogada" msgstr[1] "{number} partidas jogadas" #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} vez em primeiro lugar ({percent}%)" msgstr[1] "{number} vezes em primeiro lugar ({percent}%)" #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} carta jogada" msgstr[1] "{number} cartas jogadas" #: utils.py msgid "{emoji} Green" msgstr "{emoji} Verde" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Vermelho" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Azul" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Amarelo" ================================================ FILE: locales/ru_RU/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # Jannes Höke , 2016. # #: bot.py:224 #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-19 22:38+0200\n" "PO-Revision-Date: 2016-05-21 21:16+0200\n" "Last-Translator: Jannes Höke \n" "Language-Team: Deutsch \n" "Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: utf-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 2.91.6\n" #: bot.py:60 msgid "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. " "Use /notify_me to receive a private message when a new game is started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all " "languages spoken in a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Выполните следующие действия:\n" "\n" "1. Добавьте этого бота в свою группу\n" "2. Создайте новую игру в своей группе с помощью команды /new " "либо присоединитесь к уже существующей, написав /join\n" "3. Как только к игре присоединятся по меньшей мере двое игроков, Вы можете начать " "с помощью команды /start\n" "4. Напишите @unobot в окне чата и поставьте " "пробел либо нажмите на текст via @unobot " "рядом с сообщениями. Вы увидите свои карточки (некоторые из них будут серыми), " "а также некоторые дополнительные опции и кнопку ? для просмотра текущего " "состояния игры. Вы не можете выбрать серые карточки. " "Нажмите на доступную кнопку для осуществления выбранного действия. \n " "Присоединиться к игре можно в любой момент. Выйти из партии можно с помощью " "команды /leave. Если игрок затратил больше 90 секунд на ход, его ход можно пропустить " "командой /skip. " "Используйте /notify_me для получения приватного сообщения о начале новой партии.\n" "\n" "Язык и другие настройки: /settings\n" "Другие команды (только для организаторов партии):\n" "/close - Закрыть лобби\n" "/open - Открыть лобби\n" "/enable_translations - Разрешить вывод текста на языках игроков/n" "/disable_translations - Выводить текст только на Английском языке\n" "\n" "Экспериментальные опции: Одновременная игра в нескольких группах. " "Нажмите на кнопку" "Текущая игры: ... и выберите, в какой группе сделать ход.\n" "Если Вам понравился этот бот, оцените его и следите за новостным каналом, а такщже купите себе карточки UNO." #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Этот бот является программой с открытым исходным кодом и выпущен под лицензией AGPL. " "Весь код доступен по адресу:\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "Создана новая игра! Присоединитесь к ней командой /join и начните, написав /start" #: bot.py msgid "Send this command in a group to be notified when a new game is started there." msgstr "Отправьте эту команду в группе, чтобы получать уведомления о новых партиях. " #: bot.py msgid "A new game has been started in {title}" msgstr "В {title} началась новая игра" #: bot.py:152 msgid "The lobby is closed" msgstr "Лобби закрыто" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "Нет активных партий в данный момент. Создайте новую, написав /new" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "Вы уже присоединились к этой игре. Начните ее с помощью /start" #: bot.py:167 msgid "Joined the game" msgstr "Присоединился к игре" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "Вы не играете в данной группе." #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "Игра окончена!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "Ок. Следующий игрок: {name}" #: bot.py:219 msgid "Game not found." msgstr "Игры не найдены." #: bot.py:223 msgid "Back to last group" msgstr "Вернуться к последней группе" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "Пожалуйста, переключитесь на выбранную группу!" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Выбранная группа: {group}\n" "Убедитесь, что Вы переключились на нее!" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "Удаляю {name} из игры" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" "Нет ни одной игры в данном чате. Создайте новую командой /new" #: bot.py:278 msgid "The game has already started" msgstr "Игра уже началась" #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "Как минимум два человека должны присоединиться, прежде чем Вы сможете " "начать игру" #: bot.py:297 #, python-format, fuzzy msgid "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Первый игрок: {name}\n" "Напишите /close, чтобы запретить присоединяться к этой игре." "Включите перевод текстов командой /enable-translations" #: bot.py:321 msgid "Please select the group you want to play in." msgstr "Пожалуйста, выберите группу, в которой хотите играть." #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "Нет ни одной игры в данном чате." #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "" "Лобби закрыто. К данной игре нельзя присоединиться." #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "Только создатель партии ({name}) может это сделать." #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Перевод активирован. Выключите с помощью /disable_translations" #: bot.py:377 #, python-format msgid "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Перевод отключен. Вы можете включить его с помощью " "/enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "Лобби открыто. Теперь к игре можно присоединиться." #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "Вы не играете ни в одну из партий в данном чате." #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Пожалуйста, подождите {time} секунды" msgstr[1] "Пожалуйста, подождите {time} секунд" #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "Время на ход для данного игрока было сокращено на {time} " "секунды.\n" "Следюущий игрок: {name}" msgstr[1] "Время на ход для данного игрока было сокращено на {time} " "секунд.\n" "Следующий игрок: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1} был пропущен 4 раза подряд и вышел из игры.\n" "Следующий игрок: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name1} был пропущен 4 раза поряд и вышел из игры.\n" "Игра окончена." #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "Все новости здесь: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {game}" msgstr "Текущая игра: {game}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} попытался сжульничать!" #: bot.py:562 msgid "Next player: {name}" msgstr "Следующий игрок: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "Время на ход для {name} было сброшено до 90 секунд." #: bot.py:585 msgid "Please choose a color" msgstr "Пожалуйста, выберите цвет" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} победил!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "В колоде больше нет карт." #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Это блеф! {name} получает 4 карты." #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} не блефовал! {name2} получает 6 карт." #: results.py:38 msgid "Choose Color" msgstr "Выберите цвет" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Последняя карта (нажмите для просмотра статуса игры):" msgstr[1] "Карты (нажмите для просмотра статуса игры):" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "Текущий игрок: {name}" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "Последняя карта: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Игрок: {player_list}" msgstr[1] "Игроки: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} карты)" msgstr[1] "{name} ({number} карт)" #: results.py:81 msgid "You are not playing" msgstr "Вы не играете" #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "В данный момент Вы не играете. Используйте /new, чтобы начать новую, или /" "join, чтобы присоединиться к текущей." #: results.py:95 msgid "The game wasn't started yet" msgstr "Игра еще не началась." #: results.py:97 msgid "Start the game with /start" msgstr "Начните новую игру с помощью /start" #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Забирает {number} карты" msgstr[1] "Забирает {number} карты" #: results.py:136 msgid "Pass" msgstr "Пас" #: results.py:148 msgid "I'm calling your bluff!" msgstr "Я бросаю тебе вызов!" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "Пожалуйста, напишите боту для изменения своих настроек." #: settings.py:49 msgid "Enable statistics" msgstr "Включить статистику" #: settings.py:51 msgid "Delete all statistics" msgstr "Удалить всю статистику" #: settings.py:53 msgid "Language" msgstr "Язык" #: settings.py:54 msgid "Settings" msgstr "Настройки" #: settings.py:68 msgid "Enabled statistics!" msgstr "Статистика включена!" #: settings.py:70 msgid "Select locale" msgstr "Выберите язык" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "Статистика удалена и отключена!" #: settings.py:94 msgid "Set locale!" msgstr "Язык установлен!" #: simple_commands.py msgid "You did not enable statistics. Use /settings in " "a private chat with the bot to enable them." msgstr "Вы не включали статистику. Чтобы ее активировать, напишите " "/settings в приватном чате с ботом." #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} игры сыграно" msgstr[1] "{number} игр сыграно" #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} первое место ({percent}%)" msgstr[1] "{number} первых мест ({percent}%)" #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} карты сыграно" msgstr[1] "{number} карты сыграно" #: utils.py msgid "{emoji} Green" msgstr "{emoji} Зеленый" #: utils.py msgid "{emoji} Red" msgstr "{emoji} Красный" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} Синий" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} Желтый" ================================================ FILE: locales/tr_TR/LC_MESSAGES/unobot.po ================================================ # SOME DESCRIPTIVE TITLE. # This file is put in the public domain. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 1.0\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2019-08-28 14:21+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Kasım @Holytotem \n" "Language-Team: Turkish-Türkçe/TR \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n>1);\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "Bu oyuncuyu atlamak için gereken süre {time} saniyeye düşürüldü.\n" "Sıradaki oyuncu: {name}" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "{player} turu pas geçti!" #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "{name1}’ın süresi doldu ve oyundan çıkarıldı!\n" "Sıradaki oyuncu: {name2}" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "{name}’ın süresi doldu ve oyundan çıkarıldı!\n" "Oyun sona erdi." #: actions.py:101 msgid "Please choose a color" msgstr "Lütfen bir renk seçin" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "{name} kazandı!" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "Oyun Bitti!" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "Destede yeterli kart kalmadı." #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Blöf yapıyor! {name}’a 4 kart ver." #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} blöf yapmıyordu! {name2}’a 6 kart ver." #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "Bu komutu, bir grupta yeni bir oyuna başladığında bildirim almak için o gruba gönderin." #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "Şu grupta yeni bir oyun başladı: {title}" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "Yeni bir oyun oluşturuldu! Oyuna katılmak için /join yaz ve oyunu başlatmak için /start komutunu gönder." #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "Bu sohbette başlamış bir oyun yok" #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "Oyun henüz başlamadı. Oyuna katılmak için /join yaz" "ve oyunu başlatmak için /start komutunu gönder." #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "Yalnızca oyunun kurucusu ({name}) ve yönetici bunu yapabilir." #: bot.py:146 msgid "The lobby is closed" msgstr "Girişler kapatıldı" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "Şu anda oyun mevcut değil. /new ile yeni bir oyun oluşturabilirsin." #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "Zaten oyuna katıldın. Oyunu başlatmak için /start komutunu kullan" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "Yeni oyuncuların katılması için destede yeterli kart kalmadı." #: bot.py:168 msgid "Joined the game" msgstr "Oyuna katıldın" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "Bu gruptaki bir oyunda yoksunuz." #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "Pekala. Sıradaki Oyuncu: {name}" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "{name}, başlamadan oyundan ayrıldı." #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "Oyuncu {name} mevcut oyunda bulunamadı." #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "{0}, {1} tarafından atıldı!" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "Lütfen atmak istediğiniz kişiyi alıntılayarak/kick komutunu yazın" #: bot.py:299 msgid "Game not found." msgstr "Oyun bulunamadı." #: bot.py:304 msgid "Back to last group" msgstr "Son gruba geri dön" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "Lütfen seçtiğiniz gruba geçin!" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "Grup seçildi: {group}\n" " Doğru gruba geçtiğinizden emin olun!" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "{name} oyundan silindi." #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "Bu sohbette şu an oyun yok. /new ile yeni bir oyun oluşturabilirsin." #: bot.py:365 msgid "The game has already started" msgstr "Oyun zaten başladı!" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "Oyun başlatmak için en az {minplayers} kişi oyuna /join yazarak katılmalı." #: bot.py:380 #, python-brace-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "İlk oyuncu: {name}\n" "/close yazarak oyuna daha fazla kişinin katılmasını kapatabilirsin.\n" "Çoklu dili etkinleştirmek için /enable_translations yaz." #: bot.py:417 msgid "Please select the group you want to play in." msgstr "Lütfen oynamak istediğiniz grubu seçin" #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "Girişler kapatıldı. Oyuna daha fazla oyuncu katılamaz." #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "Girişler açıldı. Yeni oyuncular /join yazarak oyuna katılabilir." #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Çoklu dil etkinleştirildi. Kapatmak için /disable_translations yaz." #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Çoklu dil kapatıldı. Açmak için /enable_translations yaz." #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "Bu sohbetteki bir oyunda oynamıyorsun." #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Lütfen {time} saniye bekleyin" msgstr[1] "Lütfen {time} saniye bekleyin" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "Mevcut oyun: {game}" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "Oyun modu değiştirildi: {mode}" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "{name}, hile yapmaya çalıştı!" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "Sıradaki oyuncu: {name}" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "{name} için bekleme süresi {time} saniye olarak sıfırlandı." #: results.py:39 msgid "Choose Color" msgstr "Renk Seç" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Kart (oyun durumu için dokunun):" msgstr[1] "Kartlar (oyun durumu için dokunun):" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name}’ın ({number} kartı kaldı.)" msgstr[1] "{name}’ın ({number} kartı kaldı.)" #: results.py:76 msgid "You are not playing" msgstr "Oyunda değilsin." #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "Şu anda bir oyunda yoksun. Yeni bir oyun kurmak için /new, mevcut oyuna katılmak için /join yaz." #: results.py:90 msgid "The game wasn't started yet" msgstr "Oyun henüz başlamadı" #: results.py:92 msgid "Start the game with /start" msgstr "Oyunu /start ile başlat" #: results.py:102 msgid "🎻 Classic mode" msgstr "🎻 Klasik mod" #: results.py:104 msgid "Classic 🎻" msgstr "Klasik 🎻" #: results.py:114 msgid "🚀 Sanic mode" msgstr "🚀 Fişek mod" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "Daha hızlı ol! 🚀" #: results.py:126 msgid "🐉 Wild mode" msgstr "🐉 Vahşi mod" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "Vahşi doğuya ~ 🐉" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "{number} kart çekildi" msgstr[1] "{number} kart çekildi" #: results.py:167 msgid "Pass" msgstr "Pas" #: results.py:180 msgid "I'm calling your bluff!" msgstr "Blöf yapıyorsun!!" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "Şu anki oyuncu: {name}" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "Son kart: {card}" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Oyuncu: {player_list}" msgstr[1] "Oyuncular: {player_list}" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "Lütfen ayarlarınızı botun özel sohbetinde düzenleyin." #: settings.py:47 msgid "Enable statistics" msgstr "İstatistikleri Aç" #: settings.py:49 msgid "Delete all statistics" msgstr "Tüm istatistikleri sil" #: settings.py:51 msgid "Language" msgstr "Dil" #: settings.py:52 msgid "Settings" msgstr "Ayarlar" #: settings.py:66 msgid "Enabled statistics!" msgstr "İstatistikler açıldı!" #: settings.py:72 msgid "Select locale" msgstr "Dili seçiniz" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "İstatistikler devredışı bırakıldı ve silindi!" #: settings.py:95 msgid "Set locale!" msgstr "Dil seçildi!" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Şu adımları takip edin:\n" "\n" "1. Botu grubunuza ekleyin\n" "2. Grupta /new ile yeni bir oyun oluştur ya da " "/join ile mevcut oyuna katıl\n" "3. En az 2 oyuncu katıldıktan sonra oyuna, /start yazarak başlayın\n" "4. Sohbete @unobot yazıp boşluk bırakın ya da " "@unobot aracılığıyla yazısına dokunun. " "Kendi kartlarını (bazıları soluk renkte) göreceksin, ekstra seçenekler: kart çekme (drawing) kart almanızı sağlar, ve ? işareti " "oyun durumunu size bildirir. Gri renkli kartların anlamı şu anda bunu " "oynayamazsın demektir. Bir işlem yapmak için seçeneklere dokunun.\n" "Oyuncular oyuna herhangi bir zamanda katılabilir. Ayrılmak için /leave yazabilir. " "Oyuncu 90 saniyeden uzun süredir oynamadıysa sırayı atlamak için /skip yazabilirsin. " "Yeni bir oyun başladığında özel bir bildirim almak için /notify_me komutunu kullanabilirsiniz. " "\n" "Dil veya diğer ayarlar için: /settings\n" "Diğer komutlar: (sadece kurucu)\n" "/close - Girişleri kapar\n" "/open - Girişleri açar\n" "/kill - Oyunu sonlandırır\n" "/kick - Alıntılanarak yazılan oyuncu oyundan atılır\n" "/enable_translations - İlgili metinleri konuşulan tüm " "tüm dillere çevirir\n" "/disable_translations - Bu metinleri ingilizce gösterir\n" "\n" "Denenebilir: Aynı anda birden fazla grupta oynayın. " "Mevcut oyun: ... butonu ile oynamak istediğiniz grubu seçin\n" "Eğer bu botu sevdiysen, beni oyla, kanala katıl ve UNO oyun kartları satın al." #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "" "Bu UNO Botunun 3 oyun modu mevcut: Klasik, Hızlı ve Vahşi.\n" "\n" "🎻 Klasik mod, geleneksel UNO destesini kullanır ve otomatik olarak sırayı geçmez.\n " "🚀 Fişek mod, geleneksel UNO destesini kullanır ve bir oyuncu çok uzun süre oynamazsa sırasını atlar.\n" "🐉 Vahşi mod, daha özel kartlarla, daha az sayıda çeşitlilik içeren bir deste kullanır ve otomatik olarak sırayı geçmez.\n" "\n" "Oyun modunu değiştirmek için OYUN KURUCUSU botun kullanıcı adını yazıp tıpkı bir kart oynar gibi boşluk bırakarak tüm oyun modları ayarlarına gitmelidir." #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "Bu bot Açık Kaynak ve AGPL lisanslıdır. Kodları " "burada: \n" "https://github.com/jh0ker/mau_mau_bot" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "Teşekkürler:\n" "Çekme simgesi Faithtoken\n" "Pas simgesi Delapouite\n" "Orijinalleri http://game-icons.net\n" "ɳick taradından düzenlendi.\n" "Türkçe çevirisi: @holytotem tarafından yapılmıştır." #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "Tüm yenilikler burada: https://telegram.me/unobotnews" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "İstatistikleri etkinleştirmediniz. Bota özel sohbetten/settings komutunu gönder" "ve istatistik ayarını aç" #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} Oyun oynandı" msgstr[1] "{number} Oyun oynandı" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} Defa birincilik ({percent}%)" msgstr[1] "{number} Defa birincilik ({percent}%)" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} Kart oynandı" msgstr[1] "{number} Kart oynandı" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "{emoji} Kırmızı" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "{emoji} Mavi" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "{emoji} Yeşil" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "{emoji} Sarı" ================================================ FILE: locales/unobot.pot ================================================ # SOME DESCRIPTIVE TITLE. # This file is put in the public domain. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 1.0\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2019-08-28 14:21+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "" #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "" #: actions.py:101 msgid "Please choose a color" msgstr "" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "" #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "" #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "" #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "" #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "" #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "" #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "" #: bot.py:146 msgid "The lobby is closed" msgstr "" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "" #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "" #: bot.py:168 msgid "Joined the game" msgstr "" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "" #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "" #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "" #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "" #: bot.py:299 msgid "Game not found." msgstr "" #: bot.py:304 msgid "Back to last group" msgstr "" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "" #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "" #: bot.py:365 msgid "The game has already started" msgstr "" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "" #: bot.py:380 #, python-brace-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" #: bot.py:417 msgid "Please select the group you want to play in." msgstr "" #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "" #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "" #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "" #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "" #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "" msgstr[1] "" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "" #: results.py:39 msgid "Choose Color" msgstr "" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "" msgstr[1] "" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "" msgstr[1] "" #: results.py:76 msgid "You are not playing" msgstr "" #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" #: results.py:90 msgid "The game wasn't started yet" msgstr "" #: results.py:92 msgid "Start the game with /start" msgstr "" #: results.py:102 msgid "🎻 Classic mode" msgstr "" #: results.py:104 msgid "Classic 🎻" msgstr "" #: results.py:114 msgid "🚀 Sanic mode" msgstr "" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "" #: results.py:126 msgid "🐉 Wild mode" msgstr "" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "" msgstr[1] "" #: results.py:167 msgid "Pass" msgstr "" #: results.py:180 msgid "I'm calling your bluff!" msgstr "" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "" msgstr[1] "" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "" #: settings.py:47 msgid "Enable statistics" msgstr "" #: settings.py:49 msgid "Delete all statistics" msgstr "" #: settings.py:51 msgid "Language" msgstr "" #: settings.py:52 msgid "Settings" msgstr "" #: settings.py:66 msgid "Enabled statistics!" msgstr "" #: settings.py:72 msgid "Select locale" msgstr "" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "" #: settings.py:95 msgid "Set locale!" msgstr "" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "" #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "" #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "" msgstr[1] "" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "" msgstr[1] "" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "" msgstr[1] "" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "" ================================================ FILE: locales/uz_UZ/LC_MESSAGES/unobot.po ================================================ # SOME DESCRIPTIVE TITLE. # This file is put in the public domain. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 1.0\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2019-08-28 14:21+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Shohrux V \n" "Language-Team: Uzbek \n" "Language: uz_UZ\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" "Bu oʻyinchini oʻtkazib yuborishni kutish vaqti {time} soniyagacha qisqartirildi.\n" "Keyingi oʻyinchi: {name}" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "{player} oʻtkazib yuborildi!" #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "" "{name1}ning vaqti tugadi va oʻyindan olib tashlandi!\n" "Keyingi oʻyinchi: {name2}" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "" "{name}ning vaqti tugadi va oʻyindan olib tashlandi!\n" "Oʻyin tugadi." #: actions.py:101 msgid "Please choose a color" msgstr "Iltimos, rang tanlang" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "{name} goʻlib bo'ldi!" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "Oʻyin tugadi!" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "Toʻplamda boshqa kartalar yoʻq." #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Soxta chaqiruv! {name}ga 4 ta karta berilmoqda" #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} soxta emas! {name2}ga 6 ta karta berilmoqda" #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "Bu buyruqni guruhga yuboring va u yerda yangi oʻyin boshlanganda xabardor boʻling." #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "{title} oʻyinida yangi oʻyin boshlandi" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "Yangi oʻyin yaratildi! Oʻyinga /join bilan qoʻshiling va oʻyinni /start bilan boshlang" #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "Bu chatda hech qanday oʻynadigan oʻyin yoʻq." #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "O'yin hali boshlanmadi. Oʻyinga /join bilan qoʻshiling va oʻyinni " "/start bilan boshlang" #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "Buni faqat oʻyin yaratuvchisi ({name}) va administrator qila oladi." #: bot.py:146 msgid "The lobby is closed" msgstr "Lobbi yopiq" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "Hozirda hech qanday oʻyin ishlamayapti. /new bilan yangi oʻyin yarating" #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "Siz allaqachon oʻyinga qoʻshilgansiz. Oʻyinni /start bilan boshlang" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "Yangi oʻyinchilar qoʻshilishi uchun toʻplamda yetarlicha kartalar qolmadi." #: bot.py:168 msgid "Joined the game" msgstr "Oʻyinga qoʻshildi" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "Siz ushbu guruhdagi oʻyinda oʻynamayapsiz." #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "Yaxshi. Keyingi oʻyinchi: {name}" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "{name} oʻyin boshlanishidan oldin oʻyinni tark etdi." #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "{name} oʻyinchisi joriy oʻyinda topilmadi." #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "{0}ni {1} tepdi" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "Iltimos, tepmoqchi boʻlgan odamga javob bering va yana /kick ni kiriting." #: bot.py:299 msgid "Game not found." msgstr "Oʻyin topilmadi." #: bot.py:304 msgid "Back to last group" msgstr "Oxirgi guruhga qaytish" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "Iltimos, siz tanlagan guruhga oʻting!" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Tanlangan guruh: {group}\n" "Toʻgʻri guruhga oʻtganingizga ishonch hosil qiling!" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "{name} oʻyindan olib tashlanmoqda" #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "Bu chatda hech qanday o‘yin ishlamayapti. /new bilan yangisini yarating" #: bot.py:365 msgid "The game has already started" msgstr "O'yin allaqachon boshlangan" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "" "Oʻyinni boshlashdan oldin kamida {minplayers} oʻyinchi ishtirok etishi kerak." "/join bosing!" #: bot.py:380 #, python-brace-format, fuzzy msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Birinchi o'yinchi: {name}\n" "Odamlarning oʻyinga qoʻshilishini toʻxtatish uchun /close tugmasidan foydalaning.\n" "/enable_translations Koʻp tarjimalar funksiyasini yoqing" #: bot.py:417 msgid "Please select the group you want to play in." msgstr "Iltimos, oʻynamoqchi boʻlgan guruhni tanlang." #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "Lobbi yopildi. Bu oʻyinga boshqa oʻyinchilar qoʻshila olmaydi." #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "Lobbi ochildi. Yangi o'yinchilar o'yinga qo'shilishlari mumkin." #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Ko'p tarjimalar funksiyasi yoqilgan. Uni o'chirish uchun /disable_translations tugmani bosing" #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "" "Ko'p tarjimalar funksiyasi o'chirilgan. /enable_translations bilan ularni yana yoqing" #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "Siz bu chatdagi oʻyinda oʻynamayapsiz." #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Iltimos, {time} soniya kuting" msgstr[1] "Iltimos, {time} soniya kuting" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "Joriy oʻyin: {game}" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "Oʻyin rejimi {mode}ga oʻzgartirildi" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "{name} tomonidan firibgarlik urinishi" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "Keyingi oʻyinchi: {name}" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "{name} uchun kutish vaqti {time} soniyaga qaytarildi" #: results.py:39 msgid "Choose Color" msgstr "Rang tanlang" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Hozir sizga bor kartalar (oʻyin holatini koʻrish uchun bosing)" msgstr[1] "Hozir sizga bor kartalar (oʻyin holatini koʻrish uchun bosing)" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} karta bor)" msgstr[1] "{name} ({number} karta bor)" #: results.py:76 msgid "You are not playing" msgstr "Siz oʻynamayapsiz" #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "Hozir oʻynamayapti. Oʻyinni boshlash uchun /new tugmasidan foydalaning" "yoki ushbu guruhdagi joriy oʻyinga qoʻshiling." #: results.py:90 msgid "The game wasn't started yet" msgstr "Oʻyin hali boshlanmadi" #: results.py:92 msgid "Start the game with /start" msgstr "Oʻyinni /start tugmasi bilan boshlang" #: results.py:102 msgid "🎻 Classic mode" msgstr "🎻 Klassik rejimi" #: results.py:104 msgid "Classic 🎻" msgstr "Klassik 🎻" #: results.py:114 msgid "🚀 Sanic mode" msgstr "🚀 Sanik rejimi" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "Tez borish kerak! 🚀" #: results.py:126 msgid "🐉 Wild mode" msgstr "🐉 Wild rejimi" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "Wild tabiatga~ 🐉" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "{number} ta karta koʻtarildi" msgstr[1] "{number} ta karta koʻtarildi" #: results.py:167 msgid "Pass" msgstr "Oʻtish" #: results.py:180 msgid "I'm calling your bluff!" msgstr "Men sizning soxtaligingizni chaqiraman!" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "Joriy oʻyinchi: {name}" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "Oxirgi karta: {card}" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Oʻyinchi: {player_list}" msgstr[1] "Oʻyinchi: {player_list}" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "Iltimos, sozlamalaringizni bot bilan shaxsiy chatda tahrirlang." #: settings.py:47 msgid "Enable statistics" msgstr "Statistikani yoqing" #: settings.py:49 msgid "Delete all statistics" msgstr "Barcha statistikani o'chirib tashlang" #: settings.py:51 msgid "Language" msgstr "Til" #: settings.py:52 msgid "Settings" msgstr "Sozlamalar" #: settings.py:66 msgid "Enabled statistics!" msgstr "Statistika yoqilgan" #: settings.py:72 msgid "Select locale" msgstr "Mahalliy tilni tanlang" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "Statistika o'chirilgan!" #: settings.py:95 msgid "Set locale!" msgstr "Mahalliy til sozlang!" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Quyidagi amallarni bajaring:\n" "\n" "1. Ushbu botni guruhga qo'shing\n" "2. Guruhda /new bilan yangi o‘yinni boshlang yoki /join bilan allaqachon ishlayotgan o‘yinga qo‘shiling\n" "3. Kamida ikkita o‘yinchi qo‘shilgandan so‘ng, o‘yinni /start bilan boshlang\n" "4. Chat maydoniga @unobot so‘zini kiriting va bo‘sh joy tugmasini bosing" "yoki xabarlar yonidagi @unobot orqali matnni bosing." "Siz kartalaringizni (ba'zilari kul rangda), koʻtarish kabi qoʻshimcha" "variantlarni va ? joriy oʻyin holatini koʻrish uchun." "Kulrang kartalar - bu siz hozir oʻynay olmaydigan kartalar." "Tanlangan amalni bajarish uchun variantni bosing.\n" "Oʻyinchilar oʻyinga istalgan vaqtda qoʻshilishlari mumkin." "Oʻyinni tark etish uchun /leave dan foydalaning." "Agar oʻyinchi oʻynash uchun 90 soniyadan koʻproq vaqt talab qilsa," "oʻyinchini oʻtkazib yuborish uchun /skip dan foydalanishingiz mumkin." "Yangi oʻyin boshlanganda shaxsiy xabar olish uchun /notify_me dan foydalaning.\n" "\n" "Til va boshqa sozlamalar: /settings\n" "Boshqa buyruqlar (faqat oʻyin yaratuvchisi uchun):" "/close - Lobbini yopish\n" "/open - Lobbini ochish\n" "/kill - Oʻyinni tugatish\n" "/kick - Tepadigan oʻyinchiga javob berish orqali uni tanlash\n" "/enable_translations - Tegishli matnlarni o'yinda aytiladigan barcha tillarga tarjima qilish\n" "/disable_translations - Ushbu matnlar uchun ingliz tilidan foydalaning\n" "\n" "Tajriba: bir vaqtning oʻzida bir nechta guruhlarda oʻynash\n" "Joriy oʻyin: ... tugmasini bosing va karta oʻynamoqchi boʻlgan guruhni tanlang.\n" "Agar sizga ushbu bot yoqsa, menga baho bering, yangilanish kanaliga qoʻshiling va UNO karta oʻyinini sotib oling." #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "" "Ushbu UNO boti uchta o'yin rejimiga ega: Klassik, Sanik va Wild.\n" "\n" "🎻 Klassik rejim an'anaviy UNO toʻplamdan foydalanadi" "va avtomatik oʻtkazib yuborish yoʻq.\n" "🚀 Sanik rejimi an'anaviy UNO toʻplamdan foydalanadi" "va agar oʻyinchi oʻz navbatini oʻynash uchun juda uzoq vaqt" "talab qilsa, bot avtomatik ravishda uni oʻtkazib yuboradi.\n" "🐉 Wild rejim koʻproq maxsus kartalar, kamroq raqam turlari" "va avtomatik oʻtkazib yuborishsiz toʻplamdan foydalanadi." "\n" "Oʻyin rejimini oʻzgartirish uchun GAME CREATOR xuddi karta oʻynayotganda" "boʻlgani kabi bot nikini va boʻsh joyni kiritishi kerak va oʻyin" "rejimining barcha variantlari paydo boʻlishi kerak." #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "Bu bot bepul dasturiy ta'minot bo'lib, AGPL litsenziyasiga ega." "Kodni bu yerda topishingiz mumkin: \n" "https://github.com/jh0ker/mau_mau_bot" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "" "Yaratuvchilar:\n" "Faithtoken tomonidan \"Draw\" belgisi\n" "Delapouite tomonidan \"Pass\" belgisi\n" "Asl http://game-icons.net da mavjud\n." "ɳick tomonidan tahrirlangan belgilar" #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "Barcha yangiliklar bu yerda: https://telegram.me/unobotnews" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "Siz statistikani yoqmagansiz. Ularni yoqish uchun bot bilan shaxsiy" "chatda /settings dan foydalaning." #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} oʻyini oʻynaldi" msgstr[1] "{number} oʻyini oʻynaldi" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} birinchi oʻrin ({percent}%)" msgstr[1] "{number} birinchi oʻrin ({percent}%)" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} ta karta oʻynadi" msgstr[1] "{number} ta karta oʻynadi" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "{emoji} Qizil" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "{emoji} Koʻk" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "{emoji} Yashil" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "{emoji} Sariq" ================================================ FILE: locales/vi_VN/LC_MESSAGES/unobot.po ================================================ # SOME DESCRIPTIVE TITLE. # This file is put in the public domain. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: uno_bot 1.0\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2023-03-05 14:21+0800\n" "PO-Revision-Date: 2023-03-05\n" "Last-Translator: Lê Minh Sơn\n" "Language-Team: LANGUAGE \n" "Language: vi_VN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" "Thời gian chờ để bỏ qua người chơi này đã giảm xuống còn {time} giây.\n" "Người chơi tiếp theo: {name}" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "{player} đã bị bỏ qua! " #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "" "{name1} đã hết thời gian và đã bị xóa khỏi trò chơi!\n" "Người chơi tiếp theo: {name2}" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "" "{name} đã hết thời gian và đã bị xóa khỏi trò chơi!\n" "Trò chơi kết thúc." #: actions.py:101 msgid "Please choose a color" msgstr "Hãy chọn một màu may mắn" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "{name} thắng!" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "Nước mắt anh rơi trò chơi kết thúc" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "Không còn thẻ nào trong bộ bài." #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Thần may mắn gọi! Đưa 4 lá bài cho {name}" #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} không bịp! Đưa 6 thẻ cho {name2}" #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "" "Gửi lệnh này trong một nhóm để được thông báo khi trò chơi mới bắt đầu ở đó." #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "Một trò chơi mới đã được bắt đầu trong {title}" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "" "Đã tạo một trò chơi mới! Tham gia trò chơi với /join và bắt đầu trò chơi với /start" #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "Không có trò chơi đang chạy trong cuộc trò chuyện này." #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "" "Trò chơi chưa bắt đầu. Tham gia trò chơi với /join và bắt đầu trò chơi " "với /start" #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "Chỉ người tạo trò chơi ({name}) và quản trị viên mới có thể làm điều đó." #: bot.py:146 msgid "The lobby is closed" msgstr "Sảnh đóng cửa" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "Không có trò chơi đang chạy tại thời điểm này. Tạo một trò chơi mới với /new" #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "Bạn đã tham gia trò chơi. Bắt đầu trò chơi với /start" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "Không còn đủ lá trong bộ bài để người chơi mới tham gia." #: bot.py:168 msgid "Joined the game" msgstr "Đã tham gia trò chơi" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "Bạn không chơi trong một trò chơi trong nhóm này." #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "Được rồi. Người chơi tiếp theo: {name}" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "{name} đã rời khỏi trò chơi trước khi trò chơi bắt đầu." #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "Không tìm thấy người chơi {name} trong trò chơi hiện tại." #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "{0} đã bị đá bởi {1}" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "Vui lòng trả lời người bạn muốn đá và gõ lại /kick một lần nữa." #: bot.py:299 msgid "Game not found." msgstr "Không thấy ván bài nào cả." #: bot.py:304 msgid "Back to last group" msgstr "Quay lại nhóm trước" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "Vui lòng chuyển sang nhóm bạn đã chọn!" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "Nhóm được chọn: {group}\n" "Đảm bảo rằng bạn chuyển sang đúng nhóm!" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "Đang xóa {name} khỏi trò chơi" #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "Không có trò chơi đang chạy trong cuộc trò chuyện này. Tạo một cái mới với /new" #: bot.py:365 msgid "The game has already started" msgstr "Trò chơi đã bắt đầu" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "" "Ít nhất {minplayers} người chơi phải /join trò chơi trước khi bạn có thể bắt đầu trò chơi" #: bot.py:380 #, python-brace-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "Người chơi đầu tiên: {name}\n" "Sử dụng /close để ngăn mọi người tham gia trò chơi.\n" "Bật nhiều bản dịch với /enable_translations" #: bot.py:417 msgid "Please select the group you want to play in." msgstr "Vui lòng chọn nhóm bạn muốn chơi." #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "Đóng cửa sảnh. Không còn người chơi nào có thể tham gia trò chơi này." #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "Đã mở sảnh. Người chơi mới có thể /join để tham gia trò chơi." #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "Đã bật nhiều bản dịch. Vô hiệu hóa với /disable_translations" #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "Đã tắt đa bản dịch. Kích hoạt lại chúng với /enable_translations" #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "Bạn không chơi bài trong đoạn chat này." #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "Vui lòng đợi {time} giây" msgstr[1] "Vui lòng đợi {time} giây" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "Ván hiện tại: {game}" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "Chế độ trò chơi thay đổi thành {mode}" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "Lỗ lực gian lận bởi {name}" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "Người chơi tiếp theo: {name}" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "Thời gian chờ của {name} đã được đặt lại thành {time} giây" #: results.py:39 msgid "Choose Color" msgstr "Chọn màu may mắn" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "Lá bài (nhấn để biết trạng thái trò chơi):" msgstr[1] "Lá bài (nhấn để biết trạng thái trò chơi):" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} lá bài)" msgstr[1] "{name} ({number} lá bài)" #: results.py:76 msgid "You are not playing" msgstr "Bạn không chơi" #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "Không chơi ngay bây giờ. Sử dụng /new để bắt đầu trò chơi hoặc /join để tham gia " "trò chơi trong nhóm này" #: results.py:90 msgid "The game wasn't started yet" msgstr "Ván bài vẫn chưa bắt đầu" #: results.py:92 msgid "Start the game with /start" msgstr "Bắt đầu vắn bài với /start" #: results.py:102 msgid "🎻 Classic mode" msgstr "🎻 Chế độ cổ điển" #: results.py:104 msgid "Classic 🎻" msgstr "Cổ điển 🎻" #: results.py:114 msgid "🚀 Sanic mode" msgstr "🚀 Chế độ Sanic" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "Phải đi nhanh! 🚀" #: results.py:126 msgid "🐉 Wild mode" msgstr "🐉 Chế độ hoang dã" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "Lạc vào thế giới hoang dã~ 🐉" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Thêm {number} lá bài" msgstr[1] "Thêm {number} lá bài" #: results.py:167 msgid "Pass" msgstr "Qua" #: results.py:180 msgid "I'm calling your bluff!" msgstr "Tôi đang gọi lá bài của bạn" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "Bàn hiện tại là: {name}" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "Lá bài cuối: {card}" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "Người chơi: {player_list}" msgstr[1] "Người chơi: {player_list}" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "Vui lòng chỉnh sửa cài đặt của bạn trong cuộc trò chuyện riêng tư với bot." #: settings.py:47 msgid "Enable statistics" msgstr "Bật thống kê" #: settings.py:49 msgid "Delete all statistics" msgstr "Xoá tất cả dữ liệu thống kê" #: settings.py:51 msgid "Language" msgstr "Ngôn ngữ" #: settings.py:52 msgid "Settings" msgstr "Cài đặt" #: settings.py:66 msgid "Enabled statistics!" msgstr "Đã bật thống kê" #: settings.py:72 msgid "Select locale" msgstr "Chọn ngôn ngữ" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "Đã xóa và vô hiệu hóa số liệu thống kê!" #: settings.py:95 msgid "Set locale!" msgstr "Đặt ngôn ngữ!" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "Làm theo các bước sau:\n" "\n" "1. Thêm bot này vào một nhóm\n" "2. Trong nhóm, bắt đầu một trò chơi mới với /new hoặc tham gia một trò chơi đang chạy " "với /tham gia\n" "3. Sau khi có ít nhất hai người chơi tham gia, hãy bắt đầu trò chơi với /start\n" "4. Nhập @unobot vào hộp trò chuyện của bạn và nhấn dấu cách hoặc " "nhấp vào văn bản qua @unobot bên cạnh tin nhắn. Bạn sẽ thấy" "thẻ (một số bị mờ đi), bất kỳ tùy chọn bổ sung nào như vẽ và ? để " "xem trạng thái trò chơi hiện tại. các thẻ chuyển sang màu xám là những thẻ bạn có thể" "hiện không phát. Nhấn vào một tùy chọn để thực hiện hành động đã chọn.\n" "Người chơi có thể tham gia trò chơi bất cứ lúc nào. Để rời khỏi trò chơi, hãy sử dụng /leave. Nếu a" "người chơi mất hơn 90 giây để chơi, bạn có thể sử dụng /skip để bỏ qua phần đó" "người chơi. Sử dụng /notify_me để nhận tin nhắn riêng khi có trò chơi mới " "đã bắt đầu.\n" "\n" "Ngôn ngữ và các cài đặt khác: /settings\n" "Các lệnh khác (chỉ người tạo trò chơi):\n" "/đóng - Đóng sảnh\n" "/open - Mở sảnh\n" "/kill - Chấm dứt trò chơi\n" "/kick - Chọn một người chơi để kick bằng cách trả lời người đó\n" "/enable_translations - Dịch các văn bản có liên quan sang tất cả các ngôn ngữ có trong" "trò chơi\n" "/disable_translations - Sử dụng tiếng Anh cho những văn bản đó\n" "\n" "Thử nghiệm: Chơi trong nhiều nhóm cùng lúc. Nhấn nút " "Trò chơi hiện tại: ... và chọn nhóm bạn muốn chơi" "bài.\n" "Nếu bạn thích bot này, đánh giá tôi, tham gia kênh cập nhật và mua bài UNO." #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "Bot UNO này có ba chế độ chơi: Cổ điển, Sanic và Hoang dã.\n" "🎻 Chế độ Cổ điển sử dụng bộ bài UNO thông thường và không có tự động " "bỏ qua.\n" "🚀 Chế độ Sanic sử dụng bộ bài UNO thông thường và bot tự động " "bỏ qua một người chơi nếu anh ấy/cô ấy mất quá nhiều thời gian để chơi lượt của mình\n" "🐉 Chế độ Wild sử dụng bộ bài có nhiều quân bài đặc biệt hơn, số lượng ít đa dạng hơn" "và không tự động bỏ qua.\n" "\n" "Để thay đổi chế độ trò chơi, NGƯỜI TẠO TRÒ CHƠI phải nhập username bot và " "dấu cách, giống như khi chơi bài và tất cả các tùy chọn chế độ chơi sẽ xuất hiện." #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "Bot này là Phần mềm Tự do và được cấp phép theo AGPL. Mã có sẵn" "ở đây: \n" "https://github.com/jh0ker/mau_mau_bot" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "Thiết kế:\n" "Vẽ biểu tượng bởi Faithtoken\n" "Biểu tượng bỏ qua bởi Delapouite\n" "Chình sửa biểu tượng bởi ɳick" #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "Tin tức mới về bot ở đây: https://telegram.me/unobotnews" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "Bạn chưa kích hoạt thống kê. Sử dụng /settings trong cuộc trò chuyện riêng với bot " "để kích hoạt." #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "{number} ván đã chơi" msgstr[1] "{number} ván đã chơi" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "{number} vị trí đầu tiên ({percent}%)" msgstr[1] "{number} vị trí đầu tiên ({percent}%)" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "{number} bài đã chơi" msgstr[1] "{number} bài đã chơi" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "{emoji} Đỏ" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "{emoji} Xanh da trời" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "{emoji} Xanh lá cây" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "{emoji} Vàng" ================================================ FILE: locales/zh_CN/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2019-08-28 14:21+0800\n" "PO-Revision-Date: 2020-04-13 09:50+0800\n" "Last-Translator: XhyEax \n" "Language-Team: en \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.2.4\n" "Plural-Forms: nplurals=1; plural=0;\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" "该玩家的等待时间已降至 {time} 秒。\n" "轮到: {name}" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "{player} 已被跳过! " #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "" "{name1} 已经被连续跳过了 4 次。\n" "轮到: {name2}" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "" "{name} 已经被连续跳过了 4 次。\n" "游戏结束。" #: actions.py:101 msgid "Please choose a color" msgstr "请选择颜色" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "{name} 赢了!" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "游戏结束!" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "牌堆中已经没有更多的牌了。" #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "质疑成功!给 {name} 4 张牌" #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "质疑 {name1} 失败!给 {name2} 6 张牌" #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "在群组中发送该指令,以在新游戏开始时通知您。" #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "新游戏已在 {title} 开始" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "创建新游戏成功!请使用 /join 加入游戏,然后使用 /start 开始游戏" #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "这个群中并没有正在运行的游戏。" #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "游戏尚未开始。请使用 /join 加入游戏,然后使用 /start 开始游戏" #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "只有游戏创建者 ({name}) 和管理员才能执行该命令。" #: bot.py:146 msgid "The lobby is closed" msgstr "已禁止中途加入游戏" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "这个群并没有运行中的游戏。请使用 /new 创建新游戏" #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "您已经加入了游戏。请使用 /start 开始游戏" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "牌堆中已经没有足够给新加入玩家的牌了。" #: bot.py:168 msgid "Joined the game" msgstr "游戏加入成功" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "您在这个群中并没有参加游戏。" #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "好的,轮到: {name}" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "{name} 在游戏开始前就离开游戏了。" #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "未在当前游戏中找到{name}玩家。" #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "{0} 已被 {1} 踢出游戏" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "请回复要踢出的人,并再次输入 /kick 。" #: bot.py:299 msgid "Game not found." msgstr "游戏未找到。" #: bot.py:304 msgid "Back to last group" msgstr "返回上一个群" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "请切换到您选择的群!" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "选择群: {group}\n" "请确保您已切换到正确的群!" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "已成功将 {name} 移出游戏" #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "这个群并没有运行中的游戏。请使用 /new 创建新游戏" #: bot.py:365 msgid "The game has already started" msgstr "游戏已经开始" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "至少需要 {minplayers} 个人 /join 加入游戏,才能开始游戏" #: bot.py:380 #, python-brace-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "第一个出牌的玩家: {name}\n" "可使用 /close 阻止其他人中途加入游戏。\n" "使用 /enable_translations 启动游戏翻译功能" #: bot.py:417 msgid "Please select the group you want to play in." msgstr "请选择您要参加游戏的群。" #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "游戏已设置成不允许中途加入,玩家将不允许加入游戏。" #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "游戏已设置成允许中途加入,新玩家现在可以使用 /join 加入游戏。" #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "游戏翻译已启用,使用 /disable_translations 可以停用该功能" #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "游戏翻译已停用,使用 /enable_translations 可以启用该功能" #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "您并不在游戏中。" #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "请等待 {time} 秒" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "当前游戏: {game}" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "游戏模式已切换为 {mode}" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "{name} 试图作弊" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "轮到: {name}" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "{name} 的等待时间已经重置为 {time} 秒" #: results.py:39 msgid "Choose Color" msgstr "选择颜色" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "手牌 (点击查看游戏状况):" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} 张牌)" #: results.py:76 msgid "You are not playing" msgstr "您并不在游戏中" #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "您并不在游戏中。请使用 /new 创建一个新游戏,或者使用 /join 加入一个现有的游戏" #: results.py:90 msgid "The game wasn't started yet" msgstr "游戏还没有开始" #: results.py:92 msgid "Start the game with /start" msgstr "请先使用 /start 开始游戏" #: results.py:102 msgid "🎻 Classic mode" msgstr "🎻 经典模式" #: results.py:104 msgid "Classic 🎻" msgstr "经典 🎻" #: results.py:114 msgid "🚀 Sanic mode" msgstr "🚀 Sanic 模式" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "搞快点! 🚀\"" #: results.py:126 msgid "🐉 Wild mode" msgstr "🐉 野性模式" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "进入旷野~ 🐉" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "抽取 {number} 张牌" #: results.py:167 msgid "Pass" msgstr "过" #: results.py:180 msgid "I'm calling your bluff!" msgstr "我要质疑你!" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "轮到: {name}" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "上一张牌: {card}" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "玩家: {player_list}" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "请私聊我修改您的设置。" #: settings.py:47 msgid "Enable statistics" msgstr "启用数据统计" #: settings.py:49 msgid "Delete all statistics" msgstr "删除所有统计数据" #: settings.py:51 msgid "Language" msgstr "语言" #: settings.py:52 msgid "Settings" msgstr "设置" #: settings.py:66 msgid "Enabled statistics!" msgstr "数据统计已启用!" #: settings.py:72 msgid "Select locale" msgstr "请选择语言" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "统计数据已经被删除并已停用!" #: settings.py:95 msgid "Set locale!" msgstr "语言设置成功!" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "游戏指引:\n" "\n" "1. 将这个 Bot 加进一个群\n" "2. 在这个群中,您可以使用 /new 创建一个新游戏,或者使用 /join 加入一个现有的" "游戏\n" "3. 当有最少两名玩家加入后,请使用 /start 开始游戏\n" "4. 在聊天框中输入 @unobot 并按空格键,或者点击信息旁边的 " "via @unobot 。您就可以看到您的手牌,以及一些像抽牌这样的选项, " "? 选项用来查看当前游戏状态。 灰色的牌 是您当前 不可以 打" "出的。请选择其中的一个选项。\n" "玩家随时可以加入游戏,如果想要离开当前的游戏,请输入 /leave 。如果玩家超过 " "90 秒没有出牌,您可以使用 /skip 跳过这个玩家\n" "\n" "语言 和其他设置: /settings \n" "其他命令(仅限游戏创建者使用)\n" "/close - 不允许其他人中途加入\n" "/open - 允许其他人中途加入\n" "/enable_translations - 翻译文本给游戏中所有使用不同语言的玩家\n" "/disable_translations - 关闭翻译并使用英文\n" "\n" "实验性功能: 玩家可以同时在多个群组中进行游戏。点击 当前游" "戏: ... 按钮然后选择您想在哪个群组玩。\n" "如果喜欢这个机器人, 请给机器人 评分 ,订阅 更新频道 获取最新消息,并买一副 UNO 牌。" #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "" "本机器人有三种游戏模式: 传统、Sanic 及野性 (Wild) 模式。\n" " 🎻 传统模式使用常见的 UNO 卡组,且不会自动跳过。\n" " 🚀 Sanic 模式使用常见的 UNO 卡组,且机器人会自动跳过闲置过久的玩家。\n" " 🐉 野性 (Wild) 模式使用功能牌较多、数字牌较少的卡组,并且不会自动跳过。\n" "\n" "如果要切换游戏模式,游戏创建者必须输入机器人的使用者名称 + 空格,就像玩游戏那" "样,之后将显示出所有游戏模式选项以供选择。" #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "本机器人是一个在 AGPL 协议下发行的自由软件。源代码可以在这里取得:\n" "https://github.com/jh0ker/mau_mau_bot" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "" "来源:\n" "抽牌图标来自 Faithtoken。\n" "跳过图标來自 Delapouite。\n" "原始图标可在 http://game-icons.net 获取。\n" "图标由 ɳick 编辑" #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "查看机器人的所有更新: https://telegram.me/unobotnews" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "您并没有启用数据统计。请私聊我发送 /settings 进行设置。" #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "玩了 {number} 盘" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "赢了 {number} 盘 ({percent}%)" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "总共出过 {number} 张牌" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "{emoji} 红色" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "{emoji} 蓝色" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "{emoji} 绿色" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "{emoji} 黄色" #~ msgid "Drawing {number} cards" #~ msgstr "抽取 {number} 张牌" ================================================ FILE: locales/zh_HK/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2016-05-23 00:03+0100\n" "PO-Revision-Date: 2016-05-23 10:59+0100\n" "Language-Team: en \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7\n" "Last-Translator: \n" "Plural-Forms: nplurals=1; plural=0;\n" "Language: zh_HK\n" #: bot.py:60 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, " "or click the via @unobot text next to messages. You will " "see your cards (some greyed out), any extra options like drawing, and a ?" " to see the current game state. The greyed out cards are those " "you can not play at the moment. Tap an option to execute the selected " "action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "請跟隨以下指示:\n" "\n" "1. Add呢個bot入去一個group度\n" "2. 輸入/new開展一個新遊戲或者/join加入一個運行緊嘅遊戲\n" "3. 當有兩個玩家加入, 就可以用/start開始遊戲\n" "4. 喺你個chatbox打 @unobot然後禁space或者揀隔離個 " "via @unobot。之後你會見到你嘅手牌或者其他選項例如抽牌, 同埋" "?睇玩家狀態。但灰咗嘅牌就係你出唔到嘅牌, 請揀選其中一個" "選項。\n" "玩家可以喺任何時間加入, 如果想離開, 請打/leave。如果有個玩家90秒內都冇出牌嘅" "話, 你可以用 /skip skip咗佢\n" "\n" "語言同埋其他設定: /settings\n" "遊戲創始人可以用以下嘅command:\n" "/close - 關閉 lobby, 其他人就唔可以中途加入\n" "/open - 開啓 lobby, 令其他人可以中途加入\n" "/enable_translations - 翻譯指示\n" "/disable_translations - 用返英文嘅指示\n" "\n" "試驗功能: 想喺幾個group度同時玩幾個遊戲嘅話, 請揀 Current " "game:...然後揀你想喺邊個group玩\n" "如果你鍾意呢個bot嘅話, 請喺 評分, 然後加入update channel 再買一副UNO。" #: bot.py:88 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "呢個bot係一個免費嘅Software, 根據AGPL授權 \n" "Code可以係呢度搵到\n" "https://github.com/jh0ker/mau_mau_bot" #: bot.py:133 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "已經開始咗新一盤! 用/join加入同埋/start去開始" #: bot.py:152 msgid "The lobby is closed" msgstr "Lobby已經閂咗" #: bot.py:156 msgid "No game is running at the moment. Create a new game with /new" msgstr "宜家冇遊戲運行, 用 /new開展新一盤" #: bot.py:162 msgid "You already joined the game. Start the game with /start" msgstr "你已經加入咗啦, 用 /start開始呢一盤" #: bot.py:167 msgid "Joined the game" msgstr "加入咗" #: bot.py:179 bot.py:191 msgid "You are not playing in a game in this group." msgstr "你唔喺呢個group玩緊" #: bot.py:197 bot.py:258 bot.py:595 msgid "Game ended!" msgstr "遊戲結束!" #: bot.py:201 msgid "Okay. Next Player: {name}" msgstr "OK 下一個: {name}" #: bot.py:219 msgid "Game not found." msgstr "Game not found." #: bot.py:223 msgid "Back to last group" msgstr "去返前一個group" #: bot.py:227 msgid "Please switch to the group you selected!" msgstr "請轉去你揀咗果個group" #: bot.py:233 #, python-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "揀咗呢個group: {group}\n" "記住轉過去正確嘅group" #: bot.py:260 #, python-format msgid "Removing {name} from the game" msgstr "{name} 已經比人踢咗" #: bot.py:273 msgid "There is no game running in this chat. Create a new one with /new" msgstr "呢個對話入面冇遊戲運行緊, 用/new開始新一盤" #: bot.py:278 msgid "The game has already started" msgstr "呢一盤已經開始咗" #: bot.py:281 msgid "At least two players must /join the game before you can start it" msgstr "要有兩個玩家 /join咗先可以開始新一盤" #: bot.py:297 #, python-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "第一個玩家: {name}\n" "唔想其他人加入遊戲嘅話可以選擇 /close\n" "用 /enable_translations 啓用翻譯功能" #: bot.py:321 msgid "Please select the group you want to play in." msgstr "你想喺邊個group玩?" #: bot.py:335 bot.py:361 msgid "There is no running game in this chat." msgstr "呢個對話入面冇嘢玩緊喎" #: bot.py:342 msgid "Closed the lobby. No more players can join this game." msgstr "Lobby已經閂咗, 其他玩家已經冇得加入" #: bot.py:348 bot.py:373 #, python-format msgid "Only the game creator ({name}) can do that." msgstr "只有遊戲創始人先可以做呢個設定" #: bot.py:349 #, python-format msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "啓用咗其他語言, 可以用 /disable_translations 停用" #: bot.py:377 #, python-format msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "已經停用咗其他語言, 想重新嘅話可以揀 /enable_translations" #: bot.py:368 msgid "Opened the lobby. New players may /join the game." msgstr "開咗個lobby, 宜家可以 /join 呢一盤" #: bot.py:386 msgid "You are not playing in a game in this chat." msgstr "你冇喺呢個對話入面玩" #: bot.py:400 #, python-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "請等{time}秒" #: bot.py:413 #, python-format msgid "Waiting time to skip this player has been reduced to {time} second.\n" "Next player: {name}" msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr[0] "" "呢個玩家嘅等待時間已經減少到 {time} 秒\n" "下個: {name}" #: bot.py:424 #, python-format msgid "" "{name1} was skipped four times in a row and has been removed from the game.\n" "Next player: {name2}" msgstr "" "{name1}比人連接skip咗4次, 已經踢咗\n" "下個: {name2}" #: bot.py:432 #, python-format msgid "" "{name} was skipped four times in a row and has been removed from the game.\n" "The game ended." msgstr "" "{name1}比人連接skip咗4次, 已經踢咗\n" "遊戲結束" #: bot.py:455 msgid "All news here: https://telegram.me/unobotnews" msgstr "所有update都喺晒度: https://telegram.me/unobotnews" #: bot.py:513 #, python-format msgid "Current game: {group}" msgstr "宜家玩緊嘅遊戲: {group}" #: bot.py:545 #, python-format msgid "Cheat attempt by {name}" msgstr "{name} chok cheat" #: bot.py:562 msgid "Next player: {name}" msgstr "下一個: {name}" #: bot.py:572 #, python-format msgid "Waiting time for {name} has been reset to 90 seconds" msgstr "Skip {name}嘅時間已經reset咗去90秒" #: bot.py:585 msgid "Please choose a color" msgstr "請揀一隻顏色" #: bot.py:591 #, python-format msgid "{name} won!" msgstr "{name} 贏咗!" #: bot.py:613 bot.py:635 bot.py:647 msgid "There are no more cards in the deck." msgstr "檯上面冇哂牌" #: bot.py:627 #, python-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "Call咗bluff, {name} draw 4張牌" #: bot.py:639 #, python-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1}冇bluff, {name2} draw 6 張牌" #: results.py:38 msgid "Choose Color" msgstr "揀顏色" #: results.py:56 msgid "Last card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "手牌 (遊戲status)" #: results.py:60 results.py:123 results.py:165 msgid "Current player: {name}" msgstr "宜家嘅玩家" #: results.py:61 results.py:124 results.py:167 msgid "Last card: {card}" msgstr "前一張牌: {card}" #: results.py:62 results.py:125 results.py:168 msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "玩家: {player_list}" #: results.py:72 #, python-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} ({number} 張牌)" #: results.py:81 msgid "You are not playing" msgstr "你唔係玩緊喎" #: results.py:83 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "你唔係玩緊喎, 用 /new 開始新一盤或者 /join 加入宜家嘅遊戲" #: results.py:95 msgid "The game wasn't started yet" msgstr "呢一盤仲未開始喎" #: results.py:97 msgid "Start the game with /start" msgstr "用/start開始呢一盤" #: results.py:108 #, python-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "Draw緊{number}張牌" #: results.py:136 msgid "Pass" msgstr "Pass" #: results.py:148 msgid "I'm calling your bluff!" msgstr "我call你bluff" #: settings.py:39 msgid "Please edit your settings in a private chat with the bot." msgstr "請pm個bot修改你嘅設定" #: settings.py:49 msgid "Enable statistics" msgstr "啓用數據記錄" #: settings.py:51 msgid "Delete all statistics" msgstr "刪除所有數據" #: settings.py:53 msgid "Language" msgstr "語言" #: settings.py:54 msgid "Settings" msgstr "設定" #: settings.py:68 msgid "Enabled statistics!" msgstr "已經啓用咗數據記錄!" #: settings.py:70 msgid "Select locale" msgstr "請揀個區域" #: settings.py:81 msgid "Deleted and disabled statistics!" msgstr "已經熄咗同埋delete咗數據記錄" #: settings.py:94 msgid "Set locale!" msgstr "Set咗個區域" #: simple_commands.py msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "你冇啓用數據記錄, pm個bot去啓用" #: simple_commands.py msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "玩咗{number}盤" #: simple_commands.py msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "贏咗{number}次 ({percent}%)" #: simple_commands.py msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "已經玩咗{number}張牌" #: utils.py msgid "{emoji} Green" msgstr "{emoji} 綠色" #: utils.py msgid "{emoji} Red" msgstr "{emoji} 紅色" #: utils.py msgid "{emoji} Blue" msgstr "{emoji} 藍色" #: utils.py msgid "{emoji} Yellow" msgstr "{emoji} 黃色" ================================================ FILE: locales/zh_TW/LC_MESSAGES/unobot.po ================================================ # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . msgid "" msgstr "" "Project-Id-Version: uno_bot 0.1\n" "Report-Msgid-Bugs-To: uno@jhoeke.de\n" "POT-Creation-Date: 2019-08-28 14:21+0800\n" "PO-Revision-Date: 2019-08-28 14:25+0800\n" "Last-Translator: pan93412 \n" "Language-Team: en \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 2.2.3\n" #: actions.py:48 #, python-brace-format msgid "" "Waiting time to skip this player has been reduced to {time} seconds.\n" "Next player: {name}" msgstr "" "跳過此玩家的等待時間已縮短至 {time} 秒。\n" "輪到: {name}" #: actions.py:54 actions.py:69 #, python-brace-format msgid "{player} was skipped! " msgstr "{player} 已被跳過! " #: actions.py:64 #, python-brace-format msgid "" "{name1} ran out of time and has been removed from the game!\n" "Next player: {name2}" msgstr "" "{name1} 已逾時,且已將其從此場遊戲移除!\n" "輪到: {name2}" #: actions.py:76 #, python-brace-format msgid "" "{name} ran out of time and has been removed from the game!\n" "The game ended." msgstr "" "{name} 已逾時,且已將其從此場遊戲移除!\n" "遊戲結束。" #: actions.py:101 msgid "Please choose a color" msgstr "請選擇顏色。" #: actions.py:108 #, python-brace-format msgid "{name} won!" msgstr "{name} 贏了!" #: actions.py:123 bot.py:119 bot.py:199 bot.py:261 bot.py:340 msgid "Game ended!" msgstr "遊戲結束!" #: actions.py:141 actions.py:165 actions.py:179 msgid "There are no more cards in the deck." msgstr "卡堆中已經沒牌了。" #: actions.py:157 #, python-brace-format msgid "Bluff called! Giving 4 cards to {name}" msgstr "已確定為虛張聲勢! 給 {name} 4 張牌。" #: actions.py:171 #, python-brace-format msgid "{name1} didn't bluff! Giving 6 cards to {name2}" msgstr "{name1} 並未虛張聲勢! 給 {name2} 6 張牌。" #: bot.py:60 msgid "" "Send this command in a group to be notified when a new game is started there." msgstr "請將這個指令傳到群組中,以在新遊戲開始時通知您。" #: bot.py:83 #, python-brace-format msgid "A new game has been started in {title}" msgstr "新遊戲已經在 {title} 開始!" #: bot.py:93 msgid "" "Created a new game! Join the game with /join and start the game with /start" msgstr "已建立新遊戲! 使用 /join 加入遊戲,並使用 /start 開始遊戲。" #: bot.py:110 bot.py:433 bot.py:461 bot.py:488 bot.py:516 msgid "There is no running game in this chat." msgstr "此聊天室尚無進行中的遊戲。" #: bot.py:123 bot.py:239 msgid "" "The game is not started yet. Join the game with /join and start the game " "with /start" msgstr "遊戲尚未開始。請使用 /join 加入遊戲,並使用 /start 開始遊戲。" #: bot.py:129 bot.py:281 bot.py:446 bot.py:473 bot.py:501 bot.py:530 #, python-brace-format msgid "Only the game creator ({name}) and admin can do that." msgstr "只有遊戲建立者 ({name}) 及管理員才能執行。" #: bot.py:146 msgid "The lobby is closed" msgstr "遊戲大廳已關閉。" #: bot.py:150 bot.py:232 msgid "No game is running at the moment. Create a new game with /new" msgstr "目前沒有進行中的遊戲。請使用 /new 建立新遊戲。" #: bot.py:156 msgid "You already joined the game. Start the game with /start" msgstr "您已加入遊戲。請使用 /start 開始遊戲。" #: bot.py:162 msgid "There are not enough cards left in the deck for new players to join." msgstr "卡堆中已經沒有足夠給新進玩家的牌了。" #: bot.py:168 msgid "Joined the game" msgstr "已加入遊戲" #: bot.py:181 bot.py:193 msgid "You are not playing in a game in this group." msgstr "您不在此群組的遊戲中。" #: bot.py:204 bot.py:274 #, python-brace-format msgid "Okay. Next Player: {name}" msgstr "好的。下一位玩家: {name}" #: bot.py:210 #, python-brace-format msgid "{name} left the game before it started." msgstr "{name} 在遊戲開始前就離開遊戲了。" #: bot.py:253 #, python-brace-format msgid "Player {name} is not found in the current game." msgstr "未在目前遊戲找到 {name} 玩家。" #: bot.py:260 bot.py:265 #, python-brace-format msgid "{0} was kicked by {1}" msgstr "{0} 被 {1} 踢出。" #: bot.py:269 msgid "Please reply to the person you want to kick and type /kick again." msgstr "請回覆要踢出的人,並再次輸入 /kick 。" #: bot.py:299 msgid "Game not found." msgstr "找不到遊戲。" #: bot.py:304 msgid "Back to last group" msgstr "回到上一個群組" #: bot.py:307 msgid "Please switch to the group you selected!" msgstr "請切換到您選取的群組!" #: bot.py:313 #, python-brace-format msgid "" "Selected group: {group}\n" "Make sure that you switch to the correct group!" msgstr "" "已選擇的群組: {group}\n" "請確保您已切換到正確群組!" #: bot.py:343 #, python-brace-format msgid "Removing {name} from the game" msgstr "將 {name} 從遊戲移除" #: bot.py:360 msgid "There is no game running in this chat. Create a new one with /new" msgstr "此聊天室目前沒有進行中的遊戲,使用 /new 開始新遊戲。" #: bot.py:365 msgid "The game has already started" msgstr "遊戲已經開始。" #: bot.py:369 #, python-brace-format msgid "" "At least {minplayers} players must /join the game before you can start it" msgstr "必須至少要有 {minplayers} 個人 /join 才能開始遊戲。" #: bot.py:380 #, python-brace-format msgid "" "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations" msgstr "" "第一位玩家: {name}\n" "可使用 /close 防止玩家加入此場遊戲。\n" "請使用 /enable_translations 開啟多翻譯模式。" #: bot.py:417 msgid "Please select the group you want to play in." msgstr "請選擇你要遊玩的群組。" #: bot.py:440 msgid "Closed the lobby. No more players can join this game." msgstr "已關閉遊戲大廳。其他玩家無法再加入此場遊戲。" #: bot.py:468 msgid "Opened the lobby. New players may /join the game." msgstr "已開啟遊戲大廳。新玩家可以使用 /join 加入此場遊戲。" #: bot.py:495 msgid "Enabled multi-translations. Disable with /disable_translations" msgstr "已啟用多翻譯模式。可使用 /disable_translations 停用。" #: bot.py:523 msgid "" "Disabled multi-translations. Enable them again with /enable_translations" msgstr "已停用多翻譯模式。可使用 /enable_translations 再次啟用。" #: bot.py:546 msgid "You are not playing in a game in this chat." msgstr "您不在此聊天室的遊戲中。" #: bot.py:561 #, python-brace-format msgid "Please wait {time} second" msgid_plural "Please wait {time} seconds" msgstr[0] "請等待 {time} 秒" #: bot.py:637 #, python-brace-format msgid "Current game: {game}" msgstr "目前遊戲: {game}" #: bot.py:672 #, python-brace-format msgid "Gamemode changed to {mode}" msgstr "遊戲模式已變更成 {mode}" #: bot.py:678 #, python-brace-format msgid "Cheat attempt by {name}" msgstr "{name} 嘗試作弊。" #: bot.py:697 #, python-brace-format msgid "Next player: {name}" msgstr "輪到: {name}" #: bot.py:709 #, python-brace-format msgid "Waiting time for {name} has been reset to {time} seconds" msgstr "{name} 的等待時間已重設成 {time} 秒" #: results.py:39 msgid "Choose Color" msgstr "選擇顏色" #: results.py:53 msgid "Card (tap for game state):" msgid_plural "Cards (tap for game state):" msgstr[0] "卡牌 (按一下取得遊戲狀態):" #: results.py:64 #, python-brace-format msgid "{name} ({number} card)" msgid_plural "{name} ({number} cards)" msgstr[0] "{name} (有 {number} 張牌)" #: results.py:76 msgid "You are not playing" msgstr "您不在遊戲中。" #: results.py:78 msgid "" "Not playing right now. Use /new to start a game or /join to join the current " "game in this group" msgstr "" "您現在不在遊戲中。請使用 /new 開始新遊戲,或使用 /join 加入目前此群組的遊戲。" #: results.py:90 msgid "The game wasn't started yet" msgstr "遊戲尚未開始。" #: results.py:92 msgid "Start the game with /start" msgstr "請使用 /start 開始遊戲。" #: results.py:102 msgid "🎻 Classic mode" msgstr "🎻 傳統模式" #: results.py:104 msgid "Classic 🎻" msgstr "傳統 🎻" #: results.py:114 msgid "🚀 Sanic mode" msgstr "🚀 Sanic 模式" #: results.py:116 msgid "Gotta go fast! 🚀" msgstr "得快點! 🚀" #: results.py:126 msgid "🐉 Wild mode" msgstr "🐉 野外 (Wild) 模式" #: results.py:128 msgid "Into the Wild~ 🐉" msgstr "走進野外~ 🐉" #: results.py:141 #, python-brace-format msgid "Drawing {number} card" msgid_plural "Drawing {number} cards" msgstr[0] "抽 {number} 張牌" #: results.py:167 msgid "Pass" msgstr "PASS! 下一位!" #: results.py:180 msgid "I'm calling your bluff!" msgstr "別騙了,虛張聲勢 = =" #: results.py:203 #, python-brace-format msgid "Current player: {name}" msgstr "目前玩家: {name}" #: results.py:206 #, python-brace-format msgid "Last card: {card}" msgstr "上一張牌: {card}" #: results.py:208 #, python-brace-format msgid "Player: {player_list}" msgid_plural "Players: {player_list}" msgstr[0] "玩家: {player_list}" #: settings.py:37 msgid "Please edit your settings in a private chat with the bot." msgstr "請私訊這台機器人來編輯設定。" #: settings.py:47 msgid "Enable statistics" msgstr "啟用統計資料" #: settings.py:49 msgid "Delete all statistics" msgstr "刪除所有統計資料" #: settings.py:51 msgid "Language" msgstr "語言" #: settings.py:52 msgid "Settings" msgstr "設定" #: settings.py:66 msgid "Enabled statistics!" msgstr "已啟用統計資料!" #: settings.py:72 msgid "Select locale" msgstr "選擇語言" #: settings.py:82 msgid "Deleted and disabled statistics!" msgstr "已停用並刪除統計資料!" #: settings.py:95 msgid "Set locale!" msgstr "已設定語言!" #: simple_commands.py:31 msgid "" "Follow these steps:\n" "\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already running game " "with /join\n" "3. After at least two players have joined, start the game with /start\n" "4. Type @unobot into your chat box and hit space, or " "click the via @unobot text next to messages. You will see your " "cards (some greyed out), any extra options like drawing, and a ? to " "see the current game state. The greyed out cards are those you can " "not play at the moment. Tap an option to execute the selected action.\n" "Players can join the game at any time. To leave a game, use /leave. If a " "player takes more than 90 seconds to play, you can use /skip to skip that " "player. Use /notify_me to receive a private message when a new game is " "started.\n" "\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick by replying to him or her\n" "/enable_translations - Translate relevant texts into all languages spoken in " "a game\n" "/disable_translations - Use English for those texts\n" "\n" "Experimental: Play in multiple groups at the same time. Press the " "Current game: ... button and select the group you want to play " "a card in.\n" "If you enjoy this bot, rate me, join the update channel and buy an UNO card game." msgstr "" "請遵循以下步驟:\n" "\n" "1. 將機器人加入群組。\n" "2. 在群組中,請使用 /new 開始一場新遊戲,或是使用 /join 加入已經開始的遊" "戲。\n" "3. 在至少兩個玩家加入之後使用 /start 開始遊戲\n" "4. 將 @unobot 輸入到聊天列中,並按下 空白 鍵,或者是按下" "訊息旁的 [via @unobot] 文字。您將會看見您的卡牌 (部分是灰的)、延" "伸功能 (例如抽牌),以及可用來檢視目前遊戲狀態的 ?灰色卡牌為您" "現在不能使用的卡牌。按一下選項以執行選取的動作\n" "玩家可隨時加入遊戲。若要離開遊戲,請使用 /leave。如果一名玩家停滯了超過 90 " "秒,您可使用 /skip 跳過該名玩家。請使用 /notify_me 以在新一局遊戲開始時收到私" "訊。\n" "\n" "語言及其他設定: /settings\n" "其他指令 (僅遊戲建立者可使用):\n" "/close - 關閉遊戲大廳\n" "/open - 開啟遊戲大廳\n" "/kill - 終止遊戲\n" "/kick - 透過回覆以踢出玩家\n" "/enable_translations - 將對應文字翻譯成遊戲中所有使用的語言。\n" "/disable_translations - 僅顯示對應文字的英文版本。\n" "\n" "實驗性功能: 同時在多個群組遊玩。請按下 [目前遊戲: ...] 按" "鈕,並選取你想玩的群組。\n" "\n" "如果你享受這台機器人,請評價這台機器人、加入更新頻道並買一款 UNO 卡牌遊戲。" #: simple_commands.py:73 msgid "" "This UNO bot has three game modes: Classic, Sanic and Wild.\n" "\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto " "skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically " "skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety " "and no auto skip.\n" "\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a " "space, just like when playing a card, and all gamemode options should appear." msgstr "" "這台 UNO 機器人有三種遊戲模式: 傳統、Sanic 及野外 (Wild) 模式。\n" "\n" " 🎻 傳統模式使用常見的 UNO 卡牌組合,且不會自動跳過。\n" " 🚀 Sanic 模式使用常見的 UNO 卡牌組合,且機器人會自動跳過閒置過久的玩家。\n" " 🐉 野外 (Wild) 模式使用較多功能牌且較少數字牌的卡片組合且不會自動跳過。\n" "\n" "若要變更遊戲模式,遊戲建立者必須輸入機器人的使用者名稱 + 空白,就像玩遊戲那" "樣,之後應該就會顯示出所有遊戲模式選項。" #: simple_commands.py:85 msgid "" "This bot is Free Software and licensed under the AGPL. The code is available " "here: \n" "https://github.com/jh0ker/mau_mau_bot" msgstr "" "這台機器人是自由軟體,使用 AGPL 授權。程式碼可在此處取得:\n" "https://github.com/jh0ker/mau_mau_bot" #: simple_commands.py:88 msgid "" "Attributions:\n" "Draw icon by Faithtoken\n" "Pass icon by Delapouite\n" "Originals available on http://game-icons.net\n" "Icons edited by ɳick" msgstr "" "來源:\n" "抽牌 (Draw) 圖示來自 Faithtoken。\n" "跳過 (Pass) 圖示來自 Delapouite。\n" "原始圖示可在 http://game-icons.net 取得。\n" "圖示由 ɳick 編輯。" #: simple_commands.py:105 msgid "All news here: https://telegram.me/unobotnews" msgstr "新聞頻道: https://telegram.me/unobotnews" #: simple_commands.py:115 msgid "" "You did not enable statistics. Use /settings in a private chat with the bot " "to enable them." msgstr "" "您尚未啟用統計資料。請在這台機器人的私人對話中傳送 /settings 以" "啟用。" #: simple_commands.py:122 #, python-brace-format msgid "{number} game played" msgid_plural "{number} games played" msgstr[0] "已遊玩 {number} 場遊戲" #: simple_commands.py:129 #, python-brace-format msgid "{number} first place ({percent}%)" msgid_plural "{number} first places ({percent}%)" msgstr[0] "拿了 {number} 次第一名 ({percent}%)" #: simple_commands.py:136 #, python-brace-format msgid "{number} card played" msgid_plural "{number} cards played" msgstr[0] "已遊玩 {number} 張牌" #: utils.py:55 utils.py:67 #, python-brace-format msgid "{emoji} Red" msgstr "{emoji} 紅色" #: utils.py:57 utils.py:70 #, python-brace-format msgid "{emoji} Blue" msgstr "{emoji} 藍色" #: utils.py:59 utils.py:73 #, python-brace-format msgid "{emoji} Green" msgstr "{emoji} 綠色" #: utils.py:61 utils.py:76 #, python-brace-format msgid "{emoji} Yellow" msgstr "{emoji} 黃色" #~ msgid "{player} was skipped!. " #~ msgstr "{player} 已被跳過!" ================================================ FILE: mwt.py ================================================ #!/usr/bin/env python # Source: http://code.activestate.com/recipes/325905-memoize-decorator-with-timeout/#c1 import time class MWT(object): """Memoize With Timeout""" _caches = {} _timeouts = {} def __init__(self,timeout=2): self.timeout = timeout def collect(self): """Clear cache of results which have timed out""" for func in self._caches: cache = {} for key in self._caches[func]: if (time.time() - self._caches[func][key][1]) < self._timeouts[func]: cache[key] = self._caches[func][key] self._caches[func] = cache def __call__(self, f): self.cache = self._caches[f] = {} self._timeouts[f] = self.timeout def func(*args, **kwargs): kw = sorted(kwargs.items()) key = (args, tuple(kw)) try: v = self.cache[key] print("cache") if (time.time() - v[1]) > self.timeout: raise KeyError except KeyError: print("new") v = self.cache[key] = f(*args,**kwargs),time.time() return v[0] func.func_name = f.__name__ return func ================================================ FILE: player.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging from datetime import datetime import card as c from errors import DeckEmptyError from config import WAITING_TIME class Player(object): """ This class represents a player. It is basically a doubly-linked ring list with the option to reverse the direction. On initialization, it will connect itself to a game and its other players by placing itself behind the current player. """ def __init__(self, game, user): self.cards = list() self.game = game self.user = user self.logger = logging.getLogger(__name__) # Check if this player is the first player in this game. if game.current_player: self.next = game.current_player self.prev = game.current_player.prev game.current_player.prev.next = self game.current_player.prev = self else: self._next = self self._prev = self game.current_player = self self.bluffing = False self.drew = False self.anti_cheat = 0 self.turn_started = datetime.now() self.waiting_time = WAITING_TIME def draw_first_hand(self): try: for _ in range(7): self.cards.append(self.game.deck.draw()) except DeckEmptyError: for card in self.cards: self.game.deck.dismiss(card) raise def leave(self): """Removes player from the game and closes the gap in the list""" if self.next == self: return self.next.prev = self.prev self.prev.next = self.next self.next = None self.prev = None for card in self.cards: self.game.deck.dismiss(card) self.cards = list() def __repr__(self): return repr(self.user) def __str__(self): return str(self.user) @property def next(self): return self._next if not self.game.reversed else self._prev @next.setter def next(self, player): if not self.game.reversed: self._next = player else: self._prev = player @property def prev(self): return self._prev if not self.game.reversed else self._next @prev.setter def prev(self, player): if not self.game.reversed: self._prev = player else: self._next = player def draw(self): """Draws 1+ cards from the deck, depending on the draw counter""" _amount = self.game.draw_counter or 1 try: for _ in range(_amount): self.cards.append(self.game.deck.draw()) except DeckEmptyError: raise finally: self.game.draw_counter = 0 self.drew = True def play(self, card): """Plays a card and removes it from hand""" self.cards.remove(card) self.game.play_card(card) def playable_cards(self): """Returns a list of the cards this player can play right now""" playable = list() last = self.game.last_card self.logger.debug("Last card was " + str(last)) cards = self.cards if self.drew: cards = self.cards[-1:] # You may only play a +4 if you have no cards of the correct color self.bluffing = False for card in cards: if self._card_playable(card): self.logger.debug("Matching!") playable.append(card) self.bluffing = (self.bluffing or card.color == last.color) # You may not play a chooser or +4 as your last card if len(self.cards) == 1 and self.cards[0].special: return list() return playable def _card_playable(self, card): """Check a single card if it can be played""" is_playable = True last = self.game.last_card self.logger.debug("Checking card " + str(card)) if (card.color != last.color and card.value != last.value and not card.special): self.logger.debug("Card's color or value doesn't match") is_playable = False elif last.value == c.DRAW_TWO and not \ card.value == c.DRAW_TWO and self.game.draw_counter: self.logger.debug("Player has to draw and can't counter") is_playable = False elif last.special == c.DRAW_FOUR and self.game.draw_counter: self.logger.debug("Player has to draw and can't counter") is_playable = False elif (last.special == c.CHOOSE or last.special == c.DRAW_FOUR) and \ (card.special == c.CHOOSE or card.special == c.DRAW_FOUR): self.logger.debug("Can't play colorchooser on another one") is_playable = False elif not last.color: self.logger.debug("Last card has no color") is_playable = False return is_playable ================================================ FILE: promotions.py ================================================ """ Promote other UNO bots """ import random # Promotion messages and their weights PROMOTIONS = { """ For a more modern UNO experience, try out the new @uno9bot. """: 2.0, """ Also check out @UnoDemoBot, a newer version of this bot with exclusive modes and features! """: 1.0, } def get_promotion(): """ Get a random promotion message """ return random.choices(list(PROMOTIONS.keys()), weights=list(PROMOTIONS.values()))[0] def send_promotion(chat, chance=1.0): """ (Maybe) send a promotion message """ if random.random() <= chance: chat.send_message(get_promotion(), parse_mode='HTML') def send_promotion_async(chat, chance=1.0): """ Send a promotion message asynchronously """ from utils import dispatcher, error try: dispatcher.run_async(send_promotion, chat, chance=chance) except Exception as e: error(None, None, e) ================================================ FILE: renovate.json ================================================ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:best-practices", ":semanticCommits", ":semanticCommitScopeDisabled", "docker:enableMajor", "customManagers:dockerfileVersions", ":disableRateLimiting", ":ignoreUnstable", ":separateMultipleMajorReleases", ":updateNotScheduled" ], "packageRules": [ { "description": "Group OS packages to avoid build errors if more than one package is updated and previous version is not present in repo already", "matchDatasources": [ "repology" ], "groupName": "OS Packages" }, { "description": "Separate python minor releases", "matchDatasources": [ "docker" ], "matchPackageNames": [ "python" ], "separateMultipleMinor": true, "separateMinorPatch": true } ], "ignoreDeps": [ "ghcr.io/jh0ker/mau_mau_bot", "ghcr.io/juniorjpdj/mau_mau_bot" ], "baseBranches": [ "master" ], "forkProcessing": "enabled" } ================================================ FILE: requirements.txt ================================================ python-telegram-bot==13.15 pony==0.7.19 ================================================ FILE: results.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """Defines helper functions to build the inline result list""" from uuid import uuid4 from telegram import InlineQueryResultArticle, InputTextMessageContent, \ InlineQueryResultCachedSticker as Sticker import card as c from utils import display_color, display_color_group, display_name from internationalization import _, __ def add_choose_color(results, game): """Add choose color options""" for color in c.COLORS: results.append( InlineQueryResultArticle( id=color, title=_("Choose Color"), description=display_color(color), input_message_content= InputTextMessageContent(display_color_group(color, game)) ) ) def add_other_cards(player, results, game): """Add hand cards when choosing colors""" results.append( InlineQueryResultArticle( "hand", title=_("Card (tap for game state):", "Cards (tap for game state):", len(player.cards)), description=', '.join([repr(card) for card in player.cards]), input_message_content=game_info(game) ) ) def player_list(game): """Generate list of player strings""" return [_("{name} ({number} card)", "{name} ({number} cards)", len(player.cards)) .format(name=player.user.first_name, number=len(player.cards)) for player in game.players] def add_no_game(results): """Add text result if user is not playing""" results.append( InlineQueryResultArticle( "nogame", title=_("You are not playing"), input_message_content= InputTextMessageContent(_('Not playing right now. Use /new to ' 'start a game or /join to join the ' 'current game in this group')) ) ) def add_not_started(results): """Add text result if the game has not yet started""" results.append( InlineQueryResultArticle( "nogame", title=_("The game wasn't started yet"), input_message_content= InputTextMessageContent(_('Start the game with /start')) ) ) def add_mode_classic(results): """Change mode to classic""" results.append( InlineQueryResultArticle( "mode_classic", title=_("🎻 Classic mode"), input_message_content= InputTextMessageContent(_('Classic 🎻')) ) ) def add_mode_fast(results): """Change mode to classic""" results.append( InlineQueryResultArticle( "mode_fast", title=_("🚀 Sanic mode"), input_message_content= InputTextMessageContent(_('Gotta go fast! 🚀')) ) ) def add_mode_wild(results): """Change mode to classic""" results.append( InlineQueryResultArticle( "mode_wild", title=_("🐉 Wild mode"), input_message_content= InputTextMessageContent(_('Into the Wild~ 🐉')) ) ) def add_mode_text(results): """Change mode to text""" results.append( InlineQueryResultArticle( "mode_text", title=_("✍️ Text mode"), input_message_content= InputTextMessageContent(_('Text ✍️')) ) ) def add_draw(player, results): """Add option to draw""" n = player.game.draw_counter or 1 results.append( Sticker( "draw", sticker_file_id=c.STICKERS['option_draw'], input_message_content= InputTextMessageContent(__('Drawing {number} card', 'Drawing {number} cards', n, multi=player.game.translate) .format(number=n)) ) ) def add_gameinfo(game, results): """Add option to show game info""" results.append( Sticker( "gameinfo", sticker_file_id=c.STICKERS['option_info'], input_message_content=game_info(game) ) ) def add_pass(results, game): """Add option to pass""" results.append( Sticker( "pass", sticker_file_id=c.STICKERS['option_pass'], input_message_content=InputTextMessageContent( __('Pass', multi=game.translate) ) ) ) def add_call_bluff(results, game): """Add option to call a bluff""" results.append( Sticker( "call_bluff", sticker_file_id=c.STICKERS['option_bluff'], input_message_content= InputTextMessageContent(__("I'm calling your bluff!", multi=game.translate)) ) ) def add_card(game, card, results, can_play): """Add an option that represents a card""" if can_play: if game.mode != "text": results.append( Sticker(str(card), sticker_file_id=c.STICKERS[str(card)]) ) if game.mode == "text": results.append( Sticker(str(card), sticker_file_id=c.STICKERS[str(card)], input_message_content=InputTextMessageContent("Card Played: {card}".format(card=repr(card).replace('Draw Four', '+4').replace('Draw', '+2').replace('Colorchooser', 'Color Chooser'))) )) else: results.append( Sticker(str(uuid4()), sticker_file_id=c.STICKERS_GREY[str(card)], input_message_content=game_info(game)) ) def game_info(game): players = player_list(game) return InputTextMessageContent( _("Current player: {name}") .format(name=display_name(game.current_player.user)) + "\n" + _("Last card: {card}").format(card=repr(game.last_card)) + "\n" + _("Player: {player_list}", "Players: {player_list}", len(players)) .format(player_list=" -> ".join(players)) ) ================================================ FILE: settings.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from telegram import ReplyKeyboardMarkup, Update from telegram.ext import CommandHandler, Filters, MessageHandler, CallbackContext from utils import send_async from user_setting import UserSetting from shared_vars import dispatcher from locales import available_locales from internationalization import _, user_locale @user_locale def show_settings(update: Update, context: CallbackContext): chat = update.message.chat if update.message.chat.type != 'private': send_async(context.bot, chat.id, text=_("Please edit your settings in a private chat with " "the bot.")) return us = UserSetting.get(id=update.message.from_user.id) if not us: us = UserSetting(id=update.message.from_user.id) if not us.stats: stats = '📊' + ' ' + _("Enable statistics") else: stats = '❌' + ' ' + _("Delete all statistics") kb = [[stats], ['🌍' + ' ' + _("Language")]] send_async(context.bot, chat.id, text='🔧' + ' ' + _("Settings"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True)) @user_locale def kb_select(update: Update, context: CallbackContext): chat = update.message.chat user = update.message.from_user option = context.match[1] if option == '📊': us = UserSetting.get(id=user.id) us.stats = True send_async(context.bot, chat.id, text=_("Enabled statistics!")) elif option == '🌍': kb = [[locale + ' - ' + descr] for locale, descr in sorted(available_locales.items())] send_async(context.bot, chat.id, text=_("Select locale"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True)) elif option == '❌': us = UserSetting.get(id=user.id) us.stats = False us.first_places = 0 us.games_played = 0 us.cards_played = 0 send_async(context.bot, chat.id, text=_("Deleted and disabled statistics!")) @user_locale def locale_select(update: Update, context: CallbackContext): chat = update.message.chat user = update.message.from_user option = context.match[1] if option in available_locales: us = UserSetting.get(id=user.id) us.lang = option _.push(option) send_async(context.bot, chat.id, text=_("Set locale!")) _.pop() def register(): dispatcher.add_handler(CommandHandler('settings', show_settings)) dispatcher.add_handler(MessageHandler(Filters.regex('^([' + '📊' + '🌍' + '❌' + ']) .+$'), kb_select)) dispatcher.add_handler(MessageHandler(Filters.regex(r'^(\w\w_\w\w) - .*'), locale_select)) ================================================ FILE: shared_vars.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from config import TOKEN, WORKERS import logging import os from telegram.ext import Updater from game_manager import GameManager from database import db db.bind('sqlite', os.getenv('UNO_DB', 'uno.sqlite3'), create_db=True) db.generate_mapping(create_tables=True) gm = GameManager() updater = Updater(token=TOKEN, workers=WORKERS, use_context=True) dispatcher = updater.dispatcher ================================================ FILE: simple_commands.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from telegram import ParseMode, Update from telegram.ext import CommandHandler, CallbackContext from user_setting import UserSetting from utils import send_async from shared_vars import dispatcher from internationalization import _, user_locale from promotions import send_promotion @user_locale def help_handler(update: Update, context: CallbackContext): """Handler for the /help command""" help_text = _("Follow these steps:\n\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already" " running game with /join\n" "3. After at least two players have joined, start the game with" " /start\n" "4. Type @unobot into your chat box and hit " "space, or click the via @unobot text " "next to messages. You will see your cards (some greyed out), " "any extra options like drawing, and a ? to see the " "current game state. The greyed out cards are those you " "can not play at the moment. Tap an option to execute " "the selected action.\n" "Players can join the game at any time. To leave a game, " "use /leave. If a player takes more than 90 seconds to play, " "you can use /skip to skip that player. Use /notify_me to " "receive a private message when a new game is started.\n\n" "Language and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick " "by replying to him or her\n" "/enable_translations - Translate relevant texts into all " "languages spoken in a game\n" "/disable_translations - Use English for those texts\n\n" "Experimental: Play in multiple groups at the same time. " "Press the Current game: ... button and select the " "group you want to play a card in.\n" "If you enjoy this bot, " "" "rate me, join the " "update channel" " and buy an UNO card game.") def _send(): update.message.chat.send_message( help_text, parse_mode=ParseMode.HTML, disable_web_page_preview=True, ) send_promotion(update.effective_chat) context.dispatcher.run_async(_send) @user_locale def modes(update: Update, context: CallbackContext): """Handler for the /help command""" modes_explanation = _("This UNO bot has four game modes: Classic, Sanic, Wild and Text.\n\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety and no auto skip.\n" " ✍️ The Text mode uses the conventional UNO deck but instead of stickers it uses the text.\n\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a space, " "just like when playing a card, and all gamemode options should appear.") send_async(context.bot, update.message.chat_id, text=modes_explanation, parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale def source(update: Update, context: CallbackContext): """Handler for the /help command""" source_text = _("This bot is Free Software and licensed under the AGPL. " "The code is available here: \n" "https://github.com/jh0ker/mau_mau_bot") attributions = _("Attributions:\n" 'Draw icon by ' 'Faithtoken\n' 'Pass icon by ' 'Delapouite\n' "Originals available on http://game-icons.net\n" "Icons edited by ɳick") send_async(context.bot, update.message.chat_id, text=source_text + '\n' + attributions, parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale def news(update: Update, context: CallbackContext): """Handler for the /news command""" send_async(context.bot, update.message.chat_id, text=_("All news here: https://telegram.me/unobotnews"), disable_web_page_preview=True) @user_locale def stats(update: Update, context: CallbackContext): user = update.message.from_user us = UserSetting.get(id=user.id) if not us or not us.stats: send_async(context.bot, update.message.chat_id, text=_("You did not enable statistics. Use /settings in " "a private chat with the bot to enable them.")) else: stats_text = list() n = us.games_played stats_text.append( _("{number} game played", "{number} games played", n).format(number=n) ) n = us.first_places m = round((us.first_places / us.games_played) * 100) if us.games_played else 0 stats_text.append( _("{number} first place ({percent}%)", "{number} first places ({percent}%)", n).format(number=n, percent=m) ) n = us.cards_played stats_text.append( _("{number} card played", "{number} cards played", n).format(number=n) ) send_async(context.bot, update.message.chat_id, text='\n'.join(stats_text)) def register(): dispatcher.add_handler(CommandHandler('help', help_handler)) dispatcher.add_handler(CommandHandler('source', source)) dispatcher.add_handler(CommandHandler('news', news)) dispatcher.add_handler(CommandHandler('stats', stats)) dispatcher.add_handler(CommandHandler('modes', modes)) ================================================ FILE: start_bot.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # Modify this file if you want a different startup sequence, for example using # a Webhook def start_bot(updater): updater.start_polling() ================================================ FILE: test/__init__.py ================================================ ================================================ FILE: test/test_game_manager.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import unittest from telegram import User, Chat from game_manager import GameManager from errors import AlreadyJoinedError, LobbyClosedError, NoGameInChatError, \ NotEnoughPlayersError class Test(unittest.TestCase): game = None def setUp(self): self.gm = GameManager() self.chat0 = Chat(0, 'group') self.chat1 = Chat(1, 'group') self.chat2 = Chat(2, 'group') self.user0 = User(0, 'user0') self.user1 = User(1, 'user1') self.user2 = User(2, 'user2') def test_new_game(self): g0 = self.gm.new_game(self.chat0) g1 = self.gm.new_game(self.chat1) self.assertListEqual(self.gm.chatid_games[0], [g0]) self.assertListEqual(self.gm.chatid_games[1], [g1]) def test_join_game(self): self.assertRaises(NoGameInChatError, self.gm.join_game, *(self.user0, self.chat0)) g0 = self.gm.new_game(self.chat0) self.gm.join_game(self.user0, self.chat0) self.assertEqual(len(g0.players), 1) self.gm.join_game(self.user1, self.chat0) self.assertEqual(len(g0.players), 2) g0.open = False self.assertRaises(LobbyClosedError, self.gm.join_game, *(self.user2, self.chat0)) g0.open = True self.assertRaises(AlreadyJoinedError, self.gm.join_game, *(self.user1, self.chat0)) def test_leave_game(self): self.gm.new_game(self.chat0) self.gm.join_game(self.user0, self.chat0) self.gm.join_game(self.user1, self.chat0) self.assertRaises(NotEnoughPlayersError, self.gm.leave_game, *(self.user1, self.chat0)) self.gm.join_game(self.user2, self.chat0) self.gm.leave_game(self.user0, self.chat0) self.assertRaises(NoGameInChatError, self.gm.leave_game, *(self.user0, self.chat0)) def test_end_game(self): self.gm.new_game(self.chat0) self.gm.join_game(self.user0, self.chat0) self.gm.join_game(self.user1, self.chat0) self.assertEqual(len(self.gm.userid_players[0]), 1) self.gm.new_game(self.chat0) self.gm.join_game(self.user2, self.chat0) self.gm.end_game(self.chat0, self.user0) self.assertEqual(len(self.gm.chatid_games[0]), 1) self.gm.end_game(self.chat0, self.user2) self.assertFalse(0 in self.gm.chatid_games) self.assertFalse(0 in self.gm.userid_players) self.assertFalse(1 in self.gm.userid_players) self.assertFalse(2 in self.gm.userid_players) ================================================ FILE: test/test_player.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import unittest from game import Game from player import Player import card as c class Test(unittest.TestCase): game = None def setUp(self): self.game = Game(None) def test_insert(self): p0 = Player(self.game, "Player 0") p1 = Player(self.game, "Player 1") p2 = Player(self.game, "Player 2") self.assertEqual(p0, p2.next) self.assertEqual(p1, p0.next) self.assertEqual(p2, p1.next) self.assertEqual(p0.prev, p2) self.assertEqual(p1.prev, p0) self.assertEqual(p2.prev, p1) def test_reverse(self): p0 = Player(self.game, "Player 0") p1 = Player(self.game, "Player 1") p2 = Player(self.game, "Player 2") self.game.reverse() p3 = Player(self.game, "Player 3") self.assertEqual(p0, p3.next) self.assertEqual(p1, p2.next) self.assertEqual(p2, p0.next) self.assertEqual(p3, p1.next) self.assertEqual(p0, p2.prev) self.assertEqual(p1, p3.prev) self.assertEqual(p2, p1.prev) self.assertEqual(p3, p0.prev) def test_leave(self): p0 = Player(self.game, "Player 0") p1 = Player(self.game, "Player 1") p2 = Player(self.game, "Player 2") p1.leave() self.assertEqual(p0, p2.next) self.assertEqual(p2, p0.next) def test_draw(self): p = Player(self.game, "Player 0") self.game.start() deck_before = len(self.game.deck.cards) top_card = self.game.deck.cards[-1] p.draw() self.assertEqual(top_card, p.cards[-1]) self.assertEqual(deck_before, len(self.game.deck.cards) + 1) def test_draw_two(self): p = Player(self.game, "Player 0") self.game.start() deck_before = len(self.game.deck.cards) self.game.draw_counter = 2 p.draw() self.assertEqual(deck_before, len(self.game.deck.cards) + 2) def test_playable_cards_simple(self): p = Player(self.game, "Player 0") self.game.last_card = c.Card(c.RED, '5') p.cards = [c.Card(c.RED, '0'), c.Card(c.RED, '5'), c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'), c.Card(c.GREEN, '8')] expected = [c.Card(c.RED, '0'), c.Card(c.RED, '5'), c.Card(c.GREEN, '5')] self.assertListEqual(p.playable_cards(), expected) def test_playable_cards_on_draw_two(self): p = Player(self.game, "Player 0") self.game.last_card = c.Card(c.RED, c.DRAW_TWO) self.game.draw_counter = 2 p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'), c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'), c.Card(c.GREEN, c.DRAW_TWO)] expected = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.GREEN, c.DRAW_TWO)] self.assertListEqual(p.playable_cards(), expected) def test_playable_cards_on_draw_four(self): p = Player(self.game, "Player 0") self.game.last_card = c.Card(c.RED, None, c.DRAW_FOUR) self.game.draw_counter = 4 p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'), c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'), c.Card(c.GREEN, c.DRAW_TWO), c.Card(None, None, c.DRAW_FOUR), c.Card(None, None, c.CHOOSE)] expected = list() self.assertListEqual(p.playable_cards(), expected) def test_bluffing(self): p = Player(self.game, "Player 0") Player(self.game, "Player 01") self.game.last_card = c.Card(c.RED, '1') p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'), c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'), c.Card(c.RED, '5'), c.Card(c.GREEN, c.DRAW_TWO), c.Card(None, None, c.DRAW_FOUR), c.Card(None, None, c.CHOOSE)] p.playable_cards() self.assertTrue(p.bluffing) p.cards = [c.Card(c.BLUE, '1'), c.Card(c.GREEN, '1'), c.Card(c.GREEN, c.DRAW_TWO), c.Card(None, None, c.DRAW_FOUR), c.Card(None, None, c.CHOOSE)] p.playable_cards() p.play(c.Card(None, None, c.DRAW_FOUR)) self.game.choose_color(c.GREEN) self.assertFalse(self.game.current_player.prev.bluffing) ================================================ FILE: user_setting.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from pony.orm import Optional, PrimaryKey from database import db class UserSetting(db.Entity): id = PrimaryKey(int, auto=False, size=64) # Telegram User ID lang = Optional(str, default='') # The language setting for this user stats = Optional(bool, default=False) # Opt-in to keep game statistics first_places = Optional(int, default=0) # Nr. of games won in first place games_played = Optional(int, default=0) # Nr. of games completed cards_played = Optional(int, default=0) # Nr. of cards played total use_keyboards = Optional(bool, default=False) # Use keyboards (unused) ================================================ FILE: utils.py ================================================ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Telegram bot to play UNO in group chats # Copyright (c) 2016 Jannes Höke # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging from telegram import Update from telegram.ext import CallbackContext from internationalization import _, __ from mwt import MWT from shared_vars import gm, dispatcher logger = logging.getLogger(__name__) TIMEOUT = 2.5 def list_subtract(list1, list2): """ Helper function to subtract two lists and return the sorted result """ list1 = list1.copy() for x in list2: list1.remove(x) return list(sorted(list1)) def display_name(user): """ Get the current players name including their username, if possible """ user_name = user.first_name if user.username: user_name += ' (@' + user.username + ')' return user_name def display_color(color): """ Convert a color code to actual color name """ if color == "r": return _("{emoji} Red").format(emoji='❤️') if color == "b": return _("{emoji} Blue").format(emoji='💙') if color == "g": return _("{emoji} Green").format(emoji='💚') if color == "y": return _("{emoji} Yellow").format(emoji='💛') def display_color_group(color, game): """ Convert a color code to actual color name """ if color == "r": return __("{emoji} Red", game.translate).format( emoji='❤️') if color == "b": return __("{emoji} Blue", game.translate).format( emoji='💙') if color == "g": return __("{emoji} Green", game.translate).format( emoji='💚') if color == "y": return __("{emoji} Yellow", game.translate).format( emoji='💛') def error(update: Update, context: CallbackContext): """Simple error handler""" logger.exception(context.error) def send_async(bot, *args, **kwargs): """Send a message asynchronously""" if 'timeout' not in kwargs: kwargs['timeout'] = TIMEOUT try: dispatcher.run_async(bot.sendMessage, *args, **kwargs) except Exception as e: error(None, None, e) def answer_async(bot, *args, **kwargs): """Answer an inline query asynchronously""" if 'timeout' not in kwargs: kwargs['timeout'] = TIMEOUT try: dispatcher.run_async(bot.answerInlineQuery, *args, **kwargs) except Exception as e: error(None, None, e) def game_is_running(game): return game in gm.chatid_games.get(game.chat.id, list()) def user_is_creator(user, game): return user.id in game.owner def user_is_admin(user, bot, chat): return user.id in get_admin_ids(bot, chat.id) def user_is_creator_or_admin(user, game, bot, chat): return user_is_creator(user, game) or user_is_admin(user, bot, chat) @MWT(timeout=60*60) def get_admin_ids(bot, chat_id): """Returns a list of admin IDs for a given chat. Results are cached for 1 hour.""" return [admin.user.id for admin in bot.get_chat_administrators(chat_id)]